From ba8c6209aa567e01fa9f2f50224f00c17c4d3172 Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Fri, 31 Jan 2020 12:02:11 +1100 Subject: [PATCH 01/46] finish ColumnMenu styling --- www/src/assets/icons/CellResize.tsx | 10 + www/src/assets/icons/ColumnPlusAfter.tsx | 13 + www/src/assets/icons/ColumnPlusBefore.tsx | 13 + www/src/assets/icons/ColumnRemove.tsx | 13 + www/src/assets/icons/Freeze.tsx | 13 + www/src/assets/icons/Unfreeze.tsx | 13 + www/src/components/Table/ColumnMenu/index.tsx | 226 ++++++++++++++++++ www/src/components/Table/Grid.tsx | 1 + www/src/components/Table/index.tsx | 8 +- 9 files changed, 309 insertions(+), 1 deletion(-) create mode 100644 www/src/assets/icons/CellResize.tsx create mode 100644 www/src/assets/icons/ColumnPlusAfter.tsx create mode 100644 www/src/assets/icons/ColumnPlusBefore.tsx create mode 100644 www/src/assets/icons/ColumnRemove.tsx create mode 100644 www/src/assets/icons/Freeze.tsx create mode 100644 www/src/assets/icons/Unfreeze.tsx create mode 100644 www/src/components/Table/ColumnMenu/index.tsx diff --git a/www/src/assets/icons/CellResize.tsx b/www/src/assets/icons/CellResize.tsx new file mode 100644 index 00000000..687d4f3a --- /dev/null +++ b/www/src/assets/icons/CellResize.tsx @@ -0,0 +1,10 @@ +import React from "react"; +import SvgIcon, { SvgIconProps } from "@material-ui/core/SvgIcon"; + +export default function FileDownload(props: SvgIconProps) { + return ( + + + + ); +} diff --git a/www/src/assets/icons/ColumnPlusAfter.tsx b/www/src/assets/icons/ColumnPlusAfter.tsx new file mode 100644 index 00000000..5b707006 --- /dev/null +++ b/www/src/assets/icons/ColumnPlusAfter.tsx @@ -0,0 +1,13 @@ +import React from "react"; +import SvgIcon, { SvgIconProps } from "@material-ui/core/SvgIcon"; + +export default function FileDownload(props: SvgIconProps) { + return ( + + + + ); +} diff --git a/www/src/assets/icons/ColumnPlusBefore.tsx b/www/src/assets/icons/ColumnPlusBefore.tsx new file mode 100644 index 00000000..6ee2f15f --- /dev/null +++ b/www/src/assets/icons/ColumnPlusBefore.tsx @@ -0,0 +1,13 @@ +import React from "react"; +import SvgIcon, { SvgIconProps } from "@material-ui/core/SvgIcon"; + +export default function FileDownload(props: SvgIconProps) { + return ( + + + + ); +} diff --git a/www/src/assets/icons/ColumnRemove.tsx b/www/src/assets/icons/ColumnRemove.tsx new file mode 100644 index 00000000..e09a8de6 --- /dev/null +++ b/www/src/assets/icons/ColumnRemove.tsx @@ -0,0 +1,13 @@ +import React from "react"; +import SvgIcon, { SvgIconProps } from "@material-ui/core/SvgIcon"; + +export default function FileDownload(props: SvgIconProps) { + return ( + + + + ); +} diff --git a/www/src/assets/icons/Freeze.tsx b/www/src/assets/icons/Freeze.tsx new file mode 100644 index 00000000..e73cf28a --- /dev/null +++ b/www/src/assets/icons/Freeze.tsx @@ -0,0 +1,13 @@ +import React from "react"; +import SvgIcon, { SvgIconProps } from "@material-ui/core/SvgIcon"; + +export default function FileDownload(props: SvgIconProps) { + return ( + + + + ); +} diff --git a/www/src/assets/icons/Unfreeze.tsx b/www/src/assets/icons/Unfreeze.tsx new file mode 100644 index 00000000..8b887a04 --- /dev/null +++ b/www/src/assets/icons/Unfreeze.tsx @@ -0,0 +1,13 @@ +import React from "react"; +import SvgIcon, { SvgIconProps } from "@material-ui/core/SvgIcon"; + +export default function FileDownload(props: SvgIconProps) { + return ( + + + + ); +} diff --git a/www/src/components/Table/ColumnMenu/index.tsx b/www/src/components/Table/ColumnMenu/index.tsx new file mode 100644 index 00000000..ae4ba386 --- /dev/null +++ b/www/src/components/Table/ColumnMenu/index.tsx @@ -0,0 +1,226 @@ +import React from "react"; +import clsx from "clsx"; + +import { + createStyles, + makeStyles, + Menu, + MenuProps, + MenuItem, + ListItemIcon, + ListSubheader, +} from "@material-ui/core"; +import { fade } from "@material-ui/core/styles"; + +import LockOpenIcon from "@material-ui/icons/LockOpen"; +import LockIcon from "@material-ui/icons/Lock"; +import VisibilityOffIcon from "@material-ui/icons/VisibilityOff"; +import VisibilityIcon from "@material-ui/icons/Visibility"; +import FreezeIcon from "assets/icons/Freeze"; +import UnfreezeIcon from "assets/icons/Unfreeze"; +import CellResizeIcon from "assets/icons/CellResize"; +import ArrowDownwardIcon from "@material-ui/icons/ArrowDownward"; +import ArrowUpwardIcon from "@material-ui/icons/ArrowUpward"; +import EditIcon from "@material-ui/icons/Edit"; +import ReorderIcon from "@material-ui/icons/Reorder"; +import ColumnPlusBeforeIcon from "assets/icons/ColumnPlusBefore"; +import ColumnPlusAfterIcon from "assets/icons/ColumnPlusAfter"; +import ColumnRemoveIcon from "assets/icons/ColumnRemove"; + +// Note: this only imports the type +import { Column } from "react-data-grid"; + +const useStyles = makeStyles(theme => + createStyles({ + paper: { + // TODO: change this if we need to support a dark mode + backgroundColor: "#f1f1f3", + }, + + list: { + "& > * + *": { borderTop: `1px solid ${theme.palette.divider}` }, + }, + + subheader: { + ...theme.typography.overline, + color: theme.palette.text.disabled, + padding: theme.spacing(1, 1.25), + paddingTop: theme.spacing(2) + 1, + + cursor: "default", + userSelect: "none", + + "&:focus": { outline: 0 }, + }, + + menuItem: { + minHeight: 44 - 1, + padding: theme.spacing(0.75, 1.25), + + ...theme.typography.h6, + fontSize: "0.875rem", + color: theme.palette.text.secondary, + }, + menuItemIcon: { + minWidth: 24, + marginRight: theme.spacing(1.25), + color: "inherit", + }, + + menuItemActive: { color: theme.palette.text.primary }, + menuItemError: { + color: theme.palette.error.main, + "&:hover": { + backgroundColor: fade( + theme.palette.error.main, + theme.palette.action.hoverOpacity + ), + }, + }, + }) +); + +export interface IColumnMenuProps { + anchorEl: MenuProps["anchorEl"]; + handleClose: MenuProps["onClose"]; + column: Column; +} + +const ColumnMenu: React.FC = ({ + anchorEl, + handleClose, + column, +}) => { + const classes = useStyles(); + + const menuItems = [ + { type: "subheader", label: "View" }, + { + label: "Lock", + activeLabel: "Locked", + icon: , + activeIcon: , + onClick: () => alert("LOCK"), + active: false, + }, + { + label: "Hide", + activeLabel: "Show", + icon: , + activeIcon: , + onClick: () => alert("HIDE/SHOW"), + active: false, + }, + { + label: "Freeze", + activeLabel: "Unfreeze", + icon: , + activeIcon: , + onClick: () => alert("FREEZE"), + active: false, + }, + { + label: "Enable resize", + activeLabel: "Disable resize", + icon: , + onClick: () => alert("RESIZE"), + active: false, + }, + { + label: "Sort: Decreasing", + activeLabel: "Sorted: Decreasing", + icon: , + onClick: () => alert("SORT DECREASING"), + active: false, + }, + { + label: "Sort: Increasing", + activeLabel: "Sorted: Increasing", + icon: , + onClick: () => alert("SORT INCREASING"), + active: false, + }, + { type: "subheader", label: "Edit" }, + { + label: "Rename", + icon: , + onClick: () => alert("EDIT"), + }, + { + label: "Edit Type", + // TODO: This is based off the cell type + // icon: , + onClick: () => alert("EDIT TYPE"), + }, + { + label: "Re-order", + icon: , + onClick: () => alert("REORDER"), + }, + { + label: "Add New to Left", + icon: , + onClick: () => alert("ADD NEW LEFT"), + }, + { + label: "Add New to Right", + icon: , + onClick: () => alert("ADD NEW RIGHT"), + }, + { + label: "Delete Column", + icon: , + onClick: () => alert("DELETE COLUMN"), + color: "error", + }, + ]; + + return ( + + {menuItems.map((item, index) => { + if (item.type === "subheader") + return ( + + {item.label} + + ); + + let icon = item.icon ?? <>; + if (item.active && !!item.activeIcon) icon = item.activeIcon; + + return ( + + {icon} + {item.active ? item.activeLabel : item.label} + + ); + })} + + ); +}; + +export default ColumnMenu; diff --git a/www/src/components/Table/Grid.tsx b/www/src/components/Table/Grid.tsx index 721d4cc9..be2368a3 100644 --- a/www/src/components/Table/Grid.tsx +++ b/www/src/components/Table/Grid.tsx @@ -8,6 +8,7 @@ import xorWith from "lodash/xorWith"; import Loading from "../Loading"; const ReactDataGrid = lazy(() => import("react-data-grid")); + const { DraggableContainer } = DraggableHeader; const Grid = (props: any) => { const { diff --git a/www/src/components/Table/index.tsx b/www/src/components/Table/index.tsx index 75a21e26..b997b4f2 100644 --- a/www/src/components/Table/index.tsx +++ b/www/src/components/Table/index.tsx @@ -45,6 +45,7 @@ const TableHeader = lazy(() => import("./TableHeader")); const SearchBox = lazy(() => import("../SearchBox")); const DocSelect = lazy(() => import("../Fields/DocSelect")); const ColumnEditor = lazy(() => import("./ColumnEditor/index")); +const ColumnMenu = lazy(() => import("./ColumnMenu/index")); const deleteAlgoliaRecord = functions.httpsCallable( CLOUD_FUNCTIONS.deleteAlgoliaRecord @@ -367,11 +368,16 @@ function Table(props: Props) { )} }> - */} + From 2eee8e382039bbcb509018daba4a637214d0f269 Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Fri, 31 Jan 2020 12:27:51 +1100 Subject: [PATCH 02/46] fix svg/jsx fillRule issue --- www/src/assets/icons/Freeze.tsx | 2 +- www/src/assets/icons/Unfreeze.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/www/src/assets/icons/Freeze.tsx b/www/src/assets/icons/Freeze.tsx index e73cf28a..fd66e7c5 100644 --- a/www/src/assets/icons/Freeze.tsx +++ b/www/src/assets/icons/Freeze.tsx @@ -6,7 +6,7 @@ export default function FileDownload(props: SvgIconProps) { ); diff --git a/www/src/assets/icons/Unfreeze.tsx b/www/src/assets/icons/Unfreeze.tsx index 8b887a04..f2a88b81 100644 --- a/www/src/assets/icons/Unfreeze.tsx +++ b/www/src/assets/icons/Unfreeze.tsx @@ -6,7 +6,7 @@ export default function FileDownload(props: SvgIconProps) { ); From 06bd757473230577739bacc64a92c7a77601b747 Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Fri, 31 Jan 2020 12:28:08 +1100 Subject: [PATCH 03/46] fix divider, menu hover, menu icon --- www/src/components/Table/ColumnMenu/index.tsx | 74 +++++++++++-------- www/src/components/Table/index.tsx | 16 ++-- 2 files changed, 53 insertions(+), 37 deletions(-) diff --git a/www/src/components/Table/ColumnMenu/index.tsx b/www/src/components/Table/ColumnMenu/index.tsx index ae4ba386..0153ed69 100644 --- a/www/src/components/Table/ColumnMenu/index.tsx +++ b/www/src/components/Table/ColumnMenu/index.tsx @@ -9,6 +9,7 @@ import { MenuItem, ListItemIcon, ListSubheader, + Divider, } from "@material-ui/core"; import { fade } from "@material-ui/core/styles"; @@ -37,10 +38,6 @@ const useStyles = makeStyles(theme => backgroundColor: "#f1f1f3", }, - list: { - "& > * + *": { borderTop: `1px solid ${theme.palette.divider}` }, - }, - subheader: { ...theme.typography.overline, color: theme.palette.text.disabled, @@ -54,12 +51,20 @@ const useStyles = makeStyles(theme => }, menuItem: { - minHeight: 44 - 1, + minHeight: 42, padding: theme.spacing(0.75, 1.25), ...theme.typography.h6, fontSize: "0.875rem", color: theme.palette.text.secondary, + transition: theme.transitions.create(["background-color", "color"], { + duration: theme.transitions.duration.shortest, + }), + + "&:hover": { + backgroundColor: theme.palette.text.primary, + color: "#f1f1f3", + }, }, menuItemIcon: { minWidth: 24, @@ -83,9 +88,10 @@ const useStyles = makeStyles(theme => export interface IColumnMenuProps { anchorEl: MenuProps["anchorEl"]; handleClose: MenuProps["onClose"]; - column: Column; + column: Column & { [key: string]: any }; } +// TODO: implement active states and actions const ColumnMenu: React.FC = ({ anchorEl, handleClose, @@ -101,7 +107,7 @@ const ColumnMenu: React.FC = ({ icon: , activeIcon: , onClick: () => alert("LOCK"), - active: false, + active: column.locked, }, { label: "Hide", @@ -124,7 +130,7 @@ const ColumnMenu: React.FC = ({ activeLabel: "Disable resize", icon: , onClick: () => alert("RESIZE"), - active: false, + active: column.resizable, }, { label: "Sort: Decreasing", @@ -147,7 +153,7 @@ const ColumnMenu: React.FC = ({ onClick: () => alert("EDIT"), }, { - label: "Edit Type", + label: `Edit Type: ${column?.type}`, // TODO: This is based off the cell type // icon: , onClick: () => alert("EDIT TYPE"), @@ -185,38 +191,46 @@ const ColumnMenu: React.FC = ({ getContentAnchorEl={null} anchorOrigin={{ vertical: "bottom", horizontal: "right" }} transformOrigin={{ vertical: "top", horizontal: "right" }} - classes={{ paper: classes.paper, list: classes.list }} + classes={{ paper: classes.paper }} MenuListProps={{ disablePadding: true }} > {menuItems.map((item, index) => { if (item.type === "subheader") return ( - - {item.label} - + <> + {index !== 0 && } + + {item.label} + + ); let icon = item.icon ?? <>; if (item.active && !!item.activeIcon) icon = item.activeIcon; return ( - - {icon} - {item.active ? item.activeLabel : item.label} - + <> + {index !== 0 && } + + + {icon} + + {item.active ? item.activeLabel : item.label} + + ); })} diff --git a/www/src/components/Table/index.tsx b/www/src/components/Table/index.tsx index b997b4f2..21c88a9d 100644 --- a/www/src/components/Table/index.tsx +++ b/www/src/components/Table/index.tsx @@ -9,7 +9,7 @@ import { Tooltip, } from "@material-ui/core"; import ImportExportIcon from "@material-ui/icons/ImportExport"; -import SettingsIcon from "@material-ui/icons/Settings"; +import ArrowDropDownCircleIcon from "@material-ui/icons/ArrowDropDownCircle"; import Confirmation from "components/Confirmation"; import DeleteIcon from "@material-ui/icons/Delete"; import DuplicateIcon from "@material-ui/icons/FileCopy"; @@ -204,7 +204,7 @@ function Table(props: Props) { size="small" onClick={handleClick(props)} > - + @@ -374,11 +374,13 @@ function Table(props: Props) { column={header && header.column} actions={tableActions.column} /> */} - + {header && header.column && ( + + )} From c0905458a698358bf5b563543446b0b0256ba4aa Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Wed, 18 Mar 2020 16:09:08 +0800 Subject: [PATCH 04/46] read column config --- firetable | 1 + www/src/components/SideDrawer/index.tsx | 75 ++++++++++---------- www/src/components/Table/index.tsx | 2 +- www/src/hooks/useFiretable/useTableConfig.ts | 17 +++-- 4 files changed, 54 insertions(+), 41 deletions(-) create mode 160000 firetable diff --git a/firetable b/firetable new file mode 160000 index 00000000..655a4ec3 --- /dev/null +++ b/firetable @@ -0,0 +1 @@ +Subproject commit 655a4ec3985e6359416a5b2501bf878ce7a8830b diff --git a/www/src/components/SideDrawer/index.tsx b/www/src/components/SideDrawer/index.tsx index 23024b03..8a687c44 100644 --- a/www/src/components/SideDrawer/index.tsx +++ b/www/src/components/SideDrawer/index.tsx @@ -53,50 +53,53 @@ export default function SideDrawer() { }; // Map columns to form fields - const fields = tableState?.columns?.map(column => { - const field: Field = { - type: column.type, - name: column.key, - label: column.name, - }; + let fields: any[] = []; + if (tableState && tableState.columns) { + fields = Object.values(tableState.columns).map(column => { + const field: Field = { + type: column.type, + name: column.key, + label: column.name, + }; - switch (column.type) { - case FieldType.longText: - field.fieldVariant = "long"; - break; + switch (column.type) { + case FieldType.longText: + field.fieldVariant = "long"; + break; - case FieldType.email: - field.fieldVariant = "email"; - break; + case FieldType.email: + field.fieldVariant = "email"; + break; - case FieldType.phone: - field.fieldVariant = "phone"; - break; + case FieldType.phone: + field.fieldVariant = "phone"; + break; - case FieldType.number: - field.fieldVariant = "number"; - break; + case FieldType.number: + field.fieldVariant = "number"; + break; - case FieldType.singleSelect: - case FieldType.multiSelect: - field.options = column.options; - break; + case FieldType.singleSelect: + case FieldType.multiSelect: + field.options = column.options; + break; - case FieldType.connectTable: - field.collectionPath = column.collectionPath; - field.config = column.config; - break; + case FieldType.connectTable: + field.collectionPath = column.collectionPath; + field.config = column.config; + break; - case FieldType.action: - field.callableName = column.callableName; - break; + case FieldType.action: + field.callableName = column.callableName; + break; - default: - break; - } - field.editable = column.editable; - return field; - }); + default: + break; + } + field.editable = column.editable; + return field; + }); + } return (
diff --git a/www/src/components/Table/index.tsx b/www/src/components/Table/index.tsx index c5c20426..1e9c7a44 100644 --- a/www/src/components/Table/index.tsx +++ b/www/src/components/Table/index.tsx @@ -100,7 +100,7 @@ export default function Table({ collection, filters }: ITableProps) { let columns: FiretableColumn[] = []; if (!tableState.loadingColumns && tableState.columns) { - columns = tableState.columns + columns = Object.values(tableState.columns) .filter((column: any) => !column.hidden) .map((column: any, index) => ({ draggable: true, diff --git a/www/src/hooks/useFiretable/useTableConfig.ts b/www/src/hooks/useFiretable/useTableConfig.ts index 21ebb427..8082ac07 100644 --- a/www/src/hooks/useFiretable/useTableConfig.ts +++ b/www/src/hooks/useFiretable/useTableConfig.ts @@ -70,12 +70,21 @@ const useTableConfig = (tablePath?: string) => { * @param index of column. * @param {updatable[]} updatables properties to be updated */ - const updateColumn = (index: number, updatables: updatable[]) => { + const updateColumn = (key: string, updatables: updatable[]) => { const { columns } = tableConfigState; - updatables.forEach((updatable: updatable) => { - columns[index][updatable.field] = updatable.value; + const columnUpdates = updatables.reduce((acc, curr) => { + return { ...acc, [curr.field]: curr.value }; + }, {}); + + const updatedColumns = { + ...columns, + [key]: { ...columns[key], ...columnUpdates }, + }; + console.log({ key, updatedColumns, columnUpdates }); + documentDispatch({ + action: DocActions.update, + data: { columns: updatedColumns }, }); - documentDispatch({ action: DocActions.update, data: { columns } }); }; /** remove column by index * @param index of column. From 11349377eb269e65f6bcd190cad3a98f00a1d71f Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Thu, 19 Mar 2020 14:14:00 +0800 Subject: [PATCH 05/46] delete and add columns --- .../components/Table/ColumnEditor/index.tsx | 2 +- www/src/components/Table/index.tsx | 32 +++++++++++-------- www/src/firebase/index.ts | 2 ++ www/src/hooks/useDoc.ts | 3 ++ www/src/hooks/useFiretable/useTableConfig.ts | 22 +++++++++---- 5 files changed, 40 insertions(+), 21 deletions(-) diff --git a/www/src/components/Table/ColumnEditor/index.tsx b/www/src/components/Table/ColumnEditor/index.tsx index 36886466..d30ecb5f 100644 --- a/www/src/components/Table/ColumnEditor/index.tsx +++ b/www/src/components/Table/ColumnEditor/index.tsx @@ -176,7 +176,7 @@ export default function ColumnEditor() { ]); const deleteColumn = () => { - actions.remove(configColumnIndex); + actions.remove(column?.key); handleClose(); clearValues(); }; diff --git a/www/src/components/Table/index.tsx b/www/src/components/Table/index.tsx index 1e9c7a44..199ed4c0 100644 --- a/www/src/components/Table/index.tsx +++ b/www/src/components/Table/index.tsx @@ -1,4 +1,6 @@ import React, { lazy, Suspense, useEffect, useRef } from "react"; + +import _orderBy from "lodash/orderBy"; import { useDebouncedCallback } from "use-debounce"; import _isEmpty from "lodash/isEmpty"; @@ -100,19 +102,22 @@ export default function Table({ collection, filters }: ITableProps) { let columns: FiretableColumn[] = []; if (!tableState.loadingColumns && tableState.columns) { - columns = Object.values(tableState.columns) - .filter((column: any) => !column.hidden) - .map((column: any, index) => ({ - draggable: true, - editable: true, - resizable: true, - frozen: column.fixed, - headerRenderer: ColumnHeader, - formatter: getFormatter(column), - editor: getEditor(column), - ...column, - width: column.width ? (column.width > 380 ? 380 : column.width) : 150, - })); + columns = _orderBy( + Object.values(tableState.columns).filter( + (column: any) => !column.hidden && column.key + ), + "index" + ).map((column: any, index) => ({ + draggable: true, + editable: true, + resizable: true, + frozen: column.fixed, + headerRenderer: ColumnHeader, + formatter: getFormatter(column), + editor: getEditor(column), + ...column, + width: column.width ? (column.width > 380 ? 380 : column.width) : 150, + })); columns.push({ isNew: true, key: "new", @@ -125,6 +130,7 @@ export default function Table({ collection, filters }: ITableProps) { editable: false, }); } + console.log(columns); const rowHeight = tableState.config.rowHeight; diff --git a/www/src/firebase/index.ts b/www/src/firebase/index.ts index 8e9244a7..447f8bde 100644 --- a/www/src/firebase/index.ts +++ b/www/src/firebase/index.ts @@ -23,3 +23,5 @@ db.enablePersistence({ synchronizeTabs: true }); export const bucket = firebase.storage(); export const functions = firebase.functions(); export const googleProvider = new firebase.auth.GoogleAuthProvider(); + +export const deleteField = firebase.firestore.FieldValue.delete; diff --git a/www/src/hooks/useDoc.ts b/www/src/hooks/useDoc.ts index 309aa012..f7d27f10 100644 --- a/www/src/hooks/useDoc.ts +++ b/www/src/hooks/useDoc.ts @@ -13,13 +13,16 @@ const documentIntialState = { ref: null, loading: true, }; + const documentReducer = (prevState: any, newProps: any) => { switch (newProps.action) { case DocActions.clear: return documentIntialState; case DocActions.update: // takes data object form the dispatcher and updates doc + prevState.ref.set({ ...newProps.data }, { merge: true }); + return { ...prevState, doc: { ...prevState.doc, ...newProps.data } }; case DocActions.delete: prevState.ref.delete(); diff --git a/www/src/hooks/useFiretable/useTableConfig.ts b/www/src/hooks/useFiretable/useTableConfig.ts index 8082ac07..08ce0612 100644 --- a/www/src/hooks/useFiretable/useTableConfig.ts +++ b/www/src/hooks/useFiretable/useTableConfig.ts @@ -5,7 +5,9 @@ import { FieldType } from "constants/fields"; import _camelCase from "lodash/camelCase"; import _findIndex from "lodash/findIndex"; import { arrayMover } from "../../util/fns"; -import { db } from "../../firebase"; +import { db, deleteField } from "../../firebase"; + +//import const formatPathRegex = /\/[^\/]+\/([^\/]+)/g; @@ -45,13 +47,14 @@ const useTableConfig = (tablePath?: string) => { */ const add = (name: string, type: FieldType, data?: any) => { //TODO: validation - - //console.log("tableConfigState", tableConfigState); const { columns } = tableConfigState; + const newIndex = Object.keys(columns).length; + let updatedColumns = columns; const key = _camelCase(name); + updatedColumns[key] = { name, key, type, ...data, index: newIndex }; documentDispatch({ action: DocActions.update, - data: { columns: [...columns, { name, key, type, ...data }] }, + data: { columns: updatedColumns }, }); }; @@ -89,10 +92,15 @@ const useTableConfig = (tablePath?: string) => { /** remove column by index * @param index of column. */ - const remove = (index: number) => { + const remove = (key: string) => { const { columns } = tableConfigState; - columns.splice(index, 1); - documentDispatch({ action: DocActions.update, data: { columns } }); + let updatedColumns = columns; + updatedColumns[key] = deleteField(); + console.log({ updatedColumns }); + documentDispatch({ + action: DocActions.update, + data: { columns: updatedColumns }, + }); }; /** reorder columns by key * @param draggedColumnKey column being repositioned. From 1a5afce0b7aacaf4921029f4b2c94e2e5abdd22b Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Thu, 19 Mar 2020 17:46:39 +1100 Subject: [PATCH 06/46] fix ColumnMenu --- .../Table/ColumnMenu/MenuContents.tsx | 123 ++++++++++++++++ www/src/components/Table/ColumnMenu/index.tsx | 139 ++++-------------- www/src/components/Table/index.tsx | 16 +- 3 files changed, 151 insertions(+), 127 deletions(-) create mode 100644 www/src/components/Table/ColumnMenu/MenuContents.tsx diff --git a/www/src/components/Table/ColumnMenu/MenuContents.tsx b/www/src/components/Table/ColumnMenu/MenuContents.tsx new file mode 100644 index 00000000..ebac8834 --- /dev/null +++ b/www/src/components/Table/ColumnMenu/MenuContents.tsx @@ -0,0 +1,123 @@ +import React from "react"; +import clsx from "clsx"; + +import { + createStyles, + makeStyles, + MenuItem, + ListItemIcon, + ListSubheader, + Divider, +} from "@material-ui/core"; +import { fade } from "@material-ui/core/styles"; + +const useStyles = makeStyles(theme => + createStyles({ + subheader: { + ...theme.typography.overline, + color: theme.palette.text.disabled, + padding: theme.spacing(1, 1.25), + paddingTop: theme.spacing(2) + 1, + + cursor: "default", + userSelect: "none", + + "&:focus": { outline: 0 }, + }, + + menuItem: { + minHeight: 42, + padding: theme.spacing(0.75, 1.25), + + ...theme.typography.h6, + fontSize: "0.875rem", + color: theme.palette.text.secondary, + transition: theme.transitions.create(["background-color", "color"], { + duration: theme.transitions.duration.shortest, + }), + + "&:hover": { + backgroundColor: theme.palette.text.primary, + color: "#f1f1f3", + }, + }, + menuItemIcon: { + minWidth: 24, + marginRight: theme.spacing(1.25), + color: "inherit", + }, + + menuItemActive: { color: theme.palette.text.primary }, + menuItemError: { + color: theme.palette.error.main, + "&:hover": { + backgroundColor: fade( + theme.palette.error.main, + theme.palette.action.hoverOpacity + ), + }, + }, + }) +); + +export interface IMenuContentsProps { + menuItems: { + type?: string; + label?: string; + activeLabel?: string; + icon?: JSX.Element; + activeIcon?: JSX.Element; + onClick?: () => void; + active?: boolean; + color?: "error"; + }[]; +} + +// TODO: implement active states and actions +export default function MenuContents({ menuItems }: IMenuContentsProps) { + const classes = useStyles(); + + return ( + <> + {menuItems.map((item, index) => { + if (item.type === "subheader") + return ( + <> + {index !== 0 && } + + {item.label} + + + ); + + let icon: JSX.Element = item.icon ?? <>; + if (item.active && !!item.activeIcon) icon = item.activeIcon; + + return ( + <> + {index !== 0 && } + + + {icon} + + {item.active ? item.activeLabel : item.label} + + + ); + })} + + ); +} diff --git a/www/src/components/Table/ColumnMenu/index.tsx b/www/src/components/Table/ColumnMenu/index.tsx index 0153ed69..f2bd7ec8 100644 --- a/www/src/components/Table/ColumnMenu/index.tsx +++ b/www/src/components/Table/ColumnMenu/index.tsx @@ -1,17 +1,8 @@ import React from "react"; -import clsx from "clsx"; -import { - createStyles, - makeStyles, - Menu, - MenuProps, - MenuItem, - ListItemIcon, - ListSubheader, - Divider, -} from "@material-ui/core"; -import { fade } from "@material-ui/core/styles"; +import { createStyles, makeStyles, Menu } from "@material-ui/core"; + +import MenuContents from "./MenuContents"; import LockOpenIcon from "@material-ui/icons/LockOpen"; import LockIcon from "@material-ui/icons/Lock"; @@ -28,8 +19,7 @@ import ColumnPlusBeforeIcon from "assets/icons/ColumnPlusBefore"; import ColumnPlusAfterIcon from "assets/icons/ColumnPlusAfter"; import ColumnRemoveIcon from "assets/icons/ColumnRemove"; -// Note: this only imports the type -import { Column } from "react-data-grid"; +import { useFiretableContext } from "contexts/firetableContext"; const useStyles = makeStyles(theme => createStyles({ @@ -37,68 +27,29 @@ const useStyles = makeStyles(theme => // TODO: change this if we need to support a dark mode backgroundColor: "#f1f1f3", }, - - subheader: { - ...theme.typography.overline, - color: theme.palette.text.disabled, - padding: theme.spacing(1, 1.25), - paddingTop: theme.spacing(2) + 1, - - cursor: "default", - userSelect: "none", - - "&:focus": { outline: 0 }, - }, - - menuItem: { - minHeight: 42, - padding: theme.spacing(0.75, 1.25), - - ...theme.typography.h6, - fontSize: "0.875rem", - color: theme.palette.text.secondary, - transition: theme.transitions.create(["background-color", "color"], { - duration: theme.transitions.duration.shortest, - }), - - "&:hover": { - backgroundColor: theme.palette.text.primary, - color: "#f1f1f3", - }, - }, - menuItemIcon: { - minWidth: 24, - marginRight: theme.spacing(1.25), - color: "inherit", - }, - - menuItemActive: { color: theme.palette.text.primary }, - menuItemError: { - color: theme.palette.error.main, - "&:hover": { - backgroundColor: fade( - theme.palette.error.main, - theme.palette.action.hoverOpacity - ), - }, - }, }) ); -export interface IColumnMenuProps { - anchorEl: MenuProps["anchorEl"]; - handleClose: MenuProps["onClose"]; - column: Column & { [key: string]: any }; -} - -// TODO: implement active states and actions -const ColumnMenu: React.FC = ({ - anchorEl, - handleClose, - column, -}) => { +export default function ColumnMenu() { const classes = useStyles(); + const { + tableState, + tableActions, + selectedColumnHeader, + setSelectedColumnHeader, + } = useFiretableContext(); + const actions = tableActions!.column; + const { column, anchorEl } = selectedColumnHeader ?? {}; + + const handleClose = () => { + if (!setSelectedColumnHeader) return; + setSelectedColumnHeader({ column: column!, anchorEl: null }); + setTimeout(() => setSelectedColumnHeader(null), 300); + }; + + if (!column) return null; + const menuItems = [ { type: "subheader", label: "View" }, { @@ -177,7 +128,7 @@ const ColumnMenu: React.FC = ({ label: "Delete Column", icon: , onClick: () => alert("DELETE COLUMN"), - color: "error", + color: "error" as "error", }, ]; @@ -194,47 +145,7 @@ const ColumnMenu: React.FC = ({ classes={{ paper: classes.paper }} MenuListProps={{ disablePadding: true }} > - {menuItems.map((item, index) => { - if (item.type === "subheader") - return ( - <> - {index !== 0 && } - - {item.label} - - - ); - - let icon = item.icon ?? <>; - if (item.active && !!item.activeIcon) icon = item.activeIcon; - - return ( - <> - {index !== 0 && } - - - {icon} - - {item.active ? item.activeLabel : item.label} - - - ); - })} + ); -}; - -export default ColumnMenu; +} diff --git a/www/src/components/Table/index.tsx b/www/src/components/Table/index.tsx index 5614d1c8..ca1cdee5 100644 --- a/www/src/components/Table/index.tsx +++ b/www/src/components/Table/index.tsx @@ -18,6 +18,7 @@ import Loading from "components/Loading"; import SubTableBreadcrumbs, { BREADCRUMBS_HEIGHT } from "./SubTableBreadcrumbs"; import TableHeader, { TABLE_HEADER_HEIGHT } from "./TableHeader"; import ColumnHeader from "./ColumnHeader"; +import ColumnMenu from "./ColumnMenu"; import FinalColumnHeader from "./FinalColumnHeader"; import FinalColumn, { useFinalColumnStyles } from "./formatters/FinalColumn"; @@ -29,14 +30,11 @@ import { getFormatter } from "./formatters"; import { getEditor } from "./editors"; import useWindowSize from "hooks/useWindowSize"; -import { DRAWER_WIDTH, DRAWER_COLLAPSED_WIDTH } from "components/SideDrawer"; +import { DRAWER_COLLAPSED_WIDTH } from "components/SideDrawer"; import { APP_BAR_HEIGHT } from "components/Navigation"; import useStyles from "./styles"; // const Hotkeys = lazy(() => import("./HotKeys" /* webpackChunkName: "HotKeys" */)); -const ColumnMenu = lazy(() => - import("./ColumnMenu" /* webpackChunkName: "ColumnMenu" */) -); const { DraggableContainer } = DraggableHeader; export type FiretableColumn = Column & { @@ -222,15 +220,7 @@ export default function Table({ collection, filters }: ITableProps) { )} - }> - {header && header.column && ( - - )} - + ); } From dc0a147b1fe49c676b196bf07c938c96522643cb Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Fri, 20 Mar 2020 17:10:02 +0800 Subject: [PATCH 07/46] functional lock, hide,freeze sort and resize toglz --- www/src/components/Table/ColumnMenu/index.tsx | 44 +++++++++++++------ www/src/hooks/useFiretable/useTableConfig.ts | 9 ++-- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/www/src/components/Table/ColumnMenu/index.tsx b/www/src/components/Table/ColumnMenu/index.tsx index f2bd7ec8..b9e605ba 100644 --- a/www/src/components/Table/ColumnMenu/index.tsx +++ b/www/src/components/Table/ColumnMenu/index.tsx @@ -39,6 +39,9 @@ export default function ColumnMenu() { selectedColumnHeader, setSelectedColumnHeader, } = useFiretableContext(); + if (!tableState || !tableActions) return null; + const { orderBy } = tableState; + const actions = tableActions!.column; const { column, anchorEl } = selectedColumnHeader ?? {}; @@ -49,53 +52,66 @@ export default function ColumnMenu() { }; if (!column) return null; - + const isSorted = orderBy?.[0]?.key === (column.key as string); + const isAsc = isSorted && orderBy?.[0]?.direction === "asc"; const menuItems = [ - { type: "subheader", label: "View" }, + { type: "subheader", label: column.key as string }, { label: "Lock", - activeLabel: "Locked", + activeLabel: "Locked (unlock)", icon: , activeIcon: , - onClick: () => alert("LOCK"), - active: column.locked, + onClick: () => { + actions.update(column.key, { editable: !column.editable }); + }, + active: column.editable, }, { label: "Hide", activeLabel: "Show", icon: , activeIcon: , - onClick: () => alert("HIDE/SHOW"), - active: false, + onClick: () => { + actions.update(column.key, { hidden: !column.hidden }); + }, + active: column.hidden, }, { label: "Freeze", activeLabel: "Unfreeze", icon: , activeIcon: , - onClick: () => alert("FREEZE"), - active: false, + onClick: () => { + actions.update(column.key, { fixed: !column.fixed }); + }, + active: column.fixed, }, { label: "Enable resize", activeLabel: "Disable resize", icon: , - onClick: () => alert("RESIZE"), + onClick: () => { + actions.update(column.key, { resizable: !column.resizable }); + }, active: column.resizable, }, { label: "Sort: Decreasing", activeLabel: "Sorted: Decreasing", icon: , - onClick: () => alert("SORT DECREASING"), - active: false, + onClick: () => { + tableActions.table.orderBy([{ key: column.key, direction: "desc" }]); + }, + active: isSorted && !isAsc, }, { label: "Sort: Increasing", activeLabel: "Sorted: Increasing", icon: , - onClick: () => alert("SORT INCREASING"), - active: false, + onClick: () => { + tableActions.table.orderBy([{ key: column.key, direction: "asc" }]); + }, + active: isSorted && isAsc, }, { type: "subheader", label: "Edit" }, { diff --git a/www/src/hooks/useFiretable/useTableConfig.ts b/www/src/hooks/useFiretable/useTableConfig.ts index 08ce0612..fdb1941c 100644 --- a/www/src/hooks/useFiretable/useTableConfig.ts +++ b/www/src/hooks/useFiretable/useTableConfig.ts @@ -73,17 +73,14 @@ const useTableConfig = (tablePath?: string) => { * @param index of column. * @param {updatable[]} updatables properties to be updated */ - const updateColumn = (key: string, updatables: updatable[]) => { + const updateColumn = (key: string, updates: any) => { const { columns } = tableConfigState; - const columnUpdates = updatables.reduce((acc, curr) => { - return { ...acc, [curr.field]: curr.value }; - }, {}); const updatedColumns = { ...columns, - [key]: { ...columns[key], ...columnUpdates }, + [key]: { ...columns[key], ...updates }, }; - console.log({ key, updatedColumns, columnUpdates }); + documentDispatch({ action: DocActions.update, data: { columns: updatedColumns }, From d4c9fcbdacd0666b0037c85100bf407be7a9dd28 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Fri, 20 Mar 2020 17:26:02 +0800 Subject: [PATCH 08/46] delete columns and auto close menu --- www/src/components/Table/ColumnMenu/index.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/www/src/components/Table/ColumnMenu/index.tsx b/www/src/components/Table/ColumnMenu/index.tsx index b9e605ba..e5377d62 100644 --- a/www/src/components/Table/ColumnMenu/index.tsx +++ b/www/src/components/Table/ColumnMenu/index.tsx @@ -63,6 +63,7 @@ export default function ColumnMenu() { activeIcon: , onClick: () => { actions.update(column.key, { editable: !column.editable }); + handleClose(); }, active: column.editable, }, @@ -73,6 +74,7 @@ export default function ColumnMenu() { activeIcon: , onClick: () => { actions.update(column.key, { hidden: !column.hidden }); + handleClose(); }, active: column.hidden, }, @@ -83,6 +85,7 @@ export default function ColumnMenu() { activeIcon: , onClick: () => { actions.update(column.key, { fixed: !column.fixed }); + handleClose(); }, active: column.fixed, }, @@ -92,6 +95,7 @@ export default function ColumnMenu() { icon: , onClick: () => { actions.update(column.key, { resizable: !column.resizable }); + handleClose(); }, active: column.resizable, }, @@ -101,6 +105,7 @@ export default function ColumnMenu() { icon: , onClick: () => { tableActions.table.orderBy([{ key: column.key, direction: "desc" }]); + handleClose(); }, active: isSorted && !isAsc, }, @@ -110,6 +115,7 @@ export default function ColumnMenu() { icon: , onClick: () => { tableActions.table.orderBy([{ key: column.key, direction: "asc" }]); + handleClose(); }, active: isSorted && isAsc, }, @@ -143,7 +149,10 @@ export default function ColumnMenu() { { label: "Delete Column", icon: , - onClick: () => alert("DELETE COLUMN"), + onClick: () => { + actions.remove(column.key); + handleClose(); + }, color: "error" as "error", }, ]; From a1b6c11c836bf67d72e5f538d8112450a1bbdd4a Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Mon, 23 Mar 2020 10:48:04 +0800 Subject: [PATCH 09/46] name change --- .../Table/ColumnMenu/NameChange.tsx | 84 +++++++++++++++++++ www/src/components/Table/ColumnMenu/index.tsx | 58 +++++++++---- 2 files changed, 124 insertions(+), 18 deletions(-) create mode 100644 www/src/components/Table/ColumnMenu/NameChange.tsx diff --git a/www/src/components/Table/ColumnMenu/NameChange.tsx b/www/src/components/Table/ColumnMenu/NameChange.tsx new file mode 100644 index 00000000..471c92ca --- /dev/null +++ b/www/src/components/Table/ColumnMenu/NameChange.tsx @@ -0,0 +1,84 @@ +import React, { useState } from "react"; +import Button from "@material-ui/core/Button"; +import TextField from "@material-ui/core/TextField"; +import Dialog from "@material-ui/core/Dialog"; +import Grid from "@material-ui/core/Grid"; +import DialogActions from "@material-ui/core/DialogActions"; +import DialogContent from "@material-ui/core/DialogContent"; +import { Typography, IconButton } from "@material-ui/core"; +import CloseIcon from "@material-ui/icons/Close"; +export default function FormDialog({ + name, + fieldName, + open, + handleClose, + handleSave, +}: { + name: string; + fieldName: string; + open: boolean; + handleClose: Function; + handleSave: Function; +}) { + const [newName, setName] = useState(name); + return ( +
+ { + handleClose(); + }} + aria-labelledby="form-dialog-title" + > + + + Rename Column + { + handleClose(); + }} + > + + + + {name} + { + setName(e.target.value); + }} + /> + + + + + + +
+ ); +} diff --git a/www/src/components/Table/ColumnMenu/index.tsx b/www/src/components/Table/ColumnMenu/index.tsx index e5377d62..e8468582 100644 --- a/www/src/components/Table/ColumnMenu/index.tsx +++ b/www/src/components/Table/ColumnMenu/index.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState } from "react"; import { createStyles, makeStyles, Menu } from "@material-ui/core"; @@ -18,9 +18,12 @@ import ReorderIcon from "@material-ui/icons/Reorder"; import ColumnPlusBeforeIcon from "assets/icons/ColumnPlusBefore"; import ColumnPlusAfterIcon from "assets/icons/ColumnPlusAfter"; import ColumnRemoveIcon from "assets/icons/ColumnRemove"; +import NameChange from "./NameChange"; import { useFiretableContext } from "contexts/firetableContext"; - +enum ModalStates { + nameChange = "NAME_CHANGE", +} const useStyles = makeStyles(theme => createStyles({ paper: { @@ -32,7 +35,7 @@ const useStyles = makeStyles(theme => export default function ColumnMenu() { const classes = useStyles(); - + const [modal, setModal] = useState(""); const { tableState, tableActions, @@ -123,7 +126,9 @@ export default function ColumnMenu() { { label: "Rename", icon: , - onClick: () => alert("EDIT"), + onClick: () => { + setModal(ModalStates.nameChange); + }, }, { label: `Edit Type: ${column?.type}`, @@ -158,19 +163,36 @@ export default function ColumnMenu() { ]; return ( - - - + <> + + + + {column && ( + { + setModal(""); + }} + handleSave={(key, update) => { + actions.update(key, update); + setModal(""); + handleClose(); + }} + /> + )} + ); } From 53e852d5875e69dc8c5c1c5cf275e378c7827588 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Mon, 23 Mar 2020 11:41:01 +0800 Subject: [PATCH 10/46] changing type --- .../Table/ColumnMenu/FieldsDropdown.tsx | 41 +++++++++ .../Table/ColumnMenu/TypeChange.tsx | 85 +++++++++++++++++++ www/src/components/Table/ColumnMenu/index.tsx | 49 ++++++++--- 3 files changed, 161 insertions(+), 14 deletions(-) create mode 100644 www/src/components/Table/ColumnMenu/FieldsDropdown.tsx create mode 100644 www/src/components/Table/ColumnMenu/TypeChange.tsx diff --git a/www/src/components/Table/ColumnMenu/FieldsDropdown.tsx b/www/src/components/Table/ColumnMenu/FieldsDropdown.tsx new file mode 100644 index 00000000..1bf525ca --- /dev/null +++ b/www/src/components/Table/ColumnMenu/FieldsDropdown.tsx @@ -0,0 +1,41 @@ +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 = (props: { value: FieldType | null; onChange: any }) => { + const { value, onChange } = props; + 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/ColumnMenu/TypeChange.tsx b/www/src/components/Table/ColumnMenu/TypeChange.tsx new file mode 100644 index 00000000..a1ffc220 --- /dev/null +++ b/www/src/components/Table/ColumnMenu/TypeChange.tsx @@ -0,0 +1,85 @@ +import React, { useState } from "react"; +import Button from "@material-ui/core/Button"; +import TextField from "@material-ui/core/TextField"; +import Dialog from "@material-ui/core/Dialog"; +import Grid from "@material-ui/core/Grid"; +import DialogActions from "@material-ui/core/DialogActions"; +import DialogContent from "@material-ui/core/DialogContent"; +import { Typography, IconButton } from "@material-ui/core"; +import CloseIcon from "@material-ui/icons/Close"; +import { FieldType } from "constants/fields"; +import FieldsDropdown from "./FieldsDropdown"; + +export default function FormDialog({ + name, + fieldName, + type, + open, + handleClose, + handleSave, +}: { + name: string; + fieldName: string; + type: FieldType; + open: boolean; + handleClose: Function; + handleSave: Function; +}) { + const [newType, setType] = useState(type); + return ( +
+ { + handleClose(); + }} + aria-labelledby="form-dialog-title" + > + + + Rename Column + { + handleClose(); + }} + > + + + + {name} + + { + console.log(newType.target.value); + setType(newType.target.value); + }} + /> + + + + + + +
+ ); +} diff --git a/www/src/components/Table/ColumnMenu/index.tsx b/www/src/components/Table/ColumnMenu/index.tsx index e8468582..9a46d4cb 100644 --- a/www/src/components/Table/ColumnMenu/index.tsx +++ b/www/src/components/Table/ColumnMenu/index.tsx @@ -19,10 +19,12 @@ import ColumnPlusBeforeIcon from "assets/icons/ColumnPlusBefore"; import ColumnPlusAfterIcon from "assets/icons/ColumnPlusAfter"; import ColumnRemoveIcon from "assets/icons/ColumnRemove"; import NameChange from "./NameChange"; +import TypeChange from "./TypeChange"; import { useFiretableContext } from "contexts/firetableContext"; enum ModalStates { nameChange = "NAME_CHANGE", + typeChange = "TYPE_CHANGE", } const useStyles = makeStyles(theme => createStyles({ @@ -134,7 +136,9 @@ export default function ColumnMenu() { label: `Edit Type: ${column?.type}`, // TODO: This is based off the cell type // icon: , - onClick: () => alert("EDIT TYPE"), + onClick: () => { + setModal(ModalStates.typeChange); + }, }, { label: "Re-order", @@ -179,19 +183,36 @@ export default function ColumnMenu() { {column && ( - { - setModal(""); - }} - handleSave={(key, update) => { - actions.update(key, update); - setModal(""); - handleClose(); - }} - /> + <> + { + setModal(""); + }} + handleSave={(key, update) => { + actions.update(key, update); + setModal(""); + handleClose(); + }} + /> + + { + setModal(""); + }} + handleSave={(key, update) => { + actions.update(key, update); + setModal(""); + handleClose(); + }} + /> + )} ); From 515570ff3f0e99857ed6551205263e66362c37eb Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Mon, 23 Mar 2020 18:21:16 +0800 Subject: [PATCH 11/46] functional resizing --- www/src/hooks/useFiretable/useTableConfig.ts | 40 +++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/www/src/hooks/useFiretable/useTableConfig.ts b/www/src/hooks/useFiretable/useTableConfig.ts index fdb1941c..691a3d5c 100644 --- a/www/src/hooks/useFiretable/useTableConfig.ts +++ b/www/src/hooks/useFiretable/useTableConfig.ts @@ -4,6 +4,8 @@ import useDoc, { DocActions } from "../useDoc"; import { FieldType } from "constants/fields"; import _camelCase from "lodash/camelCase"; import _findIndex from "lodash/findIndex"; +import _find from "lodash/find"; +import _sortBy from "lodash/sortBy"; import { arrayMover } from "../../util/fns"; import { db, deleteField } from "../../firebase"; @@ -64,8 +66,23 @@ const useTableConfig = (tablePath?: string) => { */ const [resize] = useDebouncedCallback((index: number, width: number) => { const { columns } = tableConfigState; - columns[index].width = width; - documentDispatch({ action: DocActions.update, data: { columns } }); + const numberOfFixedColumns = Object.values(columns).filter( + (col: any) => col.fixed && !col.hidden + ).length; + const columnsArray = _sortBy( + Object.values(columns).filter((col: any) => !col.hidden && !col.fixed), + "index" + ); + let column: any = columnsArray[index - numberOfFixedColumns]; + column.width = width; + let updatedColumns = columns; + updatedColumns[column.key] = column; + + console.log({ index, column, updatedColumns }); + documentDispatch({ + action: DocActions.update, + data: { columns: updatedColumns }, + }); }, 1000); type updatable = { field: string; value: unknown }; @@ -104,15 +121,18 @@ const useTableConfig = (tablePath?: string) => { * @param droppedColumnKey column being . */ const reorder = (draggedColumnKey: string, droppedColumnKey: string) => { + console.log(draggedColumnKey, droppedColumnKey); + const { columns } = tableConfigState; - const draggedColumnIndex = _findIndex(columns, ["key", draggedColumnKey]); - const droppedColumnIndex = _findIndex(columns, ["key", droppedColumnKey]); - const reorderedColumns = [...columns]; - arrayMover(reorderedColumns, draggedColumnIndex, droppedColumnIndex); - documentDispatch({ - action: DocActions.update, - data: { columns: reorderedColumns }, - }); + console.log(columns[draggedColumnKey], columns[droppedColumnKey]); + // const draggedColumnIndex = _findIndex(columns, ["key", draggedColumnKey]); + // const droppedColumnIndex = _findIndex(columns, ["key", droppedColumnKey]); + // const reorderedColumns = [...columns]; + // arrayMover(reorderedColumns, draggedColumnIndex, droppedColumnIndex); + // documentDispatch({ + // action: DocActions.update, + // data: { columns: reorderedColumns }, + // }); }; /** changing table configuration used for things such as row height * @param key name of parameter eg. rowHeight From b152016bcb96d175b02c6e0842b7f8cee6e4e5ec Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Mon, 23 Mar 2020 18:39:45 +0800 Subject: [PATCH 12/46] dragNdrop column repostion --- www/src/hooks/useFiretable/useTableConfig.ts | 25 ++++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/www/src/hooks/useFiretable/useTableConfig.ts b/www/src/hooks/useFiretable/useTableConfig.ts index 691a3d5c..ba4f7828 100644 --- a/www/src/hooks/useFiretable/useTableConfig.ts +++ b/www/src/hooks/useFiretable/useTableConfig.ts @@ -77,8 +77,6 @@ const useTableConfig = (tablePath?: string) => { column.width = width; let updatedColumns = columns; updatedColumns[column.key] = column; - - console.log({ index, column, updatedColumns }); documentDispatch({ action: DocActions.update, data: { columns: updatedColumns }, @@ -110,7 +108,6 @@ const useTableConfig = (tablePath?: string) => { const { columns } = tableConfigState; let updatedColumns = columns; updatedColumns[key] = deleteField(); - console.log({ updatedColumns }); documentDispatch({ action: DocActions.update, data: { columns: updatedColumns }, @@ -121,18 +118,20 @@ const useTableConfig = (tablePath?: string) => { * @param droppedColumnKey column being . */ const reorder = (draggedColumnKey: string, droppedColumnKey: string) => { - console.log(draggedColumnKey, droppedColumnKey); - const { columns } = tableConfigState; console.log(columns[draggedColumnKey], columns[droppedColumnKey]); - // const draggedColumnIndex = _findIndex(columns, ["key", draggedColumnKey]); - // const droppedColumnIndex = _findIndex(columns, ["key", droppedColumnKey]); - // const reorderedColumns = [...columns]; - // arrayMover(reorderedColumns, draggedColumnIndex, droppedColumnIndex); - // documentDispatch({ - // action: DocActions.update, - // data: { columns: reorderedColumns }, - // }); + const oldIndex = columns[draggedColumnKey].index; + const newIndex = columns[droppedColumnKey].index; + const columnsArray = _sortBy(Object.values(columns), "index"); + arrayMover(columnsArray, oldIndex, newIndex); + let updatedColumns = columns; + columnsArray.forEach((column: any, index) => { + updatedColumns[column.key] = { ...column, index }; + }); + documentDispatch({ + action: DocActions.update, + data: { columns: updatedColumns }, + }); }; /** changing table configuration used for things such as row height * @param key name of parameter eg. rowHeight From 31979ab154de9fc30f0f24e86b5aa5d362bb24d5 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Mon, 23 Mar 2020 19:31:20 +0800 Subject: [PATCH 13/46] add new columns --- .../components/Table/ColumnMenu/NewColumn.tsx | 102 ++++++++++++++++++ .../Table/ColumnMenu/TypeChange.tsx | 5 +- www/src/components/Table/ColumnMenu/index.tsx | 52 ++++++--- 3 files changed, 143 insertions(+), 16 deletions(-) create mode 100644 www/src/components/Table/ColumnMenu/NewColumn.tsx diff --git a/www/src/components/Table/ColumnMenu/NewColumn.tsx b/www/src/components/Table/ColumnMenu/NewColumn.tsx new file mode 100644 index 00000000..15dc3a07 --- /dev/null +++ b/www/src/components/Table/ColumnMenu/NewColumn.tsx @@ -0,0 +1,102 @@ +import React, { useState } from "react"; +import Button from "@material-ui/core/Button"; +import TextField from "@material-ui/core/TextField"; +import Dialog from "@material-ui/core/Dialog"; +import Grid from "@material-ui/core/Grid"; +import DialogActions from "@material-ui/core/DialogActions"; +import DialogContent from "@material-ui/core/DialogContent"; +import { Typography, IconButton } from "@material-ui/core"; +import CloseIcon from "@material-ui/icons/Close"; +import { FieldType } from "constants/fields"; +import FieldsDropdown from "./FieldsDropdown"; +import _camel from "lodash/camelCase"; + +export default function FormDialog({ + open, + data, + handleClose, + handleSave, +}: { + open: boolean; + data: any; + handleClose: Function; + handleSave: Function; +}) { + const [type, setType] = useState(FieldType.shortText); + const [name, setName] = useState(""); + return ( +
+ { + handleClose(); + }} + aria-labelledby="new-column" + > + + + Add new column + { + handleClose(); + }} + > + + + + Column Name + { + setName(e.target.value); + }} + /> + Column Type + + { + setType(newType.target.value); + }} + /> + + + + + + +
+ ); +} diff --git a/www/src/components/Table/ColumnMenu/TypeChange.tsx b/www/src/components/Table/ColumnMenu/TypeChange.tsx index a1ffc220..98fd8247 100644 --- a/www/src/components/Table/ColumnMenu/TypeChange.tsx +++ b/www/src/components/Table/ColumnMenu/TypeChange.tsx @@ -42,7 +42,7 @@ export default function FormDialog({ alignContent="flex-start" direction="row" > - Rename Column + Change Column Type { handleClose(); @@ -51,12 +51,11 @@ export default function FormDialog({ - {name} + Current Column: {name} { - console.log(newType.target.value); setType(newType.target.value); }} /> diff --git a/www/src/components/Table/ColumnMenu/index.tsx b/www/src/components/Table/ColumnMenu/index.tsx index 9a46d4cb..1fb344fa 100644 --- a/www/src/components/Table/ColumnMenu/index.tsx +++ b/www/src/components/Table/ColumnMenu/index.tsx @@ -19,12 +19,18 @@ import ColumnPlusBeforeIcon from "assets/icons/ColumnPlusBefore"; import ColumnPlusAfterIcon from "assets/icons/ColumnPlusAfter"; import ColumnRemoveIcon from "assets/icons/ColumnRemove"; import NameChange from "./NameChange"; +import NewColumn from "./NewColumn"; import TypeChange from "./TypeChange"; - import { useFiretableContext } from "contexts/firetableContext"; +import { FIELDS } from "constants/fields"; +import _find from "lodash/find"; + +const INITIAL_MODAL = { type: "", data: {} }; + enum ModalStates { nameChange = "NAME_CHANGE", typeChange = "TYPE_CHANGE", + new = "NEW_COLUMN", } const useStyles = makeStyles(theme => createStyles({ @@ -37,7 +43,7 @@ const useStyles = makeStyles(theme => export default function ColumnMenu() { const classes = useStyles(); - const [modal, setModal] = useState(""); + const [modal, setModal] = useState(INITIAL_MODAL); const { tableState, tableActions, @@ -129,15 +135,15 @@ export default function ColumnMenu() { label: "Rename", icon: , onClick: () => { - setModal(ModalStates.nameChange); + setModal({ type: ModalStates.nameChange, data: {} }); }, }, { label: `Edit Type: ${column?.type}`, // TODO: This is based off the cell type - // icon: , + icon: _find(FIELDS, { type: column.type })?.icon, onClick: () => { - setModal(ModalStates.typeChange); + setModal({ type: ModalStates.typeChange, data: {} }); }, }, { @@ -148,12 +154,20 @@ export default function ColumnMenu() { { label: "Add New to Left", icon: , - onClick: () => alert("ADD NEW LEFT"), + onClick: () => + setModal({ + type: ModalStates.new, + data: { initializeColumn: { index: column.index - 1 } }, + }), }, { label: "Add New to Right", icon: , - onClick: () => alert("ADD NEW RIGHT"), + onClick: () => + setModal({ + type: ModalStates.new, + data: { initializeColumn: { index: column.index + 1 } }, + }), }, { label: "Delete Column", @@ -187,13 +201,13 @@ export default function ColumnMenu() { { - setModal(""); + setModal(INITIAL_MODAL); }} handleSave={(key, update) => { actions.update(key, update); - setModal(""); + setModal(INITIAL_MODAL); handleClose(); }} /> @@ -201,14 +215,26 @@ export default function ColumnMenu() { { - setModal(""); + setModal(INITIAL_MODAL); }} handleSave={(key, update) => { actions.update(key, update); - setModal(""); + setModal(INITIAL_MODAL); + handleClose(); + }} + /> + { + setModal(INITIAL_MODAL); + }} + handleSave={(key, update) => { + actions.update(key, update); + setModal(INITIAL_MODAL); handleClose(); }} /> From 430e338767cd6dcc07cf7b5737e52f4bb5482d04 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Mon, 23 Mar 2020 19:49:32 +0800 Subject: [PATCH 14/46] clean up --- www/src/components/Table/ColumnMenu/index.tsx | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/www/src/components/Table/ColumnMenu/index.tsx b/www/src/components/Table/ColumnMenu/index.tsx index 1fb344fa..e8b98fe3 100644 --- a/www/src/components/Table/ColumnMenu/index.tsx +++ b/www/src/components/Table/ColumnMenu/index.tsx @@ -66,7 +66,13 @@ export default function ColumnMenu() { const isSorted = orderBy?.[0]?.key === (column.key as string); const isAsc = isSorted && orderBy?.[0]?.direction === "asc"; const menuItems = [ - { type: "subheader", label: column.key as string }, + { + type: "subheader", + label: + column.name === column?.key + ? column.name + : (`${column.name}(${column?.key as string})` as string), + }, { label: "Lock", activeLabel: "Locked (unlock)", @@ -76,7 +82,7 @@ export default function ColumnMenu() { actions.update(column.key, { editable: !column.editable }); handleClose(); }, - active: column.editable, + active: !column.editable, }, { label: "Hide", @@ -146,11 +152,11 @@ export default function ColumnMenu() { setModal({ type: ModalStates.typeChange, data: {} }); }, }, - { - label: "Re-order", - icon: , - onClick: () => alert("REORDER"), - }, + // { + // label: "Re-order", + // icon: , + // onClick: () => alert("REORDER"), + // }, { label: "Add New to Left", icon: , @@ -180,6 +186,9 @@ export default function ColumnMenu() { }, ]; + const clearModal = () => { + setModal(INITIAL_MODAL); + }; return ( <> { - setModal(INITIAL_MODAL); - }} + handleClose={clearModal} handleSave={(key, update) => { actions.update(key, update); - setModal(INITIAL_MODAL); + clearModal(); handleClose(); }} /> @@ -217,24 +224,20 @@ export default function ColumnMenu() { fieldName={column.key as string} open={modal.type === ModalStates.typeChange} type={column.type} - handleClose={() => { - setModal(INITIAL_MODAL); - }} + handleClose={clearModal} handleSave={(key, update) => { actions.update(key, update); - setModal(INITIAL_MODAL); + clearModal(); handleClose(); }} /> { - setModal(INITIAL_MODAL); - }} + handleClose={clearModal} handleSave={(key, update) => { actions.update(key, update); - setModal(INITIAL_MODAL); + clearModal(); handleClose(); }} /> From e33dbc65fae85cc508059f242b05f2da4039a261 Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Fri, 17 Apr 2020 10:51:39 +1000 Subject: [PATCH 15/46] move ColumnMenu state to internal, provide ref --- .../components/Table/ColumnEditor/index.tsx | 3 +- www/src/components/Table/ColumnHeader.tsx | 10 ++++-- www/src/components/Table/ColumnMenu/index.tsx | 32 +++++++++++++------ .../components/Table/FinalColumnHeader.tsx | 10 ++++-- www/src/contexts/firetableContext.tsx | 22 +++---------- 5 files changed, 44 insertions(+), 33 deletions(-) diff --git a/www/src/components/Table/ColumnEditor/index.tsx b/www/src/components/Table/ColumnEditor/index.tsx index d30ecb5f..1fbd94c0 100644 --- a/www/src/components/Table/ColumnEditor/index.tsx +++ b/www/src/components/Table/ColumnEditor/index.tsx @@ -65,13 +65,14 @@ const useStyles = makeStyles(theme => }) ); +// TODO: REMOVE THIS OLD COMPONENT export default function ColumnEditor() { const { tableState, tableActions, selectedColumnHeader, setSelectedColumnHeader, - } = useFiretableContext(); + } = useFiretableContext() as any; const actions = tableActions!.column; const { column, anchorEl } = selectedColumnHeader ?? {}; diff --git a/www/src/components/Table/ColumnHeader.tsx b/www/src/components/Table/ColumnHeader.tsx index 3bbdbb16..61f38e9c 100644 --- a/www/src/components/Table/ColumnHeader.tsx +++ b/www/src/components/Table/ColumnHeader.tsx @@ -90,17 +90,21 @@ const ColumnHeader: Column["headerRenderer"] = ({ column }) => { const classes = useStyles(); const { - setSelectedColumnHeader, tableState, tableActions, userClaims, + columnMenuRef, } = useFiretableContext(); - if (!setSelectedColumnHeader || !tableState || !tableActions) return null; + if (!columnMenuRef || !tableState || !tableActions) return null; const { orderBy } = tableState; const handleClick = ( event: React.MouseEvent - ) => setSelectedColumnHeader({ column, anchorEl: event.currentTarget }); + ) => + columnMenuRef?.current?.setSelectedColumnHeader({ + column, + anchorEl: event.currentTarget, + }); const isSorted = orderBy?.[0]?.key === (column.key as string); const isAsc = isSorted && orderBy?.[0]?.direction === "asc"; diff --git a/www/src/components/Table/ColumnMenu/index.tsx b/www/src/components/Table/ColumnMenu/index.tsx index e8b98fe3..f49c73e4 100644 --- a/www/src/components/Table/ColumnMenu/index.tsx +++ b/www/src/components/Table/ColumnMenu/index.tsx @@ -1,9 +1,6 @@ import React, { useState } from "react"; import { createStyles, makeStyles, Menu } from "@material-ui/core"; - -import MenuContents from "./MenuContents"; - import LockOpenIcon from "@material-ui/icons/LockOpen"; import LockIcon from "@material-ui/icons/Lock"; import VisibilityOffIcon from "@material-ui/icons/VisibilityOff"; @@ -18,12 +15,17 @@ import ReorderIcon from "@material-ui/icons/Reorder"; import ColumnPlusBeforeIcon from "assets/icons/ColumnPlusBefore"; import ColumnPlusAfterIcon from "assets/icons/ColumnPlusAfter"; import ColumnRemoveIcon from "assets/icons/ColumnRemove"; + +import MenuContents from "./MenuContents"; import NameChange from "./NameChange"; import NewColumn from "./NewColumn"; import TypeChange from "./TypeChange"; + import { useFiretableContext } from "contexts/firetableContext"; import { FIELDS } from "constants/fields"; import _find from "lodash/find"; +import { Column } from "react-data-grid"; +import { PopoverProps } from "@material-ui/core"; const INITIAL_MODAL = { type: "", data: {} }; @@ -32,6 +34,18 @@ enum ModalStates { typeChange = "TYPE_CHANGE", new = "NEW_COLUMN", } + +type SelectedColumnHeader = { + column: Column & { [key: string]: any }; + anchorEl: PopoverProps["anchorEl"]; +}; +export type ColumnMenuRef = { + selectedColumnHeader: SelectedColumnHeader | null; + setSelectedColumnHeader: React.Dispatch< + React.SetStateAction + >; +}; + const useStyles = makeStyles(theme => createStyles({ paper: { @@ -44,12 +58,12 @@ const useStyles = makeStyles(theme => export default function ColumnMenu() { const classes = useStyles(); const [modal, setModal] = useState(INITIAL_MODAL); - const { - tableState, - tableActions, - selectedColumnHeader, - setSelectedColumnHeader, - } = useFiretableContext(); + const { tableState, tableActions, columnMenuRef } = useFiretableContext(); + + const [selectedColumnHeader, setSelectedColumnHeader] = useState(); + if (columnMenuRef) + columnMenuRef.current = { selectedColumnHeader, setSelectedColumnHeader }; + if (!tableState || !tableActions) return null; const { orderBy } = tableState; diff --git a/www/src/components/Table/FinalColumnHeader.tsx b/www/src/components/Table/FinalColumnHeader.tsx index ffdfdf1d..56aa64af 100644 --- a/www/src/components/Table/FinalColumnHeader.tsx +++ b/www/src/components/Table/FinalColumnHeader.tsx @@ -39,12 +39,16 @@ const useStyles = makeStyles(theme => const FinalColumnHeader: Column["headerRenderer"] = ({ column }) => { const classes = useStyles(); - const { setSelectedColumnHeader } = useFiretableContext(); - if (!setSelectedColumnHeader) return null; + const { columnMenuRef } = useFiretableContext(); + if (!columnMenuRef) return null; const handleClick = ( event: React.MouseEvent - ) => setSelectedColumnHeader({ column, anchorEl: event.currentTarget }); + ) => + columnMenuRef?.current?.setSelectedColumnHeader({ + column, + anchorEl: event.currentTarget, + }); return ( & { [key: string]: any }; - anchorEl: PopoverProps["anchorEl"]; -}; +import { ColumnMenuRef } from "components/Table/ColumnMenu"; export type Table = { collection: string; @@ -40,16 +36,12 @@ interface FiretableContextProps { createTable: Function; userClaims: any; - // TODO: Investigate if this can be moved out of this context - selectedColumnHeader: SelectedColumnHeader | null; - setSelectedColumnHeader: React.Dispatch< - React.SetStateAction - >; - // A ref to the data grid. Contains data grid functions dataGridRef: React.RefObject; // A ref to the side drawer state. Prevents unnecessary re-renders sideDrawerRef: React.MutableRefObject; + // A ref to the column menu. Prevents unnecessary re-renders + columnMenuRef: React.MutableRefObject; } const firetableContext = React.createContext>( @@ -67,10 +59,6 @@ export const FiretableContextProvider: React.FC = ({ children }) => { const [settings, createTable] = useSettings(); const [userRoles, setUserRoles] = useState(); const [userClaims, setUserClaims] = useState(); - const [ - selectedColumnHeader, - setSelectedColumnHeader, - ] = useState(null); const { currentUser } = useAppContext(); useEffect(() => { @@ -135,6 +123,7 @@ export const FiretableContextProvider: React.FC = ({ children }) => { // A ref to the data grid. Contains data grid functions const dataGridRef = useRef(null); const sideDrawerRef = useRef(); + const columnMenuRef = useRef(); return ( { tables, sections, userClaims, - selectedColumnHeader, - setSelectedColumnHeader, dataGridRef, sideDrawerRef, + columnMenuRef, }} > {children} From 34274953a6b18077cb74d55a3decdfee33cfdf69 Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Fri, 17 Apr 2020 10:58:35 +1000 Subject: [PATCH 16/46] ColumnMenu style fixes --- www/src/components/Table/ColumnMenu/MenuContents.tsx | 7 ++----- www/src/components/Table/ColumnMenu/index.tsx | 5 +---- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/www/src/components/Table/ColumnMenu/MenuContents.tsx b/www/src/components/Table/ColumnMenu/MenuContents.tsx index ebac8834..fe26d5c5 100644 --- a/www/src/components/Table/ColumnMenu/MenuContents.tsx +++ b/www/src/components/Table/ColumnMenu/MenuContents.tsx @@ -51,10 +51,8 @@ const useStyles = makeStyles(theme => menuItemError: { color: theme.palette.error.main, "&:hover": { - backgroundColor: fade( - theme.palette.error.main, - theme.palette.action.hoverOpacity - ), + backgroundColor: theme.palette.error.main, + color: theme.palette.error.contrastText, }, }, }) @@ -73,7 +71,6 @@ export interface IMenuContentsProps { }[]; } -// TODO: implement active states and actions export default function MenuContents({ menuItems }: IMenuContentsProps) { const classes = useStyles(); diff --git a/www/src/components/Table/ColumnMenu/index.tsx b/www/src/components/Table/ColumnMenu/index.tsx index f49c73e4..631ccaba 100644 --- a/www/src/components/Table/ColumnMenu/index.tsx +++ b/www/src/components/Table/ColumnMenu/index.tsx @@ -82,10 +82,7 @@ export default function ColumnMenu() { const menuItems = [ { type: "subheader", - label: - column.name === column?.key - ? column.name - : (`${column.name}(${column?.key as string})` as string), + label: column.name, }, { label: "Lock", From cd7f78fa18541fb9598ddf4b006dde6c94793ba5 Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Fri, 17 Apr 2020 11:01:04 +1000 Subject: [PATCH 17/46] ColumnMenu: enable unsort --- www/src/components/Table/ColumnMenu/index.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/www/src/components/Table/ColumnMenu/index.tsx b/www/src/components/Table/ColumnMenu/index.tsx index 631ccaba..07e6395b 100644 --- a/www/src/components/Table/ColumnMenu/index.tsx +++ b/www/src/components/Table/ColumnMenu/index.tsx @@ -132,7 +132,9 @@ export default function ColumnMenu() { activeLabel: "Sorted: Decreasing", icon: , onClick: () => { - tableActions.table.orderBy([{ key: column.key, direction: "desc" }]); + tableActions.table.orderBy( + isSorted && !isAsc ? [] : [{ key: column.key, direction: "desc" }] + ); handleClose(); }, active: isSorted && !isAsc, @@ -142,7 +144,9 @@ export default function ColumnMenu() { activeLabel: "Sorted: Increasing", icon: , onClick: () => { - tableActions.table.orderBy([{ key: column.key, direction: "asc" }]); + tableActions.table.orderBy( + isSorted && isAsc ? [] : [{ key: column.key, direction: "asc" }] + ); handleClose(); }, active: isSorted && isAsc, From 85f55656aaae2d8ba0446417b0c280a4ae5803e7 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Wed, 1 Jul 2020 16:30:27 +0800 Subject: [PATCH 18/46] fix: side drawer and exportCSV to support new column structure --- .../components/SideDrawer/Form/Autosave.tsx | 10 ++- www/src/components/SideDrawer/index.tsx | 84 ++++++++++--------- www/src/components/Table/ColumnMenu/index.tsx | 22 +++-- www/src/components/Table/ExportCSV.tsx | 11 ++- www/src/components/Table/index.tsx | 2 - 5 files changed, 74 insertions(+), 55 deletions(-) diff --git a/www/src/components/SideDrawer/Form/Autosave.tsx b/www/src/components/SideDrawer/Form/Autosave.tsx index cb538120..49597eb1 100644 --- a/www/src/components/SideDrawer/Form/Autosave.tsx +++ b/www/src/components/SideDrawer/Form/Autosave.tsx @@ -21,7 +21,15 @@ export default function Autosave({ values, errors }: IAutosaveProps) { const { tableState, sideDrawerRef } = useFiretableContext(); const getEditables = value => - _pick(value, tableState?.columns?.map(c => c.key) ?? []); + _pick( + value, + (tableState && + (Array.isArray(tableState?.columns) + ? tableState?.columns + : Object.values(tableState?.columns) + ).map(c => c.key)) ?? + [] + ); const [debouncedValue] = useDebounce(getEditables(values), 1000, { equalityFn: _isEqual, diff --git a/www/src/components/SideDrawer/index.tsx b/www/src/components/SideDrawer/index.tsx index d5f0dd09..cd4a7b25 100644 --- a/www/src/components/SideDrawer/index.tsx +++ b/www/src/components/SideDrawer/index.tsx @@ -54,55 +54,59 @@ export default function SideDrawer() { // Map columns to form fields - const fields = tableState?.columns?.map(column => { - const field: Field = { - type: column.type, - name: column.key, - label: column.name, - }; + const fields = + tableState?.columns && + (Array.isArray(tableState?.columns) + ? tableState?.columns + : Object.values(tableState?.columns) + ).map(column => { + const field: Field = { + type: column.type, + name: column.key, + label: column.name, + }; - switch (column.type) { - case FieldType.longText: - field.fieldVariant = "long"; - break; + switch (column.type) { + case FieldType.longText: + field.fieldVariant = "long"; + break; - case FieldType.email: - field.fieldVariant = "email"; - break; + case FieldType.email: + field.fieldVariant = "email"; + break; - case FieldType.phone: - field.fieldVariant = "phone"; - break; + case FieldType.phone: + field.fieldVariant = "phone"; + break; - case FieldType.number: - field.fieldVariant = "number"; - break; + case FieldType.number: + field.fieldVariant = "number"; + break; - case FieldType.singleSelect: - case FieldType.multiSelect: - field.options = column.options; - break; + case FieldType.singleSelect: + case FieldType.multiSelect: + field.options = column.options; + break; - case FieldType.connectTable: - field.collectionPath = column.collectionPath; - field.config = column.config; - break; + case FieldType.connectTable: + field.collectionPath = column.collectionPath; + field.config = column.config; + break; - case FieldType.subTable: - field.parentLabel = column.parentLabel; - break; + case FieldType.subTable: + field.parentLabel = column.parentLabel; + break; - case FieldType.action: - field.callableName = column.callableName; - break; - - default: - break; - } - field.editable = column.editable; - return field; - }); + case FieldType.action: + field.callableName = column.callableName; + break; + default: + break; + } + field.editable = column.editable; + return field; + }); return (
diff --git a/www/src/components/Table/ColumnMenu/index.tsx b/www/src/components/Table/ColumnMenu/index.tsx index 07e6395b..460bc84f 100644 --- a/www/src/components/Table/ColumnMenu/index.tsx +++ b/www/src/components/Table/ColumnMenu/index.tsx @@ -60,19 +60,25 @@ export default function ColumnMenu() { const [modal, setModal] = useState(INITIAL_MODAL); const { tableState, tableActions, columnMenuRef } = useFiretableContext(); - const [selectedColumnHeader, setSelectedColumnHeader] = useState(); + const [selectedColumnHeader, setSelectedColumnHeader] = useState(null); if (columnMenuRef) - columnMenuRef.current = { selectedColumnHeader, setSelectedColumnHeader }; + columnMenuRef.current = { + selectedColumnHeader, + setSelectedColumnHeader, + } as any; if (!tableState || !tableActions) return null; const { orderBy } = tableState; const actions = tableActions!.column; - const { column, anchorEl } = selectedColumnHeader ?? {}; + const { column, anchorEl } = (selectedColumnHeader ?? {}) as any; const handleClose = () => { if (!setSelectedColumnHeader) return; - setSelectedColumnHeader({ column: column!, anchorEl: null }); + setSelectedColumnHeader({ + column: column!, + anchorEl: null, + }); setTimeout(() => setSelectedColumnHeader(null), 300); }; @@ -178,7 +184,9 @@ export default function ColumnMenu() { onClick: () => setModal({ type: ModalStates.new, - data: { initializeColumn: { index: column.index - 1 } }, + data: { + initializeColumn: { index: column.index ? column.index - 1 : 0 }, + }, }), }, { @@ -187,7 +195,9 @@ export default function ColumnMenu() { onClick: () => setModal({ type: ModalStates.new, - data: { initializeColumn: { index: column.index + 1 } }, + data: { + initializeColumn: { index: column.index ? column.index + 1 : 0 }, + }, }), }, { diff --git a/www/src/components/Table/ExportCSV.tsx b/www/src/components/Table/ExportCSV.tsx index b79dcc1e..cbaf8337 100644 --- a/www/src/components/Table/ExportCSV.tsx +++ b/www/src/components/Table/ExportCSV.tsx @@ -21,11 +21,7 @@ import { SnackContext } from "contexts/snackContext"; import { useFiretableContext } from "contexts/firetableContext"; import { db } from "../../firebase"; import { FieldType } from "constants/fields"; -async function asyncForEach(array, callback) { - for (let index = 0; index < array.length; index++) { - await callback(array[index], index, array); - } -} + const ITEM_HEIGHT = 48; const ITEM_PADDING_TOP = 8; const MenuProps = { @@ -223,7 +219,10 @@ export default function ExportCSV() { MenuProps={MenuProps} > {tableState?.columns && - tableState?.columns.map((column: any) => ( + (Array.isArray(tableState?.columns) + ? tableState?.columns + : Object.values(tableState?.columns) + ).map((column: any) => ( {column.name} diff --git a/www/src/components/Table/index.tsx b/www/src/components/Table/index.tsx index ccf0d46f..feb859d7 100644 --- a/www/src/components/Table/index.tsx +++ b/www/src/components/Table/index.tsx @@ -127,10 +127,8 @@ export default function Table({ collection, filters }: ITableProps) { editable: false, }); } - console.log(columns); const rowHeight = tableState.config.rowHeight; - const rows = tableState.rows; const rowGetter = (rowIdx: number) => rows[rowIdx]; From 755c0b25a3f3ed34c21dbef6e5f160bee41c5804 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Wed, 1 Jul 2020 16:31:59 +0800 Subject: [PATCH 19/46] fix:multiselect supports undefined options --- www/src/components/SideDrawer/Form/Fields/MultiSelect.tsx | 1 + www/src/components/Table/formatters/MultiSelect.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/www/src/components/SideDrawer/Form/Fields/MultiSelect.tsx b/www/src/components/SideDrawer/Form/Fields/MultiSelect.tsx index 2cca8a90..ae70ee63 100644 --- a/www/src/components/SideDrawer/Form/Fields/MultiSelect.tsx +++ b/www/src/components/SideDrawer/Form/Fields/MultiSelect.tsx @@ -24,6 +24,7 @@ export default function MultiSelect({ <> form.setFieldValue(field.name, value)} diff --git a/www/src/components/Table/formatters/MultiSelect.tsx b/www/src/components/Table/formatters/MultiSelect.tsx index 497d7e7e..daf2d3df 100644 --- a/www/src/components/Table/formatters/MultiSelect.tsx +++ b/www/src/components/Table/formatters/MultiSelect.tsx @@ -103,7 +103,7 @@ export default function MultiSelect({ multiple={!isSingle as any} label={column.name} labelPlural={column.name} - options={options} + options={options ?? []} disabled={column.editable === false} onOpen={handleOpen} TextFieldProps={ From baf4245776d8bdce57bc0874bc53915beb5cbc64 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Thu, 2 Jul 2020 11:55:39 +0800 Subject: [PATCH 20/46] kaniko test, log current build config --- cloud_functions/functions/updateDeployStatus.ts | 9 ++++++--- cloudbuildfunctions.yaml | 6 ++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/cloud_functions/functions/updateDeployStatus.ts b/cloud_functions/functions/updateDeployStatus.ts index 17740a8d..b5d4aadd 100644 --- a/cloud_functions/functions/updateDeployStatus.ts +++ b/cloud_functions/functions/updateDeployStatus.ts @@ -20,12 +20,15 @@ if (serviceAccount) { }); const db = admin.firestore(); - const main = async deployRequestPath => { - await db.doc(deployRequestPath).update({ deployedAt: serverTimestamp() }); + const main = async (deployRequestPath: string, currentBuild) => { + await db.doc(deployRequestPath).update({ + deployedAt: serverTimestamp(), + currentBuild: currentBuild ?? "", + }); return true; }; - main(process.argv[2]) + main(process.argv[2], process.argv[3]) .catch(err => console.log(err)) .then(() => console.log("this will succeed")) .catch(() => "obligatory catch"); diff --git a/cloudbuildfunctions.yaml b/cloudbuildfunctions.yaml index 81d99c76..c5854692 100644 --- a/cloudbuildfunctions.yaml +++ b/cloudbuildfunctions.yaml @@ -1,4 +1,9 @@ steps: + - name: "gcr.io/kaniko-project/executor:latest" + args: + - --destination=gcr.io/${_PROJECT_ID}/image + - --cache=true + - --cache-ttl=24h - name: gcr.io/cloud-builders/gcloud args: - kms @@ -34,6 +39,7 @@ steps: args: - "updateStatus" - "${_REQUEST_DOC_PATH}" + - "${_FUNCTION_CONFIG}" dir: "cloud_functions/functions" substitutions: From 7e864075d975f5084b2080e76f3a6121a8326a99 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Thu, 2 Jul 2020 11:59:22 +0800 Subject: [PATCH 21/46] fix kaniko --- cloudbuildfunctions.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudbuildfunctions.yaml b/cloudbuildfunctions.yaml index c5854692..fc5fe9ac 100644 --- a/cloudbuildfunctions.yaml +++ b/cloudbuildfunctions.yaml @@ -1,7 +1,7 @@ steps: - name: "gcr.io/kaniko-project/executor:latest" args: - - --destination=gcr.io/${_PROJECT_ID}/image + - --destination=gcr.io/$PROJECT_ID/image - --cache=true - --cache-ttl=24h - name: gcr.io/cloud-builders/gcloud From ddd3bd7cfb79f76e9f6dd6878b2692fea64582b9 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Thu, 2 Jul 2020 12:02:52 +0800 Subject: [PATCH 22/46] remove docker file --- Dockerfile | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index edfc9216..00000000 --- a/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -# Stage 1 -FROM node:8 as react-build -WORKDIR /www -COPY . ./ -RUN yarn -RUN yarn build - -# Stage 2 - the production environment -FROM nginx:alpine -COPY nginx.conf /etc/nginx/conf.d/default.conf -COPY --from=react-build /app/build /usr/share/nginx/html -EXPOSE 80 -CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file From c7fbe6892ca55e76dab7c760f0c2077f21bacfcc Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Thu, 2 Jul 2020 12:07:06 +0800 Subject: [PATCH 23/46] kaniko test2 --- cloudbuildfunctions.yaml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/cloudbuildfunctions.yaml b/cloudbuildfunctions.yaml index fc5fe9ac..6a058049 100644 --- a/cloudbuildfunctions.yaml +++ b/cloudbuildfunctions.yaml @@ -1,9 +1,13 @@ steps: - - name: "gcr.io/kaniko-project/executor:latest" - args: - - --destination=gcr.io/$PROJECT_ID/image - - --cache=true - - --cache-ttl=24h + # - name: "gcr.io/kaniko-project/executor:latest" + # args: + # - --destination=gcr.io/$PROJECT_ID/image + # - --cache=true + # - --cache-ttl=24h + - name: gcr.io/cloud-builders/docker + args: ["build", "-t", "gcr.io/$PROJECT_ID/image", "."] + images: + - "gcr.io/$PROJECT_ID/image" - name: gcr.io/cloud-builders/gcloud args: - kms From a9f68e6fccd15ce09a016649a5ba4b185a8a09d1 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Thu, 2 Jul 2020 12:21:56 +0800 Subject: [PATCH 24/46] disable kaniko --- cloudbuildfunctions.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cloudbuildfunctions.yaml b/cloudbuildfunctions.yaml index 6a058049..2598e222 100644 --- a/cloudbuildfunctions.yaml +++ b/cloudbuildfunctions.yaml @@ -4,10 +4,6 @@ steps: # - --destination=gcr.io/$PROJECT_ID/image # - --cache=true # - --cache-ttl=24h - - name: gcr.io/cloud-builders/docker - args: ["build", "-t", "gcr.io/$PROJECT_ID/image", "."] - images: - - "gcr.io/$PROJECT_ID/image" - name: gcr.io/cloud-builders/gcloud args: - kms From 20848c0929b5f92ad92822269e27f317112ed1fc Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Thu, 2 Jul 2020 14:21:16 +0800 Subject: [PATCH 25/46] kaniko dockerfile test --- Dockerfile | 5 +++++ cloudbuildfunctions.yaml | 18 +++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..b579ba9e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,5 @@ +FROM node:10.15.1 +WORKDIR cloud_functions/function +COPY package*.json ./ +RUN npm install +COPY . . \ No newline at end of file diff --git a/cloudbuildfunctions.yaml b/cloudbuildfunctions.yaml index 2598e222..d3a6e56b 100644 --- a/cloudbuildfunctions.yaml +++ b/cloudbuildfunctions.yaml @@ -1,9 +1,9 @@ steps: - # - name: "gcr.io/kaniko-project/executor:latest" - # args: - # - --destination=gcr.io/$PROJECT_ID/image - # - --cache=true - # - --cache-ttl=24h + - name: "gcr.io/kaniko-project/executor:latest" + args: + - --destination=gcr.io/$PROJECT_ID/image + - --cache=true + - --cache-ttl=24h - name: gcr.io/cloud-builders/gcloud args: - kms @@ -13,10 +13,10 @@ steps: - --location=global - --keyring=antler-vc - --key=cloudbuild-env - - name: node:10.15.1 - entrypoint: yarn - args: ["install"] - dir: "cloud_functions/functions" + # - name: node:10.15.1 + # entrypoint: yarn + # args: ["install"] + # dir: "cloud_functions/functions" - name: node:10.15.1 entrypoint: yarn args: From 9d35ac2159e54d1b6c759f95835f38aefac90640 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Thu, 2 Jul 2020 14:23:41 +0800 Subject: [PATCH 26/46] updated dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index b579ba9e..45c13428 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM node:10.15.1 WORKDIR cloud_functions/function -COPY package*.json ./ +COPY package.json ./ RUN npm install COPY . . \ No newline at end of file From f4c42038a5270cd07986f5112e7bae3ea719fdfc Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Thu, 2 Jul 2020 14:25:19 +0800 Subject: [PATCH 27/46] docker typo --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 45c13428..6df51133 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM node:10.15.1 -WORKDIR cloud_functions/function +WORKDIR cloud_functions/functions COPY package.json ./ RUN npm install COPY . . \ No newline at end of file From 3eb27aba3a850882ba7e49a2ad8e276d12185686 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Thu, 2 Jul 2020 14:31:04 +0800 Subject: [PATCH 28/46] dockerfile test2 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 6df51133..be654b47 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM node:10.15.1 WORKDIR cloud_functions/functions -COPY package.json ./ +COPY cloud_functions/functions/package.json ./ RUN npm install COPY . . \ No newline at end of file From e4791c31ca2d08a3b8087668c8b2160267d14e4a Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Thu, 2 Jul 2020 14:39:20 +0800 Subject: [PATCH 29/46] docker using yarn --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index be654b47..5bcc8ddd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM node:10.15.1 WORKDIR cloud_functions/functions COPY cloud_functions/functions/package.json ./ -RUN npm install +RUN yarn install COPY . . \ No newline at end of file From ab8647a379b09c0a85ecbdc33afcbbd88cf83ad8 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Thu, 2 Jul 2020 15:32:03 +0800 Subject: [PATCH 30/46] delete github workflow --- .github/workflows/firebase_hosting.yml | 0 cloudbuildfunctions.yaml | 18 +++++++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 .github/workflows/firebase_hosting.yml diff --git a/.github/workflows/firebase_hosting.yml b/.github/workflows/firebase_hosting.yml deleted file mode 100644 index e69de29b..00000000 diff --git a/cloudbuildfunctions.yaml b/cloudbuildfunctions.yaml index d3a6e56b..2598e222 100644 --- a/cloudbuildfunctions.yaml +++ b/cloudbuildfunctions.yaml @@ -1,9 +1,9 @@ steps: - - name: "gcr.io/kaniko-project/executor:latest" - args: - - --destination=gcr.io/$PROJECT_ID/image - - --cache=true - - --cache-ttl=24h + # - name: "gcr.io/kaniko-project/executor:latest" + # args: + # - --destination=gcr.io/$PROJECT_ID/image + # - --cache=true + # - --cache-ttl=24h - name: gcr.io/cloud-builders/gcloud args: - kms @@ -13,10 +13,10 @@ steps: - --location=global - --keyring=antler-vc - --key=cloudbuild-env - # - name: node:10.15.1 - # entrypoint: yarn - # args: ["install"] - # dir: "cloud_functions/functions" + - name: node:10.15.1 + entrypoint: yarn + args: ["install"] + dir: "cloud_functions/functions" - name: node:10.15.1 entrypoint: yarn args: From be8909ff2633dc9febc97fd643d8106d1dd83e8a Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Fri, 3 Jul 2020 17:44:06 +0800 Subject: [PATCH 31/46] column setttings setup+ single/multiselect fields --- www/package.json | 2 +- .../ColumnMenu/ConfigFields/OptionsInput.tsx | 90 +++++++++++ .../components/Table/ColumnMenu/Settings.tsx | 144 ++++++++++++++++++ .../Table/ColumnMenu/TypeChange.tsx | 1 - www/src/components/Table/ColumnMenu/index.tsx | 27 +++- .../Table/formatters/MultiSelect.tsx | 6 +- www/src/contexts/firetableContext.tsx | 1 - 7 files changed, 264 insertions(+), 7 deletions(-) create mode 100644 www/src/components/Table/ColumnMenu/ConfigFields/OptionsInput.tsx create mode 100644 www/src/components/Table/ColumnMenu/Settings.tsx diff --git a/www/package.json b/www/package.json index 671a00ee..93d866bd 100644 --- a/www/package.json +++ b/www/package.json @@ -4,7 +4,7 @@ "private": true, "dependencies": { "@antlerengineering/components": "^0.2.7", - "@antlerengineering/multiselect": "^0.3.9", + "@antlerengineering/multiselect": "^0.3.14", "@date-io/date-fns": "1.x", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", diff --git a/www/src/components/Table/ColumnMenu/ConfigFields/OptionsInput.tsx b/www/src/components/Table/ColumnMenu/ConfigFields/OptionsInput.tsx new file mode 100644 index 00000000..b9cf217a --- /dev/null +++ b/www/src/components/Table/ColumnMenu/ConfigFields/OptionsInput.tsx @@ -0,0 +1,90 @@ +import React, { useEffect, useState } from "react"; +import { createStyles, makeStyles } 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 _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", + flexWrap: "wrap", + maxWidth: "95%", + padding: Theme.spacing(1), + }, + chip: { + margin: Theme.spacing(0.5), + }, + }) +); + +export default function OptionsInput(props: any) { + const { options, handleChange } = props; + const classes = useStyles(); + const [newOption, setNewOption] = useState(""); + const handleAdd = () => { + // setOptions([...options, newOption]); + if (newOption !== "") { + handleChange([...options, newOption]); + setNewOption(""); + } + }; + const handleDelete = (optionToDelete: string) => () => + handleChange(options.filter((option: string) => option !== optionToDelete)); + + 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/ColumnMenu/Settings.tsx b/www/src/components/Table/ColumnMenu/Settings.tsx new file mode 100644 index 00000000..5c198b52 --- /dev/null +++ b/www/src/components/Table/ColumnMenu/Settings.tsx @@ -0,0 +1,144 @@ +import React, { useState } from "react"; +import Button from "@material-ui/core/Button"; + +import Dialog from "@material-ui/core/Dialog"; +import Grid from "@material-ui/core/Grid"; +import DialogActions from "@material-ui/core/DialogActions"; +import DialogContent from "@material-ui/core/DialogContent"; +import { Typography, IconButton, TextField, Switch } from "@material-ui/core"; +import CloseIcon from "@material-ui/icons/Close"; +import { FieldType } from "constants/fields"; +import FieldsDropdown from "./FieldsDropdown"; +import OptionsInput from "./ConfigFields/OptionsInput"; +import { useFiretableContext } from "contexts/firetableContext"; +import MultiSelect from "@antlerengineering/multiselect"; + +const ColumnSelector = ({ columns, handleChange, validTypes }) => { + const options = columns + .filter(col => validTypes.includes(col.type)) + .map(col => ({ value: col.key, label: col.name })); + return ; +}; + +const ConfigForm = ({ type, config, handleChange }) => { + const { tableState, tables } = useFiretableContext(); + console.log(tables); + if (!tableState) return <>; + + switch (type) { + case FieldType.singleSelect: + case FieldType.multiSelect: + const { columns } = tableState; + return ( + <> + + ADD NEW? + + + User can add new options. + + { + handleChange("freeText")(!config.freeText); + }} + /> + + + ); + case FieldType.subTable: + return ( + + ); + + default: + return <>; + } +}; + +export default function FormDialog({ + name, + fieldName, + type, + open, + config, + handleClose, + handleSave, +}: { + name: string; + fieldName: string; + type: FieldType; + open: boolean; + config: any; + handleClose: Function; + handleSave: Function; +}) { + const [newConfig, setNewConfig] = useState(config ?? {}); + + return ( +
+ { + handleClose(); + }} + aria-labelledby="form-column-settings" + > + + + {name}: Settings + { + handleClose(); + }} + > + + + + + + { + update => { + console.log(key, update); + setNewConfig({ ...newConfig, [key]: update }); + }} + config={newConfig} + /> + } + + + + + + +
+ ); +} diff --git a/www/src/components/Table/ColumnMenu/TypeChange.tsx b/www/src/components/Table/ColumnMenu/TypeChange.tsx index 98fd8247..2e492e7c 100644 --- a/www/src/components/Table/ColumnMenu/TypeChange.tsx +++ b/www/src/components/Table/ColumnMenu/TypeChange.tsx @@ -1,6 +1,5 @@ import React, { useState } from "react"; import Button from "@material-ui/core/Button"; -import TextField from "@material-ui/core/TextField"; import Dialog from "@material-ui/core/Dialog"; import Grid from "@material-ui/core/Grid"; import DialogActions from "@material-ui/core/DialogActions"; diff --git a/www/src/components/Table/ColumnMenu/index.tsx b/www/src/components/Table/ColumnMenu/index.tsx index 460bc84f..5ce64b09 100644 --- a/www/src/components/Table/ColumnMenu/index.tsx +++ b/www/src/components/Table/ColumnMenu/index.tsx @@ -12,6 +12,7 @@ import ArrowDownwardIcon from "@material-ui/icons/ArrowDownward"; import ArrowUpwardIcon from "@material-ui/icons/ArrowUpward"; import EditIcon from "@material-ui/icons/Edit"; import ReorderIcon from "@material-ui/icons/Reorder"; +import SettingsIcon from "@material-ui/icons/Settings"; import ColumnPlusBeforeIcon from "assets/icons/ColumnPlusBefore"; import ColumnPlusAfterIcon from "assets/icons/ColumnPlusAfter"; import ColumnRemoveIcon from "assets/icons/ColumnRemove"; @@ -20,6 +21,7 @@ import MenuContents from "./MenuContents"; import NameChange from "./NameChange"; import NewColumn from "./NewColumn"; import TypeChange from "./TypeChange"; +import Settings from "./Settings"; import { useFiretableContext } from "contexts/firetableContext"; import { FIELDS } from "constants/fields"; @@ -33,6 +35,7 @@ enum ModalStates { nameChange = "NAME_CHANGE", typeChange = "TYPE_CHANGE", new = "NEW_COLUMN", + settings = "COLUMN_SETTINGS", } type SelectedColumnHeader = { @@ -170,7 +173,15 @@ export default function ColumnMenu() { // TODO: This is based off the cell type icon: _find(FIELDS, { type: column.type })?.icon, onClick: () => { - setModal({ type: ModalStates.typeChange, data: {} }); + setModal({ type: ModalStates.typeChange, data: { column } }); + }, + }, + { + label: `Column Settings`, + // TODO: This is based off the cell type + icon: , + onClick: () => { + setModal({ type: ModalStates.settings, data: { column } }); }, }, // { @@ -214,6 +225,7 @@ export default function ColumnMenu() { const clearModal = () => { setModal(INITIAL_MODAL); }; + console.log({ column }); return ( <> + { + actions.update(key, update); + clearModal(); + handleClose(); + }} + /> { currentUser.getIdTokenResult(true).then(results => { setUserRoles(results.claims.roles || []); setUserClaims(results.claims); - // setUserRegions(results.claims.regions || []); }); } }, [currentUser]); From f3bef430b2364183b0ccde9a28ba7b64ceba7175 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Fri, 3 Jul 2020 20:17:15 +0800 Subject: [PATCH 32/46] tableConnect and subtable columns settings --- .../Table/ColumnMenu/MenuContents.tsx | 1 - .../components/Table/ColumnMenu/NewColumn.tsx | 1 + .../components/Table/ColumnMenu/Settings.tsx | 97 ++++++++++++++++--- www/src/components/Table/ColumnMenu/index.tsx | 49 ++++++---- .../Table/formatters/ConnectTable.tsx | 2 +- .../components/Table/formatters/SubTable.tsx | 15 ++- 6 files changed, 130 insertions(+), 35 deletions(-) diff --git a/www/src/components/Table/ColumnMenu/MenuContents.tsx b/www/src/components/Table/ColumnMenu/MenuContents.tsx index fe26d5c5..8da82a9a 100644 --- a/www/src/components/Table/ColumnMenu/MenuContents.tsx +++ b/www/src/components/Table/ColumnMenu/MenuContents.tsx @@ -9,7 +9,6 @@ import { ListSubheader, Divider, } from "@material-ui/core"; -import { fade } from "@material-ui/core/styles"; const useStyles = makeStyles(theme => createStyles({ diff --git a/www/src/components/Table/ColumnMenu/NewColumn.tsx b/www/src/components/Table/ColumnMenu/NewColumn.tsx index 15dc3a07..ab075d32 100644 --- a/www/src/components/Table/ColumnMenu/NewColumn.tsx +++ b/www/src/components/Table/ColumnMenu/NewColumn.tsx @@ -88,6 +88,7 @@ export default function FormDialog({ name, fieldName, key: fieldName, + config: {}, ...data.initializeColumn, }); }} diff --git a/www/src/components/Table/ColumnMenu/Settings.tsx b/www/src/components/Table/ColumnMenu/Settings.tsx index 5c198b52..4ab49939 100644 --- a/www/src/components/Table/ColumnMenu/Settings.tsx +++ b/www/src/components/Table/ColumnMenu/Settings.tsx @@ -1,6 +1,5 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import Button from "@material-ui/core/Button"; - import Dialog from "@material-ui/core/Dialog"; import Grid from "@material-ui/core/Grid"; import DialogActions from "@material-ui/core/DialogActions"; @@ -8,27 +7,62 @@ import DialogContent from "@material-ui/core/DialogContent"; import { Typography, IconButton, TextField, Switch } from "@material-ui/core"; import CloseIcon from "@material-ui/icons/Close"; import { FieldType } from "constants/fields"; -import FieldsDropdown from "./FieldsDropdown"; import OptionsInput from "./ConfigFields/OptionsInput"; import { useFiretableContext } from "contexts/firetableContext"; import MultiSelect from "@antlerengineering/multiselect"; +import { db } from "../../../firebase"; +import _sortBy from "lodash/sortBy"; +const ColumnSelector = ({ + tableColumns, + handleChange, + validTypes, + table, + value, +}: { + tableColumns?: any[]; + handleChange: any; + validTypes: FieldType[]; + table?: string; + value: any; +}) => { + const [columns, setColumns] = useState(tableColumns ?? []); + const getColumns = async table => { + const tableConfigDoc = await db + .doc(`_FIRETABLE_/settings/schema/${table}`) + .get(); + const tableConfig = tableConfigDoc.data(); -const ColumnSelector = ({ columns, handleChange, validTypes }) => { + if (tableConfig) setColumns(tableConfig.columns ?? []); + }; + useEffect(() => { + if (table) { + console.log({ table }); + getColumns(table); + } + }, [table]); + console.log({ columns }); const options = columns - .filter(col => validTypes.includes(col.type)) - .map(col => ({ value: col.key, label: col.name })); - return ; + ? columns + .filter(col => validTypes.includes(col.type)) + .map(col => ({ value: col.key, label: col.name })) + : []; + return ( + + ); }; const ConfigForm = ({ type, config, handleChange }) => { const { tableState, tables } = useFiretableContext(); - console.log(tables); - if (!tableState) return <>; + if (!tableState) return <>; + const { columns } = tableState; switch (type) { case FieldType.singleSelect: case FieldType.multiSelect: - const { columns } = tableState; return ( <> { ); + case FieldType.connectTable: + const tableOptions = _sortBy( + tables?.map(t => ({ + label: `${t.section} - ${t.name}`, + value: t.collection, + })) ?? [], + "label" + ); + + return ( + <> + + + { + handleChange("filters")(e.target.value); + }} + /> + + ); case FieldType.subTable: return ( diff --git a/www/src/components/Table/ColumnMenu/index.tsx b/www/src/components/Table/ColumnMenu/index.tsx index 5ce64b09..9de0ffd2 100644 --- a/www/src/components/Table/ColumnMenu/index.tsx +++ b/www/src/components/Table/ColumnMenu/index.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import { createStyles, makeStyles, Menu } from "@material-ui/core"; import LockOpenIcon from "@material-ui/icons/LockOpen"; @@ -24,7 +24,7 @@ import TypeChange from "./TypeChange"; import Settings from "./Settings"; import { useFiretableContext } from "contexts/firetableContext"; -import { FIELDS } from "constants/fields"; +import { FIELDS, FieldType } from "constants/fields"; import _find from "lodash/find"; import { Column } from "react-data-grid"; import { PopoverProps } from "@material-ui/core"; @@ -70,11 +70,22 @@ export default function ColumnMenu() { setSelectedColumnHeader, } as any; + const { column, anchorEl } = (selectedColumnHeader ?? {}) as any; + + useEffect(() => { + if (column && column.type === FieldType.last) { + setModal({ + type: ModalStates.new, + data: { + initializeColumn: { index: column.index ? column.index + 1 : 0 }, + }, + }); + } + }, [column]); if (!tableState || !tableActions) return null; const { orderBy } = tableState; const actions = tableActions!.column; - const { column, anchorEl } = (selectedColumnHeader ?? {}) as any; const handleClose = () => { if (!setSelectedColumnHeader) return; @@ -225,23 +236,25 @@ export default function ColumnMenu() { const clearModal = () => { setModal(INITIAL_MODAL); }; - console.log({ column }); + return ( <> - - - + {column.type !== FieldType.last && ( + + + + )} {column && ( <> ( diff --git a/www/src/components/Table/formatters/SubTable.tsx b/www/src/components/Table/formatters/SubTable.tsx index 00e0c9fd..b659c0ca 100644 --- a/www/src/components/Table/formatters/SubTable.tsx +++ b/www/src/components/Table/formatters/SubTable.tsx @@ -19,7 +19,14 @@ const useStyles = makeStyles(theme => export default function SubTable({ column, row }: CustomCellProps) { const classes = useStyles(); - const { parentLabel } = column as any; + const { parentLabel, config } = column as any; + + const label = parentLabel + ? row[parentLabel] + : config.parentLabel.reduce((acc, curr) => { + if (acc !== "") return `${acc} - ${row[curr]}`; + else return row[curr]; + }, ""); const fieldName = column.key as string; const router = useRouter(); @@ -31,11 +38,11 @@ export default function SubTable({ column, row }: CustomCellProps) { if (parentLabels) subTablePath = encodeURIComponent(`${row.ref.path}/${fieldName}`) + - `?parentLabel=${parentLabels},${row[parentLabel]}`; + `?parentLabel=${parentLabels},${label}`; else subTablePath = encodeURIComponent(`${row.ref.path}/${fieldName}`) + - `?parentLabel=${encodeURIComponent(row[parentLabel])}`; + `?parentLabel=${encodeURIComponent(label)}`; return ( - {column.name}: {row[parentLabel]} + {column.name}: {label} From 4bbd4884d17131adc1b027334210aae788181727 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Fri, 3 Jul 2020 20:18:24 +0800 Subject: [PATCH 33/46] update table connect popper --- .../ConnectTableSelect/PopupContents.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/www/src/components/ConnectTableSelect/PopupContents.tsx b/www/src/components/ConnectTableSelect/PopupContents.tsx index e9d29429..139af606 100644 --- a/www/src/components/ConnectTableSelect/PopupContents.tsx +++ b/www/src/components/ConnectTableSelect/PopupContents.tsx @@ -42,13 +42,14 @@ export default function PopupContents({ multiple = true, row, }: IPopupContentsProps) { + const index = collectionPath ?? config.index; //temporary for pre column restructure migration const classes = useStyles(); const { userClaims } = useFiretableContext(); const algoliaIndex = useMemo(() => { - return searchClient.initIndex(collectionPath); - }, [collectionPath]); + return searchClient.initIndex(index); + }, [index]); // Algolia search query const [query, setQuery] = useState(""); @@ -62,11 +63,10 @@ export default function PopupContents({ console.log("SEARCH", query, algoliaIndex, row); const data = { ...userClaims, ...row }; - const filters = config.filters.replace( - /\{\{(.*?)\}\}/g, - (m, k) => data[k] - ); - console.log(filters); + const filters = config?.filters + ? config?.filters.replace(/\{\{(.*?)\}\}/g, (m, k) => data[k]) + : ""; + const resp = await algoliaIndex.search(query, { filters, }); @@ -86,7 +86,7 @@ export default function PopupContents({ const { _highlightResult, ...snapshot } = hit; const output = { snapshot, - docPath: `${collectionPath}/${snapshot.objectID}`, + docPath: `${index}/${snapshot.objectID}`, }; if (multiple) onChange([...value, output]); From 34372d65f9e302b4799eda8fba01c31d9a76f4c0 Mon Sep 17 00:00:00 2001 From: Shams mosowi Date: Sat, 4 Jul 2020 10:11:55 +0800 Subject: [PATCH 34/46] column restructure migration button --- www/src/components/Table/MigrateButton.tsx | 93 +++++++++++++++++++ www/src/components/Table/TableHeader.tsx | 29 +++--- .../components/Table/formatters/SubTable.tsx | 7 +- www/src/components/Table/index.tsx | 2 - www/src/hooks/useFiretable/index.ts | 4 +- www/src/hooks/useFiretable/useTable.tsx | 2 +- 6 files changed, 116 insertions(+), 21 deletions(-) create mode 100644 www/src/components/Table/MigrateButton.tsx diff --git a/www/src/components/Table/MigrateButton.tsx b/www/src/components/Table/MigrateButton.tsx new file mode 100644 index 00000000..476da5cf --- /dev/null +++ b/www/src/components/Table/MigrateButton.tsx @@ -0,0 +1,93 @@ +import React from "react"; +import { FieldType } from "constants/fields"; +import { Grid, Button, Tooltip } from "@material-ui/core"; +import { useFiretableContext } from "contexts/firetableContext"; +import { db } from "../../firebase"; +import AlertIcon from "@material-ui/icons/Warning"; +const MigrateButton = ({ columns, needsMigration }) => { + const { tableState } = useFiretableContext(); + + const configDocPath = tableState?.config.tableConfig.path; + const handleColumnMigration = async () => { + console.log({ columns }); + + const newColumns = columns.reduce((acc, currCol, currIndex) => { + const index = currCol.collectionPath; + const options = currCol.options; + delete currCol.options; + const parentLabel = [currCol.parentLabel]; + delete currCol.collectionPath; + delete currCol.parentLabel; + const baseCol = { + ...currCol, + fieldName: currCol.key, + index: currIndex, + }; + if (currCol.type === FieldType.connectTable) { + return { + ...acc, + + [currCol.key]: { ...baseCol, config: { ...currCol.config, index } }, + }; + } else if (currCol.type === FieldType.subTable) { + return { + ...acc, + [currCol.key]: { + ...baseCol, + config: { ...currCol.config, parentLabel }, + }, + }; + } else if ( + [FieldType.multiSelect, FieldType.singleSelect].includes(currCol.type) + ) { + return { + ...acc, + [currCol.key]: { + ...baseCol, + config: { ...currCol.config, options }, + }, + }; + } else return { ...acc, [currCol.key]: baseCol }; + }, {}); + console.log({ newColumns }); + await db + .doc(configDocPath) + .update({ columns: newColumns, oldColumns: columns }); + window.location.reload(); + }; + if (needsMigration) + return ( + + + + + + ); + else return <>; + // else + // return ( + // + // ); +}; +export default MigrateButton; diff --git a/www/src/components/Table/TableHeader.tsx b/www/src/components/Table/TableHeader.tsx index 7c7c49ac..5644d95a 100644 --- a/www/src/components/Table/TableHeader.tsx +++ b/www/src/components/Table/TableHeader.tsx @@ -8,6 +8,7 @@ import { MenuItem, Typography, Button, + Tooltip, } from "@material-ui/core"; import AddIcon from "@material-ui/icons/Add"; @@ -19,6 +20,7 @@ import { FireTableFilter } from "hooks/useFiretable"; import { DRAWER_COLLAPSED_WIDTH } from "components/SideDrawer"; import { useFiretableContext } from "contexts/firetableContext"; import { FieldType } from "constants/fields"; +import MigrateButton from "./MigrateButton"; export const TABLE_HEADER_HEIGHT = 56; @@ -55,11 +57,8 @@ const useStyles = makeStyles(theme => ); interface ITableHeaderProps { - collection: string; rowHeight: number; updateConfig: Function; - - columns: any; filters: FireTableFilter[]; } @@ -67,14 +66,18 @@ interface ITableHeaderProps { * TODO: Make this properly mobile responsive, not just horizontally scrolling */ export default function TableHeader({ - collection, rowHeight, updateConfig, - columns, + filters, }: ITableHeaderProps) { const classes = useStyles(); - const { tableActions, userClaims } = useFiretableContext(); + const { tableActions, tableState } = useFiretableContext(); + if (!tableState || !tableState.columns) return <>; + const { columns } = tableState; + + const needsMigration = Array.isArray(columns) && columns.length !== 0; + const tempColumns = needsMigration ? columns : Object.values(columns); return ( + */}