Skip to content

Commit

Permalink
Dataset preview data
Browse files Browse the repository at this point in the history
  • Loading branch information
andresgutgon committed Sep 6, 2024
1 parent ee4887c commit 4cac553
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 10 deletions.
21 changes: 21 additions & 0 deletions apps/web/src/actions/datasets/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use server'

import { DatasetsRepository } from '@latitude-data/core/repositories'
import { previewDataset } from '@latitude-data/core/services/datasets/preview'
import disk from '$/lib/disk'
import { z } from 'zod'

import { authProcedure } from '../procedures'

export const previewDatasetAction = authProcedure
.createServerAction()
.input(
z.object({
id: z.number(),
}),
)
.handler(async ({ ctx, input }) => {
const repo = new DatasetsRepository(ctx.workspace.id)
const dataset = await repo.find(input.id).then((r) => r.unwrap())
return await previewDataset({ dataset, disk }).then((r) => r.unwrap())
})
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import {
TableHeader,
TableRow,
Text,
Tooltip,
} from '@latitude-data/web-ui'
import DeleteDatasetModal from '$/app/(private)/datasets/_components/DeleteDatasetModal'
import PreviewDatasetModal from '$/app/(private)/datasets/_components/PreviewDatasetModal'
import useDatasets from '$/stores/datasets'

export function DatasetsTable({
Expand All @@ -23,12 +25,14 @@ export function DatasetsTable({
datasets: Dataset[]
}) {
const [deletable, setDeletable] = useState<Dataset | null>(null)
const [preview, setPreview] = useState<Dataset | null>(null)
const { data: datasets } = useDatasets(undefined, {
fallbackData: serverDatasets,
})
return (
<>
<DeleteDatasetModal dataset={deletable} setDataset={setDeletable} />
<PreviewDatasetModal dataset={preview} setPreview={setPreview} />
<Table>
<TableHeader>
<TableRow verticalPadding>
Expand All @@ -38,6 +42,7 @@ export function DatasetsTable({
<TableHead>Author</TableHead>
<TableHead>Created at</TableHead>
<TableHead />
<TableHead />
</TableRow>
</TableHeader>
<TableBody>
Expand All @@ -60,6 +65,19 @@ export function DatasetsTable({
{dateFormatter.formatDate(dataset.createdAt)}
</Text.H4>
</TableCell>
<TableCell align='center'>
<Tooltip
trigger={
<Button
onClick={() => setPreview(dataset)}
variant='nope'
iconProps={{ name: 'eye', color: 'foregroundMuted' }}
/>
}
>
<Text.H6B color='white'>Show file preview (first 100 rows)</Text.H6B>
</Tooltip>
</TableCell>
<TableCell align='center'>
<Button
onClick={() => setDeletable(dataset)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Dataset } from '@latitude-data/core/browser'
import { Modal, ReactStateDispatch } from '@latitude-data/web-ui'
import useDatasetPreview from '$/stores/datasetPreviews'

function PreviewModal({
dataset,
setPreview,
}: {
dataset: Dataset
setPreview: ReactStateDispatch<Dataset | null>
}) {
const { data, isLoading } = useDatasetPreview({ dataset })
console.log('Preview', data, isLoading)
return (
<Modal
size='large'
open
title={`${dataset.name} preview`}
description='First 100 rows of the dataset'
onOpenChange={(open: boolean) => !open && setPreview(null)}
>
Hola {isLoading}
</Modal>
)
}

export default function PreviewDatasetModal({
dataset,
setPreview,
}: {
dataset: Dataset | null
setPreview: ReactStateDispatch<Dataset | null>
}) {
if (!dataset) return null

return <PreviewModal dataset={dataset} setPreview={setPreview} />
}
42 changes: 42 additions & 0 deletions apps/web/src/stores/datasetPreviews.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useCallback } from 'react'

import type { Dataset } from '@latitude-data/core/browser'
import { useToast } from '@latitude-data/web-ui'
import { previewDatasetAction } from '$/actions/datasets/preview'
import useCurrentWorkspace from '$/stores/currentWorkspace'
import { SWRConfiguration } from 'swr'
import useSWRImmutable from 'swr/immutable'

export default function useDatasetPreview(
{ dataset }: { dataset: Dataset },
opts?: SWRConfiguration,
) {
const { data: workspace } = useCurrentWorkspace()
const { toast } = useToast()
const fetcher = useCallback(async () => {
const [data, error] = await previewDatasetAction({ id: dataset.id })
console.log('FETCHING')
if (error) {
toast({
title: 'Error',
description: error.message,
variant: 'destructive',
})

return []
}

return data
}, [toast])

const { data = [], ...rest } = useSWRImmutable(
['workspace', workspace.id, 'datasets_preview', dataset?.id],
fetcher,
opts,
)

return {
data,
isLoading: rest.isLoading,
}
}
38 changes: 28 additions & 10 deletions packages/core/src/lib/readCsv.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,43 @@
import { CsvError, parse } from 'csv-parse/sync'
import { CsvError, parse, type Options as CsvOptions } from 'csv-parse/sync'

import { Result } from './Result'

type ParseCsvOptions = { delimiter?: string }
function getData(file: File | string) {
if (typeof file === 'string') {
return file
}
return file.text()
}

type ParseCsvOptions = {
delimiter?: string
// https://csv.js.org/parse/options/to_line/
limit?: number
}
type ParseResult = {
record: Record<string, string>
info: { columns: { name: string }[] }
}
export async function syncReadCsv(
file: File,
{ delimiter = ';' }: ParseCsvOptions = {},
file: File | string,
{ delimiter = ';', limit = -1 }: ParseCsvOptions = {},
) {
try {
const data = await file.text()
const records = parse(data, {
const data = await getData(file)
let opts: CsvOptions = {
delimiter,
relax_column_count: true,
trim: true,
skip_empty_lines: true,
columns: true,
info: true,
}) as {
record: Record<string, string>
info: { columns: { name: string }[] }
}[] // not typed
}

if (limit > 0) {
opts = { ...opts, to_line: limit }
}

const records = parse(data, opts) as ParseResult[]

if (records.length < 1)
return Result.ok({ headers: [], rowCount: 0, data: [] })
Expand Down
21 changes: 21 additions & 0 deletions packages/core/src/services/datasets/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Dataset } from '../../browser'
import { DiskWrapper } from '../../lib/disk'
import { syncReadCsv } from '../../lib/readCsv'

/**
* This service pick the first N rows of a CSV file
*/
export async function previewDataset({
dataset,
disk,
limit = 100,
}: {
dataset: Dataset
disk: DiskWrapper
limit?: number
}) {
const diskFile = disk.file(dataset.fileKey)
const bytes = await diskFile.getBytes()
const file = new TextDecoder().decode(bytes)
return syncReadCsv(file, { limit })
}
2 changes: 2 additions & 0 deletions packages/web-ui/src/ds/atoms/Icons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Copy,
Ellipsis,
EllipsisVertical,
Eye,
File,
FilePlus,
FileUpIcon,
Expand Down Expand Up @@ -56,6 +57,7 @@ const Icons = {
moon: Moon,
trash: Trash,
sun: Sun,
eye: Eye
}

export type IconName = keyof typeof Icons
Expand Down

0 comments on commit 4cac553

Please sign in to comment.