From 0982f5a8d05159b61a28fc8c30de410a5ea23a28 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Wed, 15 Jul 2020 17:19:51 +1000 Subject: [PATCH 01/12] delete old colum editor ui --- .../Table/ColumnEditor/DocInput.tsx | 193 --------- .../Table/ColumnEditor/FieldsDropdown.tsx | 39 -- .../Table/ColumnEditor/SelectOptionsInput.tsx | 100 ----- .../components/Table/ColumnEditor/index.tsx | 378 ------------------ 4 files changed, 710 deletions(-) delete mode 100644 www/src/components/Table/ColumnEditor/DocInput.tsx delete mode 100644 www/src/components/Table/ColumnEditor/FieldsDropdown.tsx delete mode 100644 www/src/components/Table/ColumnEditor/SelectOptionsInput.tsx delete mode 100644 www/src/components/Table/ColumnEditor/index.tsx diff --git a/www/src/components/Table/ColumnEditor/DocInput.tsx b/www/src/components/Table/ColumnEditor/DocInput.tsx deleted file mode 100644 index 7f4bebe2..00000000 --- a/www/src/components/Table/ColumnEditor/DocInput.tsx +++ /dev/null @@ -1,193 +0,0 @@ -import React, { useContext, useEffect, useState } from "react"; -import { createStyles, makeStyles, Theme } from "@material-ui/core/styles"; -import Chip from "@material-ui/core/Chip"; -import Grid from "@material-ui/core/Grid"; -import TextField from "@material-ui/core/TextField"; -import Divider from "@material-ui/core/Divider"; -import Select from "@material-ui/core/Select"; - -import MenuItem from "@material-ui/core/MenuItem"; -import useTableConfig from "../../../hooks/useFiretable/useTableConfig"; -import FormControl from "@material-ui/core/FormControl"; -import InputLabel from "@material-ui/core/InputLabel"; -import Input from "@material-ui/core/Input"; - -const useStyles = makeStyles(Theme => - createStyles({ - root: { - display: "flex", - justifyContent: "center", - flexWrap: "wrap", - maxWidth: 300, - padding: Theme.spacing(1), - }, - chip: { - margin: Theme.spacing(0.5), - }, - formControl: { - margin: Theme.spacing(1), - minWidth: 120, - maxWidth: 300, - }, - chips: { - display: "flex", - flexWrap: "wrap", - }, - }) -); - -const ITEM_HEIGHT = 48; -const ITEM_PADDING_TOP = 8; -const MenuProps = { - PaperProps: { - style: { - maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP, - width: 250, - }, - }, -}; - -export default function DocInput(props: any) { - const { collectionPath, setValue } = props; - const [tableConfig, tableConfigActions] = useTableConfig( - collectionPath ? collectionPath : "initial" - ); - - const [columns, setColumns] = useState<{ key: string; name: string }[]>([]); - const [primaryKeys, setPrimaryKeys] = useState([]); - const [secondaryKeys, setSecondaryKeys] = useState([]); - - useEffect(() => { - setColumns(tableConfig.columns); - }, [tableConfig.columns]); - - const classes = useStyles(); - - const onChange = (e: any, v: any) => { - setValue("collectionPath", v.props.value); - setPrimaryKeys([]); - setSecondaryKeys([]); - setColumns([]); - tableConfigActions.setTable(v.props.value); - }; - useEffect(() => { - setValue("config", { - primaryKeys, - secondaryKeys, - }); - }, [primaryKeys, secondaryKeys]); - // WAS USING TABLES CONTEXT RIP - // if (tables.value) - // return ( - // <> - // - // - // Table - // - // - // - // {collectionPath ? ( - // <> - // - // - // Primary Text - // - // } - // renderValue={selected => ( - //
- // {(selected as string[]).map(value => ( - // - // ))} - //
- // )} - // MenuProps={MenuProps} - // > - // {columns && - // columns.length !== 0 && - // columns.map(column => ( - // - // {column.name} - // - // ))} - // - //
- - // - // - // Secondary Text - // - // } - // renderValue={selected => ( - //
- // {(selected as string[]).map(value => ( - // - // ))} - //
- // )} - // MenuProps={MenuProps} - // > - // {columns && - // columns.length !== 0 && - // columns.map(column => ( - // - // {column.name} - // - // ))} - // - //
- // - // ) : ( - // "please select a table" - // )} - // - // ); - // else - return
; -} diff --git a/www/src/components/Table/ColumnEditor/FieldsDropdown.tsx b/www/src/components/Table/ColumnEditor/FieldsDropdown.tsx deleted file mode 100644 index e2600349..00000000 --- a/www/src/components/Table/ColumnEditor/FieldsDropdown.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React from "react"; - -import { TextField, MenuItem, ListItemIcon } from "@material-ui/core"; - -import { FIELDS, FieldType } from "constants/fields"; - -/** - * Returns dropdown component of all available types - */ -const FieldsDropdown = (value: FieldType | null, onChange: any) => { - return ( - - {FIELDS.map( - (field: { icon: JSX.Element; name: string; type: FieldType }) => { - return ( - - - {field.icon} - - {field.name} - - ); - } - )} - - ); -}; - -export default FieldsDropdown; diff --git a/www/src/components/Table/ColumnEditor/SelectOptionsInput.tsx b/www/src/components/Table/ColumnEditor/SelectOptionsInput.tsx deleted file mode 100644 index 94f3c09b..00000000 --- a/www/src/components/Table/ColumnEditor/SelectOptionsInput.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { createStyles, makeStyles, Theme } from "@material-ui/core/styles"; -import Chip from "@material-ui/core/Chip"; -import TextField from "@material-ui/core/TextField"; -import Grid from "@material-ui/core/Grid"; -import Divider from "@material-ui/core/Divider"; -import _includes from "lodash/includes"; -import _camelCase from "lodash/camelCase"; - -import AddIcon from "@material-ui/icons/AddCircle"; -import IconButton from "@material-ui/core/IconButton"; -import InputAdornment from "@material-ui/core/InputAdornment"; -const useStyles = makeStyles(Theme => - createStyles({ - root: {}, - field: { - width: "100%", - }, - chipsContainer: { - display: "flex", - justifyContent: "center", - flexWrap: "wrap", - maxWidth: 300, - padding: Theme.spacing(1), - }, - chip: { - margin: Theme.spacing(0.5), - }, - }) -); - -export default function SelectOptionsInput(props: any) { - const { options, setValue } = props; - const classes = useStyles(); - const [newOption, setNewOption] = useState(""); - const handleAdd = () => { - // setOptions([...options, newOption]); - if (newOption !== "") { - setValue("options", [...options, newOption]); - setNewOption(""); - } - }; - const handleDelete = (optionToDelete: string) => () => { - const newOptions = options.filter( - (option: string) => option !== optionToDelete - ); - setValue("options", newOptions); - }; - - useEffect(() => { - setValue({ data: { options } }); - }, [options]); - - return ( - - - { - setNewOption(e.target.value); - }} - onKeyPress={(e: any) => { - if (e.key === "Enter") { - handleAdd(); - } - }} - InputProps={{ - endAdornment: ( - - { - handleAdd(); - }} - > - {} - - - ), - }} - /> - - - {options.map((option: string) => { - return ( - - ); - })} - - - ); -} diff --git a/www/src/components/Table/ColumnEditor/index.tsx b/www/src/components/Table/ColumnEditor/index.tsx deleted file mode 100644 index 1fbd94c0..00000000 --- a/www/src/components/Table/ColumnEditor/index.tsx +++ /dev/null @@ -1,378 +0,0 @@ -import React, { useEffect, useState } from "react"; -import _findIndex from "lodash/findIndex"; -import Button from "@material-ui/core/Button"; -import FormControl from "@material-ui/core/FormControl"; - -import TextField from "@material-ui/core/TextField"; -import Grid from "@material-ui/core/Grid"; -import Popover from "@material-ui/core/Popover"; -import { createStyles, makeStyles } from "@material-ui/core/styles"; -import FieldsDropdown from "./FieldsDropdown"; -import { FieldType } from "constants/fields"; -import ToggleButton from "@material-ui/lab/ToggleButton"; -import ToggleButtonGroup from "@material-ui/lab/ToggleButtonGroup"; - -import LockIcon from "@material-ui/icons/Lock"; -import LockOpenIcon from "@material-ui/icons/LockOpen"; -import VisibilityIcon from "@material-ui/icons/Visibility"; -import VisibilityOffIcon from "@material-ui/icons/VisibilityOff"; -import FrozenIcon from "@material-ui/icons/AcUnit"; -import ResizeIcon from "@material-ui/icons/PhotoSizeSelectSmall"; -import DeleteIcon from "@material-ui/icons/Delete"; -import SelectOptionsInput from "./SelectOptionsInput"; - -import DocInput from "./DocInput"; -import { Tooltip } from "@material-ui/core"; -import Confirmation from "../../Confirmation"; - -import { useFiretableContext } from "contexts/firetableContext"; - -const useStyles = makeStyles(theme => - createStyles({ - container: { - padding: 15, - }, - typography: { - padding: 1, - }, - - button: { - // margin: theme.spacing(1) - }, - root: { - padding: 10, - display: "flex", - flexWrap: "wrap", - }, - formControl: { - margin: theme.spacing(1), - minWidth: 120, - }, - selectEmpty: { - marginTop: theme.spacing(2), - }, - toggleGrouped: { - margin: theme.spacing(0.5), - border: "none", - padding: theme.spacing(0, 1), - "&:not(:first-child)": { - borderRadius: theme.shape.borderRadius, - }, - "&:first-child": { - borderRadius: theme.shape.borderRadius, - }, - }, - }) -); - -// TODO: REMOVE THIS OLD COMPONENT -export default function ColumnEditor() { - const { - tableState, - tableActions, - selectedColumnHeader, - setSelectedColumnHeader, - } = useFiretableContext() as any; - const actions = tableActions!.column; - const { column, anchorEl } = selectedColumnHeader ?? {}; - - const handleClose = () => { - if (setSelectedColumnHeader) setSelectedColumnHeader(null); - }; - - const [values, setValues] = useState({ - type: null, - name: "", - options: [], - collectionPath: "", - config: {}, - parentLabel: "", - callableName: "", - }); - const [flags, setFlags] = useState(() => [""]); - const classes = useStyles(); - - function handleChange( - event: React.ChangeEvent<{ name?: string; value: unknown }> - ) { - event.stopPropagation(); - event.preventDefault(); - setValues(oldValues => ({ - ...oldValues, - [event.target.name as string]: event.target.value, - })); - } - const setValue = (key: string, value: any) => { - setValues(oldValues => ({ - ...oldValues, - [key]: value, - })); - }; - - useEffect(() => { - if (column && !column.isNew) { - setValues(oldValues => ({ - ...oldValues, - name: column.name, - type: column.type, - key: column.key, - isNew: column.isNew, - })); - if (column.options) { - setValue("options", column.options); - } else { - setValue("options", []); - } - if (column.collectionPath) { - setValue("collectionPath", column.collectionPath); - } - const flags = ["resizable", "editable", "fixed", "hidden"].filter( - flag => - column[flag] === true || - (flag === "resizable" && column[flag] !== false) - ); - setFlags(flags); - } - }, [column]); - - const clearValues = () => { - setValues({ - type: null, - name: "", - options: [], - collectionPath: "", - config: {}, - parentLabel: "", - callableName: "", - }); - }; - const onClose = (event: any) => { - handleClose(); - clearValues(); - }; - - const handleToggle = ( - event: React.MouseEvent, - newFlags: string[] - ) => { - setFlags(newFlags); - }; - - const createNewColumn = () => { - const { name, type, options, collectionPath, config, parentLabel } = values; - - actions.add(name, type, { options, collectionPath, config, parentLabel }); - - handleClose(); - clearValues(); - }; - - // WARNING: column.idx does NOT map to how we store column config in Firestore - // when a column is fixed AND it is not the first column. We should NOT be - // using indexes to manipulate column config anyway! - - const configColumnIndex = _findIndex(tableState?.columns, [ - "key", - column?.key, - ]); - - const deleteColumn = () => { - actions.remove(column?.key); - handleClose(); - clearValues(); - }; - - const updateColumn = () => { - let updatables: { field: string; value: any }[] = [ - { field: "name", value: values.name }, - { field: "type", value: values.type }, - // TEMP: disable resizing fixed columns due to the problem described - // on line 169 - { - field: "resizable", - value: !flags.includes("fixed") && flags.includes("resizable"), - }, - { field: "editable", value: flags.includes("editable") }, - { field: "hidden", value: flags.includes("hidden") }, - { field: "fixed", value: flags.includes("fixed") }, - ]; - if ( - values.type === FieldType.multiSelect || - values.type === FieldType.singleSelect - ) { - updatables.push({ - field: "options", - value: values.options, - }); - } - if (values.type === FieldType.connectTable) { - updatables.push({ - field: "collectionPath", - value: values.collectionPath, - }); - updatables.push({ - field: "config", - value: values.config, - }); - } - if (values.type === FieldType.subTable) { - updatables.push({ field: "parentLabel", value: values.parentLabel }); - } - if (values.type === FieldType.action) { - updatables.push({ field: "callableName", value: values.callableName }); - } - actions.update(configColumnIndex, updatables); - handleClose(); - clearValues(); - }; - - const disableAdd = () => { - const { type, name, options, collectionPath, config } = values; - if (!type || name === "") return true; - //TODO: Add more validation - return false; - }; - - if (column) - return ( - - - - - - {flags.includes("editable") ? : } - - - {/* - - {flags.includes("visible") ? ( - - ) : ( - - )} - - */} - - - - - - - - - - - - - - { - setValue("name", e.target.value); - }} - /> - - {FieldsDropdown(values.type, handleChange)} - - {(values.type === FieldType.singleSelect || - values.type === FieldType.multiSelect) && ( - - )} - {values.type === FieldType.connectTable && ( - - )} - {values.type === FieldType.subTable && ( - { - setValue("parentLabel", e.target.value); - }} - /> - )} - {values.type === FieldType.action && ( - { - setValue("callableName", e.target.value); - }} - /> - )} - - - {column.isNew ? ( - - ) : ( - - )} - - - {!column.isNew && ( - - - - - - )} - - - - - ); - - return null; -} From de27c807e7ac04d1b4018e5236e9b7a6df0fc182 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Wed, 15 Jul 2020 17:22:12 +1000 Subject: [PATCH 02/12] store filters in _FT_user doc for each table --- www/src/components/Table/Filters/index.tsx | 77 ++++++++++++++++------ www/src/components/Table/TableHeader.tsx | 6 +- 2 files changed, 59 insertions(+), 24 deletions(-) diff --git a/www/src/components/Table/Filters/index.tsx b/www/src/components/Table/Filters/index.tsx index c941d741..35f4b5ad 100644 --- a/www/src/components/Table/Filters/index.tsx +++ b/www/src/components/Table/Filters/index.tsx @@ -8,12 +8,11 @@ import { Button, Typography, IconButton, - FormControl, Grid, - Select, MenuItem, TextField, Switch, + Chip, } from "@material-ui/core"; import FilterIcon from "@material-ui/icons/FilterList"; import CloseIcon from "@material-ui/icons/Close"; @@ -25,6 +24,8 @@ import { FireTableFilter } from "hooks/useFiretable"; import { useFiretableContext } from "contexts/firetableContext"; import DocSelector from "./DocSelector"; +import { useAppContext } from "contexts/appContext"; +import { DocActions } from "hooks/useDoc"; const OPERATORS = [ { value: "==", @@ -94,10 +95,29 @@ const useStyles = makeStyles(theme => }) ); -const Filters = ({ columns, setFilters }: any) => { - const { userClaims } = useFiretableContext(); - const filterColumns = columns - .filter(c => c.type !== FieldType.file && c.type !== FieldType.image) +const UNFILTERABLES = [ + FieldType.image, + FieldType.file, + FieldType.action, + FieldType.subTable, + FieldType.last, +]; +const Filters = () => { + const { userClaims, tableState, tableActions } = useFiretableContext(); + const { userDoc } = useAppContext(); + + useEffect(() => { + if (userDoc.state.doc && tableState?.tablePath) { + if (userDoc.state.doc.tables?.[tableState?.tablePath]?.filters) { + console.log(userDoc.state.doc.tables[tableState?.tablePath].filters); + tableActions?.table.filter( + userDoc.state.doc.tables[tableState?.tablePath].filters + ); + } + } + }, [userDoc.state, tableState?.tablePath]); + const filterColumns = Object.values(tableState!.columns) + .filter(c => !UNFILTERABLES.includes(c.type)) .map(c => ({ key: c.key, label: c.name, @@ -273,19 +293,38 @@ const Filters = ({ columns, setFilters }: any) => { break; } }; + + const handleUpdateFilters = (filters: FireTableFilter[]) => { + userDoc.dispatch({ + action: DocActions.update, + data: { + tables: { [`${tableState?.tablePath}`]: { filters } }, + }, + }); + }; return ( <> - - + + + {(tableState?.filters ?? []).map(filter => ( + { + handleUpdateFilters([]); + }} + /> + ))} + {