Log state changes

This commit is contained in:
Jackson Harper
2024-11-02 14:48:51 +08:00
parent 11144ffc66
commit 8e8bae9e1a
3 changed files with 88 additions and 2 deletions

View File

@ -175,6 +175,12 @@ export const exportJob = async (jobData: ExportJobData) => {
userId
)
await saveExport(userId, {
id: exportId,
state: TaskState.Running,
totalItems: itemCount,
})
logger.info(`exporting ${itemCount} items...`, {
userId,
})
@ -226,6 +232,11 @@ export const exportJob = async (jobData: ExportJobData) => {
// fetch data from the database
const batchSize = 20
for (cursor = 0; cursor < itemCount; cursor += batchSize) {
logger.info(`export extracting ${cursor} of ${itemCount}`, {
userId,
exportId,
})
const items = await searchLibraryItems(
{
from: cursor,
@ -242,6 +253,10 @@ export const exportJob = async (jobData: ExportJobData) => {
// write data to the csv file
if (size > 0) {
await uploadToBucket(userId, items, cursor, size, archive)
await saveExport(userId, {
id: exportId,
processedItems: cursor,
})
} else {
break
}
@ -264,7 +279,7 @@ export const exportJob = async (jobData: ExportJobData) => {
// generate a temporary signed url for the zip file
const [signedUrl] = await file.getSignedUrl({
action: 'read',
expires: Date.now() + 48 * 60 * 60 * 1000, // 48 hours
expires: Date.now() + 168 * 60 * 60 * 1000, // one week
})
logger.info('signed url for export:', {
@ -275,6 +290,8 @@ export const exportJob = async (jobData: ExportJobData) => {
await saveExport(userId, {
id: exportId,
state: TaskState.Succeeded,
signedUrl,
processedItems: itemCount,
})
const job = await sendExportJobEmail(userId, 'completed', signedUrl)

View File

@ -1,11 +1,38 @@
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { apiFetcher } from './networkHelpers'
import { TaskState } from './mutations/exportToIntegrationMutation'
type Export = {
id: string
state: TaskState
createdAt: string
signedUrl: string
}
type ExportsResponse = {
exports: Export[]
}
export const createExport = async (): Promise<boolean> => {
try {
const response = await apiFetcher(`/api/export/`)
console.log('RESPONSE: ', response)
if ('error' in (response as any)) {
return false
}
return true
} catch (error) {
console.log('error scheduling export. ')
return false
}
}
export function useGetExports() {
return useQuery({
queryKey: ['exports'],
queryFn: async () => {
const response = (await apiFetcher(`/api/export/list`)) as ExportsResponse
return response.exports
},
})
}

View File

@ -2,6 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'
import { Button } from '../../components/elements/Button'
import {
Box,
HStack,
SpanBox,
VStack,
} from '../../components/elements/LayoutPrimitives'
@ -27,7 +28,13 @@ import { useGetViewerQuery } from '../../lib/networking/queries/useGetViewerQuer
import { useValidateUsernameQuery } from '../../lib/networking/queries/useValidateUsernameQuery'
import { applyStoredTheme } from '../../lib/themeUpdater'
import { showErrorToast, showSuccessToast } from '../../lib/toastHelpers'
import { createExport } from '../../lib/networking/useCreateExport'
import {
createExport,
useGetExports,
} from '../../lib/networking/useCreateExport'
import { TaskState } from '../../lib/networking/mutations/exportToIntegrationMutation'
import { timeAgo } from '../../lib/textFormatting'
import { Download, DownloadSimple } from '@phosphor-icons/react'
const ACCOUNT_LIMIT = 50_000
@ -475,6 +482,8 @@ export default function Account(): JSX.Element {
}
const ExportSection = (): JSX.Element => {
const { data: recentExports } = useGetExports()
console.log('recentExports: ', recentExports)
const doExport = useCallback(async () => {
const result = await createExport()
if (result) {
@ -502,6 +511,12 @@ const ExportSection = (): JSX.Element => {
you should receive an email with a link to your data within an hour. The
download link will be available for 24 hours.
</StyledText>
<StyledText style="footnote" css={{ mt: '10px', mb: '20px' }}>
If you do not receive your completed export within 24hrs please contact{' '}
<a href="mailto:feedback@omnivore.app">
Contact&nbsp;us via&nbsp;email
</a>
</StyledText>
<Button
style="ctaDarkYellow"
onClick={(event) => {
@ -512,6 +527,33 @@ const ExportSection = (): JSX.Element => {
>
Export Data
</Button>
{recentExports && (
<VStack css={{ width: '100% ', mt: '20px' }}>
<StyledLabel>Recent exports</StyledLabel>
{recentExports.map((item) => {
return (
<HStack
key={item.id}
css={{ width: '100% ' }}
distribution="start"
>
<SpanBox css={{ width: '180px' }} title={item.createdAt}>
{timeAgo(item.createdAt)}
</SpanBox>
<SpanBox>{item.state}</SpanBox>
{item.signedUrl && (
<SpanBox css={{ marginLeft: 'auto' }}>
<a href={item.signedUrl} target="_blank" rel="noreferrer">
Download
</a>
</SpanBox>
)}
</HStack>
)
})}
</VStack>
)}
</VStack>
)
}