UNPKG

wcz-layout

Version:

148 lines (137 loc) 5.2 kB
--- name: data-grid description: "Use when: building or configuring MUI X DataGrid tables, editable columns, toolbar actions, row selection, or TanStack DB-backed grids." --- ## Rules - Wrap DataGrid in `Fullscreen` when it is the only content on the page. - Type columns as `Array<GridColDef<RowType>>` with the row interface. - Use translation for all `headerName` values. - Use `rows`, `columns`, `showToolbar`, `loading`, `ignoreDiacritics`, `cellSelection`, and `disableRowSelectionOnClick` on grids. - For enums use `type: "singleSelect"` with `{ value, label }` options array used from enumObject. - For editable columns, pair `editable: true` with `renderHeader: EditableColumnHeader`. - Use `ChipInputCell`, `EditableColumnHeader`, and router button/grid action components from `wcz-layout/components` when they fit. ## File Placement ``` @mui/x-data-grid-premium — GridColDef, DataGridPremium src/db-collections/ - TanStack DB collections to get data @tanstack/react-db - useLiveQuery, useLiveSuspenseQuery src/server/actions/ - server functions and enums wcz-layout/components - ChipInputCell, EditableColumnHeader, Fullscreen wcz-layout/hooks - useTranslation ``` ## Examples ```tsx // src/routes/<feature>s/index.tsx const { t } = useTranslation(); const { confirm, alert } = useDialogs(); const navigate = useNavigate(); const [cellSelectionModel, setCellSelectionModel] = useState<GridCellSelectionModel>({}); const { data, isLoading } = useLiveQuery((q) => q.from({ feature: featureCollection }).orderBy(({ feature }) => feature.name, "asc"), ); const columns: Array<GridColDef<Feature>> = [ { field: "name", headerName: t("Feature.Name"), width: 200, editable: true, renderHeader: EditableColumnHeader, }, { field: "tags", headerName: t("Feature.Tags"), width: 200, renderCell: (params) => <ChipInputCell params={params} />, }, { field: "status", headerName: t("Feature.Status"), width: 200, type: "singleSelect", valueOptions: featureStatusEnum.enumValues.map((status) => ({ value: status, label: t(`FeatureStatus.${status}`), })), }, ]; const handleOnDelete = createOptimisticAction<Array<string>>({ onMutate: (ids) => { ids.forEach((id) => { featureCollection.delete(id); }); }, mutationFn: async (ids) => { deleteFeatures({ data: ids }); await featureCollection.utils.refetch(); }, }); return ( <Fullscreen> <DataGridPremium rows={data} columns={columns} showToolbar loading={isLoading} ignoreDiacritics onRowDoubleClick={({ row }) => navigate({ to: "/features/$id", params: { id: row.id } })} cellSelection disableRowSelectionOnClick cellSelectionModel={cellSelectionModel} onCellSelectionModelChange={(newModel) => setCellSelectionModel(newModel)} slots={{ toolbar: DataGridToolbar }} slotProps={{ toolbar: { title: t("Feature.Features"), actions: [ <Tooltip key="create" title={t("Create")}> <RouterIconButton to="/features/create"> <Add fontSize="small" /> </RouterIconButton> </Tooltip>, Object.keys(cellSelectionModel).length === 1 && ( <Tooltip key="edit" title={t("Edit")}> <RouterIconButton to="/features/edit/$id" params={{ id: Object.keys(cellSelectionModel)[0].toString() }} > <Edit fontSize="small" /> </RouterIconButton> </Tooltip> ), Object.keys(cellSelectionModel).length > 0 && ( <Tooltip key="delete" title={t("Delete")}> <IconButton onClick={async () => { const confirmed = await confirm( t("DeleteConfirmation", { count: Object.keys(cellSelectionModel).length }), ); if (confirmed) { try { const transaction = handleOnDelete( Object.keys(cellSelectionModel).map((id) => id.toString()), ); await transaction.isPersisted.promise; setCellSelectionModel({}); } catch (error) { if (error instanceof Error) await alert(error.message); } } }} > <Badge badgeContent={Object.keys(cellSelectionModel).length} invisible={Object.keys(cellSelectionModel).length <= 1} color="error" > <Delete fontSize="small" /> </Badge> </IconButton> </Tooltip> ), ], }, }} /> </Fullscreen> ); ```