From 82b97854761bbaa34e43ee143da030809233560f Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Tue, 12 Jan 2021 19:31:41 +1100 Subject: [PATCH] add SingleSelect, MultiSelect --- www/src/components/Table/withPopoverCell.tsx | 18 ++-- .../MultiSelect/ConvertStringToArray.tsx | 26 ++++++ .../fields/MultiSelect/PopoverBasicCell.tsx | 89 +++++++++++++++++++ .../fields/MultiSelect/PopoverCell.tsx | 43 +++++++++ .../fields/MultiSelect/SideDrawerField.tsx | 76 ++++++++++++++++ .../components/fields/MultiSelect/index.tsx | 35 ++++++++ .../components/fields/MultiSelect/utils.ts | 4 + .../fields/SingleSelect/PopoverBasicCell.tsx | 61 +++++++++++++ .../fields/SingleSelect/PopoverCell.tsx | 43 +++++++++ .../fields/SingleSelect/SideDrawerField.tsx | 49 ++++++++++ .../components/fields/SingleSelect/index.tsx | 35 ++++++++ .../components/fields/SingleSelect/utils.ts | 5 ++ www/src/components/fields/index.tsx | 6 +- www/src/components/fields/types.ts | 3 + 14 files changed, 484 insertions(+), 9 deletions(-) create mode 100644 www/src/components/fields/MultiSelect/ConvertStringToArray.tsx create mode 100644 www/src/components/fields/MultiSelect/PopoverBasicCell.tsx create mode 100644 www/src/components/fields/MultiSelect/PopoverCell.tsx create mode 100644 www/src/components/fields/MultiSelect/SideDrawerField.tsx create mode 100644 www/src/components/fields/MultiSelect/index.tsx create mode 100644 www/src/components/fields/MultiSelect/utils.ts create mode 100644 www/src/components/fields/SingleSelect/PopoverBasicCell.tsx create mode 100644 www/src/components/fields/SingleSelect/PopoverCell.tsx create mode 100644 www/src/components/fields/SingleSelect/SideDrawerField.tsx create mode 100644 www/src/components/fields/SingleSelect/index.tsx create mode 100644 www/src/components/fields/SingleSelect/utils.ts diff --git a/www/src/components/Table/withPopoverCell.tsx b/www/src/components/Table/withPopoverCell.tsx index 0a3417cf..e53493d6 100644 --- a/www/src/components/Table/withPopoverCell.tsx +++ b/www/src/components/Table/withPopoverCell.tsx @@ -64,6 +64,13 @@ export default function withPopoverCell( setLocalValue(value); }, [value]); + const handleSubmit = (value: any) => { + if (updateCell && !options?.readOnly) { + updateCell(props.row.ref, props.column.key as string, value); + setLocalValue(value); + } + }; + const basicCell = ( ); @@ -79,13 +87,6 @@ export default function withPopoverCell( const parentRef = basicCellRef.current?.parentElement; - const handleSubmit = (value: any) => { - if (updateCell && !options?.readOnly) { - updateCell(props.row.ref, props.column.key as string, value); - setLocalValue(value); - } - }; - // Switch to heavy cell Component once basic cell is clicked return ( <> @@ -104,6 +105,8 @@ export default function withPopoverCell( }, ...popoverProps?.PaperProps, }} + onClick={(e) => e.stopPropagation()} + onKeyDown={(e) => e.stopPropagation()} > diff --git a/www/src/components/fields/MultiSelect/ConvertStringToArray.tsx b/www/src/components/fields/MultiSelect/ConvertStringToArray.tsx new file mode 100644 index 00000000..1177087e --- /dev/null +++ b/www/src/components/fields/MultiSelect/ConvertStringToArray.tsx @@ -0,0 +1,26 @@ +import React from "react"; +import { Grid, Tooltip, Button } from "@material-ui/core"; + +export const ConvertStringToArray = ({ value, onSubmit }) => ( + + + {value} + + + + + + + +); diff --git a/www/src/components/fields/MultiSelect/PopoverBasicCell.tsx b/www/src/components/fields/MultiSelect/PopoverBasicCell.tsx new file mode 100644 index 00000000..ff8a9686 --- /dev/null +++ b/www/src/components/fields/MultiSelect/PopoverBasicCell.tsx @@ -0,0 +1,89 @@ +import React from "react"; +import clsx from "clsx"; +import { IPopoverBasicCellProps } from "../types"; + +import { makeStyles, createStyles, ButtonBase, Grid } from "@material-ui/core"; +import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown"; + +import { sanitiseValue } from "./utils"; +import FormattedChip from "components/FormattedChip"; +import { ConvertStringToArray } from "./ConvertStringToArray"; + +const useStyles = makeStyles((theme) => + createStyles({ + root: { + height: "100%", + padding: theme.spacing(0, 1, 0, 1.5), + + font: "inherit", + color: "inherit !important", + letterSpacing: "inherit", + textAlign: "inherit", + justifyContent: "flex-start", + }, + + value: { + flex: 1, + maxWidth: `calc(100% - 24px + 4px)`, + overflow: "hidden", + marginRight: 0, + }, + chip: { + display: "flex", + cursor: "inherit", + }, + chipLabel: { whiteSpace: "nowrap" }, + + icon: { + display: "block", + color: theme.palette.action.active, + }, + disabled: { + color: theme.palette.action.disabled, + }, + }) +); + +export const SingleSelect = React.forwardRef(function SingleSelect( + { value, setShowComplexCell, disabled, onSubmit }: IPopoverBasicCellProps, + ref: React.Ref +) { + const classes = useStyles(); + + if (typeof value === "string" && value !== "") + return ; + + return ( + setShowComplexCell(true)} + ref={ref} + disabled={disabled} + > + + {sanitiseValue(value).map( + (item) => + typeof item === "string" && ( + + + + ) + )} + + + + + ); +}); +export default SingleSelect; diff --git a/www/src/components/fields/MultiSelect/PopoverCell.tsx b/www/src/components/fields/MultiSelect/PopoverCell.tsx new file mode 100644 index 00000000..6f7efec2 --- /dev/null +++ b/www/src/components/fields/MultiSelect/PopoverCell.tsx @@ -0,0 +1,43 @@ +import React from "react"; +import { IPopoverCellProps } from "../types"; +import _get from "lodash/get"; + +import MultiSelect_ from "@antlerengineering/multiselect"; + +import { sanitiseValue } from "./utils"; + +export default function SingleSelect({ + value, + onSubmit, + column, + parentRef, + setShowComplexCell, + disabled, +}: IPopoverCellProps) { + const config = column.config ?? {}; + + return ( + setShowComplexCell(false)} + /> + ); +} diff --git a/www/src/components/fields/MultiSelect/SideDrawerField.tsx b/www/src/components/fields/MultiSelect/SideDrawerField.tsx new file mode 100644 index 00000000..beecd21c --- /dev/null +++ b/www/src/components/fields/MultiSelect/SideDrawerField.tsx @@ -0,0 +1,76 @@ +import React from "react"; +import { Controller } from "react-hook-form"; +import { ISideDrawerFieldProps } from "../types"; + +import { useTheme, Grid } from "@material-ui/core"; +import MultiSelect_ from "@antlerengineering/multiselect"; +import FormattedChip from "components/FormattedChip"; + +import { sanitiseValue } from "./utils"; +import { ConvertStringToArray } from "./ConvertStringToArray"; + +export default function SingleSelect({ + column, + control, + disabled, +}: ISideDrawerFieldProps) { + const theme = useTheme(); + + const config = column.config ?? {}; + + return ( + { + const handleDelete = (index: number) => () => { + const newValues = [...value]; + newValues.splice(index, 1); + onChange(newValues); + }; + + if (typeof value === "string" && value !== "") + return ; + + return ( + <> + + + {value && Array.isArray(value) && ( + + {value.map( + (item, i) => + item?.length > 0 && ( + + + + ) + )} + + )} + + ); + }} + /> + ); +} diff --git a/www/src/components/fields/MultiSelect/index.tsx b/www/src/components/fields/MultiSelect/index.tsx new file mode 100644 index 00000000..0db14658 --- /dev/null +++ b/www/src/components/fields/MultiSelect/index.tsx @@ -0,0 +1,35 @@ +import React, { lazy } from "react"; +import { IFieldConfig, FieldType } from "components/fields/types"; +import withPopoverCell from "components/Table/withPopoverCell"; + +import MultiSelectIcon from "assets/icons/MultiSelect"; +import PopoverBasicCell from "./PopoverBasicCell"; +import NullEditor from "components/Table/editors/NullEditor"; + +const PopoverCell = lazy( + () => + import("./PopoverCell" /* webpackChunkName: "PopoverCell-MultiSelect" */) +); +const SideDrawerField = lazy( + () => + import( + "./SideDrawerField" /* webpackChunkName: "SideDrawerField-MultiSelect" */ + ) +); + +export const config: IFieldConfig = { + type: FieldType.multiSelect, + name: "MultiSelect", + dataType: "string[]", + initialValue: [], + icon: , + description: + "Dropdown selector with searchable options and check box behavior. Optionally allows users to input custom values. Max selection: all options.", + TableCell: withPopoverCell(PopoverCell, PopoverBasicCell, { + anchorOrigin: { horizontal: "left", vertical: "bottom" }, + transparent: true, + }), + TableEditor: NullEditor, + SideDrawerField, +}; +export default config; diff --git a/www/src/components/fields/MultiSelect/utils.ts b/www/src/components/fields/MultiSelect/utils.ts new file mode 100644 index 00000000..d2feec47 --- /dev/null +++ b/www/src/components/fields/MultiSelect/utils.ts @@ -0,0 +1,4 @@ +export const sanitiseValue = (value: any) => { + if (value === undefined || value === null || value === "") return []; + else return value as string[]; +}; diff --git a/www/src/components/fields/SingleSelect/PopoverBasicCell.tsx b/www/src/components/fields/SingleSelect/PopoverBasicCell.tsx new file mode 100644 index 00000000..0f42c7c7 --- /dev/null +++ b/www/src/components/fields/SingleSelect/PopoverBasicCell.tsx @@ -0,0 +1,61 @@ +import React from "react"; +import clsx from "clsx"; +import { IPopoverBasicCellProps } from "../types"; + +import { makeStyles, createStyles, ButtonBase } from "@material-ui/core"; +import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown"; + +import { sanitiseValue } from "./utils"; + +const useStyles = makeStyles((theme) => + createStyles({ + root: { + height: "100%", + padding: theme.spacing(0, 1, 0, 1.5), + + font: "inherit", + color: "inherit !important", + letterSpacing: "inherit", + textAlign: "inherit", + justifyContent: "flex-start", + }, + + value: { + flex: 1, + maxWidth: `calc(100% - 24px)`, + overflow: "hidden", + textOverflow: "ellipsis", + }, + + icon: { + display: "block", + color: theme.palette.action.active, + }, + disabled: { + color: theme.palette.action.disabled, + }, + }) +); + +export const SingleSelect = React.forwardRef(function SingleSelect( + { value, setShowComplexCell, disabled }: IPopoverBasicCellProps, + ref: React.Ref +) { + const classes = useStyles(); + + return ( + setShowComplexCell(true)} + ref={ref} + disabled={disabled} + > +
{sanitiseValue(value)}
+ + +
+ ); +}); +export default SingleSelect; diff --git a/www/src/components/fields/SingleSelect/PopoverCell.tsx b/www/src/components/fields/SingleSelect/PopoverCell.tsx new file mode 100644 index 00000000..33a1b082 --- /dev/null +++ b/www/src/components/fields/SingleSelect/PopoverCell.tsx @@ -0,0 +1,43 @@ +import React from "react"; +import { IPopoverCellProps } from "../types"; +import _get from "lodash/get"; + +import MultiSelect_ from "@antlerengineering/multiselect"; + +import { sanitiseValue } from "./utils"; + +export default function SingleSelect({ + value, + onSubmit, + column, + parentRef, + setShowComplexCell, + disabled, +}: IPopoverCellProps) { + const config = column.config ?? {}; + + return ( + setShowComplexCell(false)} + /> + ); +} diff --git a/www/src/components/fields/SingleSelect/SideDrawerField.tsx b/www/src/components/fields/SingleSelect/SideDrawerField.tsx new file mode 100644 index 00000000..93069283 --- /dev/null +++ b/www/src/components/fields/SingleSelect/SideDrawerField.tsx @@ -0,0 +1,49 @@ +import React from "react"; +import { Controller } from "react-hook-form"; +import { ISideDrawerFieldProps } from "../types"; + +import { useTheme } from "@material-ui/core"; +import MultiSelect_ from "@antlerengineering/multiselect"; +import FormattedChip from "components/FormattedChip"; + +import { sanitiseValue } from "./utils"; + +export default function SingleSelect({ + column, + control, + disabled, +}: ISideDrawerFieldProps) { + const theme = useTheme(); + + const config = column.config ?? {}; + + return ( + ( + <> + + + {value?.length > 0 && ( +
+ +
+ )} + + )} + /> + ); +} diff --git a/www/src/components/fields/SingleSelect/index.tsx b/www/src/components/fields/SingleSelect/index.tsx new file mode 100644 index 00000000..eee9eaa5 --- /dev/null +++ b/www/src/components/fields/SingleSelect/index.tsx @@ -0,0 +1,35 @@ +import React, { lazy } from "react"; +import { IFieldConfig, FieldType } from "components/fields/types"; +import withPopoverCell from "components/Table/withPopoverCell"; + +import SingleSelectIcon from "@material-ui/icons/FormatListBulleted"; +import PopoverBasicCell from "./PopoverBasicCell"; +import NullEditor from "components/Table/editors/NullEditor"; + +const PopoverCell = lazy( + () => + import("./PopoverCell" /* webpackChunkName: "PopoverCell-SingleSelect" */) +); +const SideDrawerField = lazy( + () => + import( + "./SideDrawerField" /* webpackChunkName: "SideDrawerField-SingleSelect" */ + ) +); + +export const config: IFieldConfig = { + type: FieldType.singleSelect, + name: "SingleSelect", + dataType: "string | null", + initialValue: null, + icon: , + description: + "Dropdown selector with searchable options and radio button behavior. Optionally allows users to input custom values. Max selection: 1 option.", + TableCell: withPopoverCell(PopoverCell, PopoverBasicCell, { + anchorOrigin: { horizontal: "left", vertical: "bottom" }, + transparent: true, + }), + TableEditor: NullEditor, + SideDrawerField, +}; +export default config; diff --git a/www/src/components/fields/SingleSelect/utils.ts b/www/src/components/fields/SingleSelect/utils.ts new file mode 100644 index 00000000..3070d669 --- /dev/null +++ b/www/src/components/fields/SingleSelect/utils.ts @@ -0,0 +1,5 @@ +export const sanitiseValue = (value: any) => { + if (value === undefined || value === null || value === "") return null; + else if (Array.isArray(value)) return value[0] as string; + else return value as string; +}; diff --git a/www/src/components/fields/index.tsx b/www/src/components/fields/index.tsx index 59610a11..cc34bd41 100644 --- a/www/src/components/fields/index.tsx +++ b/www/src/components/fields/index.tsx @@ -21,6 +21,8 @@ import DateTime from "./DateTime"; import Duration from "./Duration"; import Image_ from "./Image"; import File_ from "./File"; +import SingleSelect from "./SingleSelect"; +import MultiSelect from "./MultiSelect"; import SubTable from "./SubTable"; import Json from "./Json"; import Code from "./Code"; @@ -54,8 +56,8 @@ export const FIELDS: IFieldConfig[] = [ Image_, File_, // SELECT - // TODO: singleSelect, - // TODO: multiSelect, + SingleSelect, + MultiSelect, // CONNECTION SubTable, // TODO: connectTable, diff --git a/www/src/components/fields/types.ts b/www/src/components/fields/types.ts index 3a341194..54c3a1e6 100644 --- a/www/src/components/fields/types.ts +++ b/www/src/components/fields/types.ts @@ -2,6 +2,7 @@ import { FieldType } from "constants/fields"; import { FormatterProps, EditorProps } from "react-data-grid"; import { Control } from "react-hook-form"; +import { PopoverProps } from "@material-ui/core"; export { FieldType }; @@ -36,10 +37,12 @@ export interface IBasicCellProps { export interface IPopoverCellProps extends ICustomCellProps { setShowComplexCell: React.Dispatch>; + parentRef: PopoverProps["anchorEl"]; } export interface IPopoverBasicCellProps extends IBasicCellProps { setShowComplexCell: React.Dispatch>; disabled: boolean; + onSubmit: (value: any) => void; } export interface ISideDrawerFieldProps {