Add chat data export to Export My Data dialog (#9900)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import {View} from 'react-native'
|
|||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||||
import {saveBytesToDisk} from '#/lib/media/manip'
|
import {saveBytesToDisk} from '#/lib/media/manip'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
@@ -23,14 +24,14 @@ export function ExportCarDialog({
|
|||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState<'repo' | 'chat' | false>(false)
|
||||||
|
|
||||||
const download = useCallback(async () => {
|
const download = useCallback(async () => {
|
||||||
if (!agent.session) {
|
if (!agent.session) {
|
||||||
return // shouldnt ever happen
|
return // shouldnt ever happen
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
setLoading(true)
|
setLoading('repo')
|
||||||
const did = agent.session.did
|
const did = agent.session.did
|
||||||
const downloadRes = await agent.com.atproto.sync.getRepo({did})
|
const downloadRes = await agent.com.atproto.sync.getRepo({did})
|
||||||
const saveRes = await saveBytesToDisk(
|
const saveRes = await saveBytesToDisk(
|
||||||
@@ -51,6 +52,40 @@ export function ExportCarDialog({
|
|||||||
}
|
}
|
||||||
}, [_, control, agent])
|
}, [_, control, agent])
|
||||||
|
|
||||||
|
const downloadChatData = useCallback(async () => {
|
||||||
|
if (!agent.session) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
setLoading('chat')
|
||||||
|
// Using raw fetch because the XRPC client incorrectly tries to JSON-parse
|
||||||
|
// application/jsonl responses (substring match on application/json).
|
||||||
|
const res = await agent.sessionManager.fetchHandler(
|
||||||
|
'/xrpc/chat.bsky.actor.exportAccountData',
|
||||||
|
{headers: DM_SERVICE_HEADERS},
|
||||||
|
)
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(`HTTP ${res.status}`)
|
||||||
|
}
|
||||||
|
const data = new Uint8Array(await res.arrayBuffer())
|
||||||
|
const saveRes = await saveBytesToDisk(
|
||||||
|
'chat.jsonl',
|
||||||
|
data,
|
||||||
|
res.headers.get('content-type') || 'application/jsonl',
|
||||||
|
)
|
||||||
|
|
||||||
|
if (saveRes) {
|
||||||
|
Toast.show(_(msg`File saved successfully!`))
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('Error occurred while downloading chat data', {message: e})
|
||||||
|
Toast.show(_(msg`Error occurred while saving file`), {type: 'error'})
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
|
control.close()
|
||||||
|
}
|
||||||
|
}, [_, control, agent])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
|
<Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
|
||||||
<Dialog.Handle />
|
<Dialog.Handle />
|
||||||
@@ -77,13 +112,34 @@ export function ExportCarDialog({
|
|||||||
color="primary"
|
color="primary"
|
||||||
size="large"
|
size="large"
|
||||||
label={_(msg`Download CAR file`)}
|
label={_(msg`Download CAR file`)}
|
||||||
disabled={loading}
|
disabled={!!loading}
|
||||||
onPress={download}>
|
onPress={download}>
|
||||||
<ButtonIcon icon={DownloadIcon} />
|
<ButtonIcon icon={DownloadIcon} />
|
||||||
<ButtonText>
|
<ButtonText>
|
||||||
<Trans>Download CAR file</Trans>
|
<Trans>Download CAR file</Trans>
|
||||||
</ButtonText>
|
</ButtonText>
|
||||||
{loading && <ButtonIcon icon={Loader} />}
|
{loading === 'repo' && <ButtonIcon icon={Loader} />}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Text style={[a.text_sm, a.leading_snug, t.atoms.text_contrast_high]}>
|
||||||
|
<Trans>
|
||||||
|
You can also download your chat data as a "JSONL" file. This file
|
||||||
|
only includes chat messages that you have sent and does not
|
||||||
|
include chat messages that you have received.
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
color="secondary"
|
||||||
|
size="large"
|
||||||
|
label={_(msg`Download chat data`)}
|
||||||
|
disabled={!!loading}
|
||||||
|
onPress={downloadChatData}>
|
||||||
|
<ButtonIcon icon={DownloadIcon} />
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Download chat data</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
{loading === 'chat' && <ButtonIcon icon={Loader} />}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Text
|
<Text
|
||||||
|
|||||||
Reference in New Issue
Block a user