Skip to content

Commit fbccc8b

Browse files
authored
Update dataset column name and role and display row columns in different (#1038)
color based on their role. Also show label badge on dataset grid column
1 parent ac89c1c commit fbccc8b

File tree

8 files changed

+244
-320
lines changed

8 files changed

+244
-320
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use server'
2+
3+
import { updateDatasetColumn } from '@latitude-data/core/services/datasetsV2/updateColumn'
4+
import { z } from 'zod'
5+
6+
import { authProcedure } from '../procedures'
7+
import {
8+
DATASET_COLUMN_ROLES,
9+
DatasetColumnRole,
10+
} from '@latitude-data/core/browser'
11+
import { DatasetsV2Repository } from '@latitude-data/core/repositories'
12+
13+
const datasetColumnRoleSchema = z.enum(
14+
Object.values(DATASET_COLUMN_ROLES) as [
15+
DatasetColumnRole,
16+
...DatasetColumnRole[],
17+
],
18+
)
19+
export const updateDatasetColumnAction = authProcedure
20+
.createServerAction()
21+
.input(
22+
z.object({
23+
datasetId: z.string(),
24+
identifier: z.string(),
25+
name: z.string().min(1, { message: 'Name is required' }),
26+
role: datasetColumnRoleSchema,
27+
}),
28+
)
29+
.handler(async ({ input, ctx }) => {
30+
const repo = new DatasetsV2Repository(ctx.workspace.id)
31+
const dataset = await repo.find(input.datasetId).then((r) => r.unwrap())
32+
return updateDatasetColumn({
33+
dataset,
34+
data: {
35+
identifier: input.identifier,
36+
name: input.name,
37+
role: input.role,
38+
},
39+
}).then((r) => r.unwrap())
40+
})
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { useFormAction } from '$/hooks/useFormAction'
2+
import useDatasets from '$/stores/datasetsV2'
3+
import { DATASET_COLUMN_ROLES, DatasetV2 } from '@latitude-data/core/browser'
4+
import {
5+
Button,
6+
FormWrapper,
7+
Input,
8+
Modal,
9+
Select,
10+
SelectOption,
11+
} from '@latitude-data/web-ui'
12+
import { useMemo } from 'react'
13+
14+
export function UpdateColumnModal({
15+
dataset,
16+
columnKey,
17+
onClose,
18+
}: {
19+
dataset: DatasetV2
20+
columnKey: string
21+
onClose: () => void
22+
}) {
23+
const column = dataset.columns.find((col) => col.identifier === columnKey)
24+
const { updateColumn, isUpdatingColumn } = useDatasets()
25+
const options = useMemo<SelectOption<string>[]>(
26+
() =>
27+
Object.keys(DATASET_COLUMN_ROLES).map((key) => ({
28+
label: key,
29+
value: key,
30+
})),
31+
[],
32+
)
33+
const { action: updateColumnAction } = useFormAction(updateColumn, {
34+
onSuccess: () => {
35+
onClose()
36+
},
37+
})
38+
39+
if (!column) return null
40+
41+
return (
42+
<Modal
43+
dismissible
44+
open
45+
onOpenChange={onClose}
46+
title='Edit Column'
47+
description={`Edit column ${column.name} in this dataset`}
48+
footer={
49+
<>
50+
<Button variant='outline' fancy onClick={onClose}>
51+
Cancel
52+
</Button>
53+
<Button
54+
form='edit-column'
55+
type='submit'
56+
fancy
57+
disabled={isUpdatingColumn}
58+
>
59+
{isUpdatingColumn ? 'Updating...' : 'Update'}
60+
</Button>
61+
</>
62+
}
63+
>
64+
<form id='edit-column' action={updateColumnAction}>
65+
<FormWrapper>
66+
<input type='hidden' name='datasetId' value={dataset.id} />
67+
<input type='hidden' name='identifier' value={column.identifier} />
68+
<Input required label='Name' name='name' defaultValue={column.name} />
69+
<Select<string>
70+
options={options}
71+
name='role'
72+
label='Column role'
73+
defaultValue={column.role ?? DATASET_COLUMN_ROLES.parameter}
74+
/>
75+
</FormWrapper>
76+
</form>
77+
</Modal>
78+
)
79+
}

apps/web/src/app/(private)/datasets/[datasetId]/DatasetDetailTable/DataGrid/index.tsx

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,27 @@ import type {
66
RowsChangeData,
77
CellClickArgs,
88
CellMouseEvent,
9+
RenderHeaderCellProps,
910
} from '@latitude-data/web-ui/data-grid'
10-
import { DataGridCellEditor, type EditorCellProps } from '@latitude-data/web-ui'
11-
import { Text, FloatingPanel, Button } from '@latitude-data/web-ui'
11+
import {
12+
DataGridCellEditor,
13+
type EditorCellProps,
14+
ReactStateDispatch,
15+
Text,
16+
FloatingPanel,
17+
Button,
18+
cn,
19+
} from '@latitude-data/web-ui'
20+
import { DatasetHeadText } from '$/app/(private)/datasets/_components/DatasetHeadText'
1221
import { DatasetRoleStyle } from '$/hooks/useDatasetRoles'
1322
import { DatasetV2 } from '@latitude-data/core/browser'
1423
import { ClientPagination } from '@latitude-data/core/lib/pagination/buildPagination'
15-
import { useCallback, useMemo, useState } from 'react'
24+
import { Suspense, useCallback, useMemo, useState } from 'react'
1625
import { LinkableTablePaginationFooter } from '$/components/TablePaginationFooter'
1726
import { ClientDatasetRow } from '$/stores/datasetRows/rowSerializationHelpers'
1827
import useDatasetRows from '$/stores/datasetRows'
28+
import useDatasets from '$/stores/datasetsV2'
29+
import { UpdateColumnModal } from '$/app/(private)/datasets/[datasetId]/DatasetDetailTable/DataGrid/UpdateColumnModal'
1930

2031
function rowKeyGetter(row: ClientDatasetRow) {
2132
return row.id
@@ -66,14 +77,41 @@ function renderEditCell(props: RenderEditCellProps<ClientDatasetRow, unknown>) {
6677
const initialValue = rawValue === undefined ? '' : String(rawValue)
6778
const valueType = typeof storedRowValue === 'object' ? 'json' : 'text'
6879
return (
69-
<DataGridCellEditor
70-
valueType={valueType}
71-
value={initialValue}
72-
onChange={onChange}
73-
/>
80+
<Suspense fallback={null}>
81+
<DataGridCellEditor
82+
valueType={valueType}
83+
value={initialValue}
84+
onChange={onChange}
85+
/>
86+
</Suspense>
7487
)
7588
}
7689

90+
const renderHeaderCell =
91+
({
92+
setEditColumnKey,
93+
column,
94+
}: {
95+
setEditColumnKey: ReactStateDispatch<string | null>
96+
column: DatasetV2['columns'][0]
97+
}) =>
98+
(props: RenderHeaderCellProps<ClientDatasetRow>) => {
99+
const onClickEdit = useCallback(() => {
100+
setEditColumnKey(props.column.key)
101+
}, [props.column.key, setEditColumnKey])
102+
return (
103+
<div className='flex items-center gap-x-2'>
104+
<DatasetHeadText text={column.name} role={column.role} />
105+
<Button
106+
className='opacity-30 group-hover/cell-header:opacity-100'
107+
variant='nope'
108+
iconProps={{ name: 'pencil', color: 'foregroundMuted' }}
109+
onClick={onClickEdit}
110+
/>
111+
</div>
112+
)
113+
}
114+
77115
type Props = DatasetRowsTableProps & {
78116
updateRows: ReturnType<typeof useDatasetRows>['updateRows']
79117
deleteRows: ReturnType<typeof useDatasetRows>['deleteRows']
@@ -82,14 +120,21 @@ type Props = DatasetRowsTableProps & {
82120

83121
const countLabel = (count: number) => `${count} rows`
84122
export default function DataGrid({
85-
dataset,
123+
dataset: serverDataset,
86124
rows,
87125
updateRows,
88126
deleteRows,
89127
isDeleting,
90128
pagination,
129+
datasetCellRoleStyles,
91130
}: Props) {
131+
const { data } = useDatasets({}, { fallbackData: [serverDataset] })
132+
const dataset = useMemo(() => {
133+
return data.find((d) => d.id === serverDataset.id) ?? serverDataset
134+
}, [data, serverDataset.id])
135+
const { backgroundCssClasses } = datasetCellRoleStyles
92136
const [selectedRows, setSelectedRows] = useState(() => new Set<number>())
137+
const [editColumnKey, setEditColumnKey] = useState<string | null>(null)
93138
const columns = useMemo<DataGridProps<ClientDatasetRow>['columns']>(() => {
94139
const dataColumns: DataGridProps<ClientDatasetRow>['columns'] =
95140
dataset.columns.map((col) => ({
@@ -98,7 +143,16 @@ export default function DataGrid({
98143
resizable: true,
99144
selectable: true,
100145
minWidth: 80,
146+
headerCellClass: cn(
147+
'group/cell-header',
148+
backgroundCssClasses[col.role],
149+
),
101150
renderEditCell,
151+
renderHeaderCell: renderHeaderCell({
152+
column: col,
153+
setEditColumnKey,
154+
}),
155+
cellClass: backgroundCssClasses[col.role],
102156
renderCell,
103157
}))
104158

@@ -136,6 +190,13 @@ export default function DataGrid({
136190

137191
return (
138192
<>
193+
{editColumnKey ? (
194+
<UpdateColumnModal
195+
dataset={dataset}
196+
columnKey={editColumnKey}
197+
onClose={() => setEditColumnKey(null)}
198+
/>
199+
) : null}
139200
<BaseDataGrid<ClientDatasetRow, unknown, number>
140201
rowKeyGetter={rowKeyGetter}
141202
rows={rows}

apps/web/src/stores/datasetsV2.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import useLatitudeAction from '$/hooks/useLatitudeAction'
88
import { ROUTES } from '$/services/routes'
99
import useSWR, { SWRConfiguration } from 'swr'
1010
import { compactObject } from '@latitude-data/core/lib/compactObject'
11+
import { updateDatasetColumnAction } from '$/actions/datasetsV2/updateColumn'
1112

1213
const EMPTY_ARRAY: DatasetV2[] = []
1314
export default function useDatasets(
@@ -73,6 +74,16 @@ export default function useDatasets(
7374
},
7475
})
7576

77+
const { execute: updateColumn, isPending: isUpdatingColumn } =
78+
useLatitudeAction<typeof updateDatasetColumnAction>(
79+
updateDatasetColumnAction,
80+
{
81+
onSuccess: ({ data: dataset }) => {
82+
mutate(data.map((ds) => (ds.id === dataset.id ? dataset : ds)))
83+
},
84+
},
85+
)
86+
7687
return {
7788
data,
7889
mutate,
@@ -81,6 +92,8 @@ export default function useDatasets(
8192
createError,
8293
destroy,
8394
isDestroying,
95+
updateColumn,
96+
isUpdatingColumn,
8497
...rest,
8598
}
8699
}

packages/core/src/data-migrations/datasets-v2/index.test.ts

Lines changed: 0 additions & 94 deletions
This file was deleted.

0 commit comments

Comments
 (0)