From 109960d7575fa2cf205d002df7dfd3102021384d Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Fri, 3 Jun 2022 12:34:18 +1000 Subject: [PATCH] prepare updated SideDrawer without react-hook-form --- .../ColumnConfigModal/DefaultValueInput.tsx | 2 +- .../SideDrawer/{Form => }/FieldSkeleton.tsx | 0 src/components/SideDrawer/FieldWrapper.tsx | 113 ++++++++++++++ src/components/SideDrawer/SideDrawer.tsx | 18 +-- .../SideDrawer/SideDrawerFields.tsx | 143 ++++++++++++++++++ src/components/SideDrawer/{Form => }/utils.ts | 34 ++--- src/components/TableToolbar/ColumnSelect.tsx | 2 +- .../Extensions/Step3Conditions.tsx | 2 +- .../TableToolbar/Extensions/Step4Body.tsx | 2 +- .../TableToolbar/Filters/FilterInputs.tsx | 2 +- src/components/fields/Action/Settings.tsx | 2 +- .../fields/Action/SideDrawerField.tsx | 2 +- .../fields/Checkbox/SideDrawerField.tsx | 2 +- .../fields/Color/SideDrawerField.tsx | 2 +- src/components/fields/Connector/Settings.tsx | 2 +- .../fields/CreatedAt/SideDrawerField.tsx | 2 +- .../fields/CreatedBy/SideDrawerField.tsx | 2 +- src/components/fields/Derivative/Settings.tsx | 2 +- .../fields/Duration/SideDrawerField.tsx | 2 +- .../fields/File/SideDrawerField.tsx | 2 +- src/components/fields/Id/SideDrawerField.tsx | 2 +- .../fields/Image/SideDrawerField.tsx | 2 +- .../fields/Json/SideDrawerField.tsx | 2 +- .../fields/Rating/SideDrawerField.tsx | 2 +- .../fields/Slider/SideDrawerField.tsx | 2 +- .../fields/SubTable/SideDrawerField.tsx | 2 +- .../fields/UpdatedAt/SideDrawerField.tsx | 2 +- .../fields/UpdatedBy/SideDrawerField.tsx | 2 +- .../fields/User/SideDrawerField.tsx | 2 +- src/components/fields/types.ts | 13 +- 30 files changed, 312 insertions(+), 57 deletions(-) rename src/components/SideDrawer/{Form => }/FieldSkeleton.tsx (100%) create mode 100644 src/components/SideDrawer/FieldWrapper.tsx create mode 100644 src/components/SideDrawer/SideDrawerFields.tsx rename src/components/SideDrawer/{Form => }/utils.ts (61%) diff --git a/src/components/ColumnModals/ColumnConfigModal/DefaultValueInput.tsx b/src/components/ColumnModals/ColumnConfigModal/DefaultValueInput.tsx index fd025967..a510a913 100644 --- a/src/components/ColumnModals/ColumnConfigModal/DefaultValueInput.tsx +++ b/src/components/ColumnModals/ColumnConfigModal/DefaultValueInput.tsx @@ -7,7 +7,7 @@ import FormControlLabel from "@mui/material/FormControlLabel"; import { Typography, TextField, MenuItem, ListItemText } from "@mui/material"; import { getFieldProp } from "@src/components/fields"; -import FieldSkeleton from "@src/components/SideDrawer/Form/FieldSkeleton"; +import FieldSkeleton from "@src/components/SideDrawer/FieldSkeleton"; import CodeEditorHelper from "@src/components/CodeEditor/CodeEditorHelper"; import FormAutosave from "./FormAutosave"; import { FieldType } from "@src/constants/fields"; diff --git a/src/components/SideDrawer/Form/FieldSkeleton.tsx b/src/components/SideDrawer/FieldSkeleton.tsx similarity index 100% rename from src/components/SideDrawer/Form/FieldSkeleton.tsx rename to src/components/SideDrawer/FieldSkeleton.tsx diff --git a/src/components/SideDrawer/FieldWrapper.tsx b/src/components/SideDrawer/FieldWrapper.tsx new file mode 100644 index 00000000..e27f6c35 --- /dev/null +++ b/src/components/SideDrawer/FieldWrapper.tsx @@ -0,0 +1,113 @@ +import { Suspense } from "react"; +import { useAtom } from "jotai"; +import { ErrorBoundary } from "react-error-boundary"; + +import { Stack, InputLabel, Typography, IconButton } from "@mui/material"; +import { DocumentPath as DocumentPathIcon } from "@src/assets/icons"; +import LaunchIcon from "@mui/icons-material/Launch"; +import LockIcon from "@mui/icons-material/LockOutlined"; + +import { InlineErrorFallback } from "@src/components/ErrorFallback"; +import FieldSkeleton from "./FieldSkeleton"; + +import { globalScope, projectIdAtom } from "@src/atoms/globalScope"; +import { FieldType } from "@src/constants/fields"; +import { getFieldProp } from "@src/components/fields"; + +export interface IFieldWrapperProps { + children?: React.ReactNode; + type: FieldType | "debug"; + name?: string; + label?: React.ReactNode; + debugText?: React.ReactNode; + disabled?: boolean; +} + +export default function FieldWrapper({ + children, + type, + name, + label, + debugText, + disabled, +}: IFieldWrapperProps) { + const [projectId] = useAtom(projectIdAtom, globalScope); + + return ( +
+ + {type === "debug" ? : getFieldProp("icon", type)} + + {label} + + {disabled && } + + + + }> + {children ?? + (!debugText && ( + + This field cannot be edited here. + + ))} + + + + {debugText && ( + + + {debugText} + + + + + + + )} +
+ ); +} diff --git a/src/components/SideDrawer/SideDrawer.tsx b/src/components/SideDrawer/SideDrawer.tsx index 583e5cde..817e5c5c 100644 --- a/src/components/SideDrawer/SideDrawer.tsx +++ b/src/components/SideDrawer/SideDrawer.tsx @@ -1,7 +1,7 @@ import { useEffect } from "react"; import clsx from "clsx"; import { useAtom } from "jotai"; -import { findIndex } from "lodash-es"; +import { find, findIndex } from "lodash-es"; import { ErrorBoundary } from "react-error-boundary"; import { DataGridHandle } from "react-data-grid"; @@ -12,6 +12,7 @@ import ChevronDownIcon from "@mui/icons-material/KeyboardArrowDown"; import ErrorFallback from "@src/components/ErrorFallback"; import StyledDrawer from "./StyledDrawer"; +import SideDrawerFields from "./SideDrawerFields"; // import Form from "./Form"; import { globalScope, userSettingsAtom } from "@src/atoms/globalScope"; @@ -44,6 +45,7 @@ export default function SideDrawer({ const [cell, setCell] = useAtom(selectedCellAtom, tableScope); const [open, setOpen] = useAtom(sideDrawerOpenAtom, tableScope); + const selectedRow = find(tableRows, ["_rowy_ref.path", cell?.path]); const selectedCellRowIndex = findIndex(tableRows, [ "_rowy_ref.path", cell?.path, @@ -109,17 +111,9 @@ export default function SideDrawer({ >
- {cell?.path} - {/* {open && - (urlDocState.doc || cell) && - !isEmpty(tableState?.columns) && ( -
- )} */} + {open && cell && selectedRow && ( + + )}
diff --git a/src/components/SideDrawer/SideDrawerFields.tsx b/src/components/SideDrawer/SideDrawerFields.tsx new file mode 100644 index 00000000..1f0838a6 --- /dev/null +++ b/src/components/SideDrawer/SideDrawerFields.tsx @@ -0,0 +1,143 @@ +import { useEffect, createElement } from "react"; +import { useAtom } from "jotai"; +import { isEmpty, get } from "lodash-es"; + +import { Stack, FormControlLabel, Switch } from "@mui/material"; +import FieldWrapper from "./FieldWrapper"; + +import { + globalScope, + userRolesAtom, + userSettingsAtom, + sideDrawerShowHiddenFieldsAtom, +} from "@src/atoms/globalScope"; +import { + tableScope, + tableIdAtom, + tableSettingsAtom, + tableColumnsOrderedAtom, + selectedCellAtom, +} from "@src/atoms/tableScope"; +import { formatSubTableName } from "@src/utils/table"; +import { getFieldProp } from "@src/components/fields"; +import { TableRow } from "@src/types/table"; +import { IFieldConfig } from "@src/components/fields/types"; + +export interface ISideDrawerFieldsProps { + row: TableRow; +} + +export default function SideDrawerFields({ row }: ISideDrawerFieldsProps) { + const [userRoles] = useAtom(userRolesAtom, globalScope); + const [userSettings] = useAtom(userSettingsAtom, globalScope); + const [tableId] = useAtom(tableIdAtom, tableScope); + const [tableSettings] = useAtom(tableSettingsAtom, tableScope); + const [tableColumnsOrdered] = useAtom(tableColumnsOrderedAtom, tableScope); + const [selectedCell] = useAtom(selectedCellAtom, tableScope); + const [showHiddenFields, setShowHiddenFields] = useAtom( + sideDrawerShowHiddenFieldsAtom, + globalScope + ); + + const userDocHiddenFields = + userSettings.tables?.[formatSubTableName(tableId)]?.hiddenFields ?? []; + + const fields = showHiddenFields + ? tableColumnsOrdered + : tableColumnsOrdered.filter((f) => !userDocHiddenFields.includes(f.key)); + + // Scroll to selected column + const selectedColumnKey = selectedCell?.columnKey; + useEffect(() => { + if (!selectedColumnKey) return; + + const labelElem = document.getElementById( + `sidedrawer-label-${selectedColumnKey}` + )?.parentElement; + const fieldElem = document.getElementById( + `sidedrawer-field-${selectedColumnKey}` + ); + + // Time out for double-clicking on cells, which can open the null editor + setTimeout(() => { + if (labelElem) labelElem.scrollIntoView({ behavior: "smooth" }); + if (fieldElem) fieldElem.focus({ preventScroll: true }); + }, 200); + }, [selectedColumnKey]); + + return ( + + {fields.map((field, i) => { + // Derivative/aggregate field support + let type = field.type; + if (field.config && field.config.renderFieldType) { + type = field.config.renderFieldType; + } + + const fieldComponent: IFieldConfig["SideDrawerField"] = getFieldProp( + "SideDrawerField", + type + ); + + // Should not reach this state + if (isEmpty(fieldComponent)) { + // console.error('Could not find SideDrawerField component', field); + return null; + } + + // Disable field if locked, or if table is read-only + const disabled = Boolean( + field.editable === false || + (tableSettings.readOnly && !userRoles.includes("ADMIN")) + ); + + return ( + + {createElement(fieldComponent, { + column: field as any, + control: {} as any, + docRef: row._rowy_ref, + disabled, + value: get(row, field.fieldName), + onSubmit: console.log, + useFormMethods: {} as any, + })} + + ); + })} + + + + {userDocHiddenFields.length > 0 && ( + + ); +} diff --git a/src/components/SideDrawer/Form/utils.ts b/src/components/SideDrawer/utils.ts similarity index 61% rename from src/components/SideDrawer/Form/utils.ts rename to src/components/SideDrawer/utils.ts index 251aff73..db2deeb3 100644 --- a/src/components/SideDrawer/Form/utils.ts +++ b/src/components/SideDrawer/utils.ts @@ -1,25 +1,25 @@ -import { Control } from "react-hook-form"; +// import { Control } from "react-hook-form"; import { colord } from "colord"; import type { SystemStyleObject, Theme } from "@mui/system"; -import { FieldType } from "@src/constants/fields"; -import { TableRowRef } from "@src/types/table"; +// import { FieldType } from "@src/constants/fields"; +// import { TableRowRef } from "@src/types/table"; -export interface IFieldProps { - control: Control; - name: string; - docRef: TableRowRef; - editable?: boolean; -} +// export interface ISideDrawerFieldProps { +// control: Control; +// name: string; +// docRef: TableRowRef; +// editable?: boolean; +// } -export type Values = Record; -export type Field = { - type?: FieldType; - name: string; - label?: string; - [key: string]: any; -}; -export type Fields = (Field | ((values: Values) => Field))[]; +// export type Values = Record; +// export type Field = { +// type?: FieldType; +// name: string; +// label?: string; +// [key: string]: any; +// }; +// export type Fields = (Field | ((values: Values) => Field))[]; export const fieldSx: SystemStyleObject = { borderRadius: 1, diff --git a/src/components/TableToolbar/ColumnSelect.tsx b/src/components/TableToolbar/ColumnSelect.tsx index bd09d402..1264d67c 100644 --- a/src/components/TableToolbar/ColumnSelect.tsx +++ b/src/components/TableToolbar/ColumnSelect.tsx @@ -94,7 +94,7 @@ export function ColumnItem({ { diff --git a/src/components/fields/Rating/SideDrawerField.tsx b/src/components/fields/Rating/SideDrawerField.tsx index 17acbce5..46b0691d 100644 --- a/src/components/fields/Rating/SideDrawerField.tsx +++ b/src/components/fields/Rating/SideDrawerField.tsx @@ -6,7 +6,7 @@ import { Rating as MuiRating } from "@mui/material"; import "@mui/lab"; import StarBorderIcon from "@mui/icons-material/StarBorder"; -import { fieldSx } from "@src/components/SideDrawer/Form/utils"; +import { fieldSx } from "@src/components/SideDrawer/utils"; export default function Rating({ control, diff --git a/src/components/fields/Slider/SideDrawerField.tsx b/src/components/fields/Slider/SideDrawerField.tsx index 246c3dc6..ece70e4c 100644 --- a/src/components/fields/Slider/SideDrawerField.tsx +++ b/src/components/fields/Slider/SideDrawerField.tsx @@ -2,7 +2,7 @@ import { Controller } from "react-hook-form"; import { ISideDrawerFieldProps } from "@src/components/fields/types"; import { Slider as MuiSlider, Stack, Typography } from "@mui/material"; -import { fieldSx } from "@src/components/SideDrawer/Form/utils"; +import { fieldSx } from "@src/components/SideDrawer/utils"; export default function Slider({ control, diff --git a/src/components/fields/SubTable/SideDrawerField.tsx b/src/components/fields/SubTable/SideDrawerField.tsx index f04a884f..e85292d5 100644 --- a/src/components/fields/SubTable/SideDrawerField.tsx +++ b/src/components/fields/SubTable/SideDrawerField.tsx @@ -5,7 +5,7 @@ import { Link } from "react-router-dom"; import { Box, Stack, IconButton } from "@mui/material"; import LaunchIcon from "@mui/icons-material/Launch"; -import { fieldSx } from "@src/components/SideDrawer/Form/utils"; +import { fieldSx } from "@src/components/SideDrawer/utils"; import { useSubTableData } from "./utils"; export default function SubTable({ diff --git a/src/components/fields/UpdatedAt/SideDrawerField.tsx b/src/components/fields/UpdatedAt/SideDrawerField.tsx index b098e26c..e7c32d0d 100644 --- a/src/components/fields/UpdatedAt/SideDrawerField.tsx +++ b/src/components/fields/UpdatedAt/SideDrawerField.tsx @@ -3,7 +3,7 @@ import { useAtom } from "jotai"; import { ISideDrawerFieldProps } from "@src/components/fields/types"; import { Box } from "@mui/material"; -import { fieldSx } from "@src/components/SideDrawer/Form/utils"; +import { fieldSx } from "@src/components/SideDrawer/utils"; import { format } from "date-fns"; import { DATE_TIME_FORMAT } from "@src/constants/dates"; diff --git a/src/components/fields/UpdatedBy/SideDrawerField.tsx b/src/components/fields/UpdatedBy/SideDrawerField.tsx index cec39b06..b56cd2d2 100644 --- a/src/components/fields/UpdatedBy/SideDrawerField.tsx +++ b/src/components/fields/UpdatedBy/SideDrawerField.tsx @@ -3,7 +3,7 @@ import { useAtom } from "jotai"; import { ISideDrawerFieldProps } from "@src/components/fields/types"; import { Box, Stack, Typography, Avatar } from "@mui/material"; -import { fieldSx } from "@src/components/SideDrawer/Form/utils"; +import { fieldSx } from "@src/components/SideDrawer/utils"; import { format } from "date-fns"; import { DATE_TIME_FORMAT } from "@src/constants/dates"; diff --git a/src/components/fields/User/SideDrawerField.tsx b/src/components/fields/User/SideDrawerField.tsx index ef0528fa..9e76183a 100644 --- a/src/components/fields/User/SideDrawerField.tsx +++ b/src/components/fields/User/SideDrawerField.tsx @@ -2,7 +2,7 @@ import { Controller } from "react-hook-form"; import { ISideDrawerFieldProps } from "@src/components/fields/types"; import { Box, Stack, Typography, Avatar } from "@mui/material"; -import { fieldSx } from "@src/components/SideDrawer/Form/utils"; +import { fieldSx } from "@src/components/SideDrawer/utils"; import { format } from "date-fns"; import { DATE_TIME_FORMAT } from "@src/constants/dates"; diff --git a/src/components/fields/types.ts b/src/components/fields/types.ts index ea42fa7f..8bb080fd 100644 --- a/src/components/fields/types.ts +++ b/src/components/fields/types.ts @@ -3,8 +3,8 @@ import { FormatterProps, EditorProps } from "react-data-grid"; import { Control, UseFormReturn } from "react-hook-form"; import { PopoverProps } from "@mui/material"; import { WhereFilterOp } from "firebase/firestore"; -import { TableRow, TableRowRef } from "@src/types/table"; -// import { SelectedCell } from "@src/atoms/ContextMenu"; +import { ColumnConfig, TableRow, TableRowRef } from "@src/types/table"; +import { selectedCellAtom } from "@src/atoms/tableScope"; import { IContextMenuActions } from "./_BasicCell/BasicCellContextMenuActions"; export { FieldType }; @@ -21,7 +21,7 @@ export interface IFieldConfig { description?: string; setupGuideLink?: string; contextMenuActions?: ( - selectedCell: any, // FIXME: SelectedCell, + selectedCell: ReturnType, reset: () => Promise ) => IContextMenuActions[]; TableCell: React.ComponentType>; @@ -62,10 +62,15 @@ export interface IPopoverCellProps extends IPopoverInlineCellProps { } export interface ISideDrawerFieldProps { - column: FormatterProps["column"] & { config?: Record }; + column: FormatterProps["column"] & ColumnConfig; control: Control; docRef: TableRowRef; disabled: boolean; + + value: any; + onSubmit: (value: any) => void; + + /** @deprecated */ useFormMethods: UseFormReturn; }