From 3941ae548ecdc79330db3c6c500645e9d2d704f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Jan 2023 18:17:26 +0000 Subject: [PATCH 01/78] Bump ua-parser-js from 0.7.32 to 0.7.33 Bumps [ua-parser-js](https://github.com/faisalman/ua-parser-js) from 0.7.32 to 0.7.33. - [Release notes](https://github.com/faisalman/ua-parser-js/releases) - [Changelog](https://github.com/faisalman/ua-parser-js/blob/master/changelog.md) - [Commits](https://github.com/faisalman/ua-parser-js/compare/0.7.32...0.7.33) --- updated-dependencies: - dependency-name: ua-parser-js dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index d669d494..5038e845 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12264,9 +12264,9 @@ typescript@^4.9.3: integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA== ua-parser-js@^0.7.30: - version "0.7.32" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.32.tgz#cd8c639cdca949e30fa68c44b7813ef13e36d211" - integrity sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw== + version "0.7.33" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532" + integrity sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw== unbox-primitive@^1.0.2: version "1.0.2" From 189c86a16ee6c6b0ebb7b20d16143ce592169655 Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Mon, 27 Feb 2023 18:10:12 +0100 Subject: [PATCH 02/78] Created Color Select and Implemented it on MultiSelect --- src/components/ColorSelect.tsx | 150 ++++++++++++++++++ .../fields/SingleSelect/Settings.tsx | 8 +- 2 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 src/components/ColorSelect.tsx diff --git a/src/components/ColorSelect.tsx b/src/components/ColorSelect.tsx new file mode 100644 index 00000000..cee3a29b --- /dev/null +++ b/src/components/ColorSelect.tsx @@ -0,0 +1,150 @@ +import { useState } from "react"; +import Button from "@mui/material/Button"; +import Box from "@mui/material/Box"; +import Menu from "@mui/material/Menu"; +import Grid from "@mui/material/Grid"; +import { Chip, Divider, Typography } from "@mui/material"; +import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; +import FormatColorResetIcon from "@mui/icons-material/FormatColorReset"; + +const MUIColorsArray = [ + "primary", + "secondary", + "info", + "success", + "error", + "warning", +]; + +const ColorSelect = () => { + /* Hold the current state of a given option defaults to `default` */ + const [color, setColor] = useState("primary"); + + /* MUI Specific state */ + const [colorSelectAnchor, setColorSelectAnchor] = + useState(null); + const open = Boolean(colorSelectAnchor); + + /* MUI Menu event handlers */ + const handleClick = (event: React.MouseEvent) => { + setColorSelectAnchor(event.currentTarget); + }; + const handleClose = () => { + setColorSelectAnchor(null); + }; + + return ( +
+ + + {/* Menu */} + + + COLOURS + + + + {MUIColorsArray.map((color_string: string, index: number) => ( + + + + + + + + + + Preview + + + + + + + +
+ ); +}; + +export default ColorSelect; diff --git a/src/components/fields/SingleSelect/Settings.tsx b/src/components/fields/SingleSelect/Settings.tsx index 2fc908b9..26362f5d 100644 --- a/src/components/fields/SingleSelect/Settings.tsx +++ b/src/components/fields/SingleSelect/Settings.tsx @@ -14,6 +14,7 @@ import { } from "@mui/material"; import AddIcon from "@mui/icons-material/AddCircle"; import RemoveIcon from "@mui/icons-material/CancelRounded"; +import ColorSelect from "@src/components/ColorSelect"; export default function Settings({ onChange, config }: ISettingsProps) { const listEndRef: any = useRef(null); @@ -52,9 +53,12 @@ export default function Settings({ onChange, config }: ISettingsProps) { alignItems="center" > - {option} + + + {option} + - + From d81b203cfd0cd977ac97e9dc4f813471896a3534 Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Thu, 2 Mar 2023 22:53:49 +0100 Subject: [PATCH 03/78] Added predefined colors from palette & added the customizable color modal --- src/components/ColorSelect.tsx | 171 ++++++++++++++++++++++++++++----- 1 file changed, 145 insertions(+), 26 deletions(-) diff --git a/src/components/ColorSelect.tsx b/src/components/ColorSelect.tsx index cee3a29b..104f6a90 100644 --- a/src/components/ColorSelect.tsx +++ b/src/components/ColorSelect.tsx @@ -1,24 +1,46 @@ -import { useState } from "react"; +import { FC, useEffect, useState } from "react"; import Button from "@mui/material/Button"; import Box from "@mui/material/Box"; import Menu from "@mui/material/Menu"; import Grid from "@mui/material/Grid"; -import { Chip, Divider, Typography } from "@mui/material"; +import { Chip, Divider, Typography, useTheme } from "@mui/material"; +import Modal from "./Modal"; import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; import FormatColorResetIcon from "@mui/icons-material/FormatColorReset"; +import { paletteToMui, palette } from "@src/theme/palette"; +import ColorPickerInput from "./ColorPickerInput"; +import { toColor } from "react-color-palette"; -const MUIColorsArray = [ - "primary", - "secondary", - "info", - "success", - "error", - "warning", -]; +interface SelectColorThemeOptions { + light: string; + dark: string; +} const ColorSelect = () => { + /* Get current */ + const theme = useTheme(); + const mode = theme.palette.mode; + + /* Palette - reset paletter to object */ + const palettes = Object({ + gray: palette.aGray, + blue: palette.blue, + red: palette.aRed, + green: palette.green, + yellow: palette.yellow, + pink: palette.pink, + teal: palette.teal, + tangerine: palette.tangerine, + orange: palette.orange, + cyan: palette.cyan, + amber: palette.amber, + lightGreen: palette.lightGreen, + }); + /* Hold the current state of a given option defaults to `default` */ - const [color, setColor] = useState("primary"); + const [color, setColor] = useState( + paletteToMui(palette["gray"]) + ); /* MUI Specific state */ const [colorSelectAnchor, setColorSelectAnchor] = @@ -53,7 +75,7 @@ const ColorSelect = () => { width: 20, height: 20, borderRadius: 100, - backgroundColor: `${color}.main`, + backgroundColor: color[mode], }} /> @@ -87,39 +109,41 @@ const ColorSelect = () => { COLOURS - - {MUIColorsArray.map((color_string: string, index: number) => ( + + {Object.keys(palettes).map((key: string, index: number) => ( @@ -138,7 +162,7 @@ const ColorSelect = () => { component="small" size="small" label="Option 1" - color={color as any} + sx={{ backgroundColor: color[mode] }} /> @@ -147,4 +171,99 @@ const ColorSelect = () => { ); }; +interface CustomizeColor { + currentColor: SelectColorThemeOptions; + onChange: (value: SelectColorThemeOptions) => void; +} + +const CustomSelectColor: FC = ({ currentColor, onChange }) => { + const [color, setColor] = useState(currentColor); + + /* Update color value onFocus */ + useEffect(() => { + setColor(currentColor); + }, [currentColor]); + + /* Pass value to the onChange function */ + const handleChange = (color: SelectColorThemeOptions) => { + setColor(color); + onChange(color); + }; + + /* MUI Specific state */ + const [open, setOpen] = useState(false); + + /* MUI Menu event handlers */ + const handleClick = () => setOpen(true); + const handleClose = () => setOpen(false); + + return ( +
+ + + + {/* Light Theme Customize Color */} + + + handleChange({ ...color, ...{ light: value.hex } }) + } + /> + + + + Light Theme + + + + + + + + + {/* Dark Theme Customize Color */} + + + handleChange({ ...color, ...{ dark: value.hex } }) + } + /> + + + + Dark Theme + + + + + + + + + +
+ ); +}; + export default ColorSelect; From 9bcab13f53cd8b95b97fdc5d0fb9ef453782d4a8 Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Thu, 2 Mar 2023 23:25:20 +0100 Subject: [PATCH 04/78] Seperated components and moved files into a folder --- .../SelectColors/CustomizeColorModal.tsx | 113 ++++++++++++++++++ .../index.tsx} | 103 +--------------- .../fields/SingleSelect/Settings.tsx | 2 +- 3 files changed, 117 insertions(+), 101 deletions(-) create mode 100644 src/components/SelectColors/CustomizeColorModal.tsx rename src/components/{ColorSelect.tsx => SelectColors/index.tsx} (59%) diff --git a/src/components/SelectColors/CustomizeColorModal.tsx b/src/components/SelectColors/CustomizeColorModal.tsx new file mode 100644 index 00000000..a9d7e6a8 --- /dev/null +++ b/src/components/SelectColors/CustomizeColorModal.tsx @@ -0,0 +1,113 @@ +import { FC, useEffect, useState } from "react"; +import Button from "@mui/material/Button"; +import Box from "@mui/material/Box"; +import Grid from "@mui/material/Grid"; +import { Chip, Typography } from "@mui/material"; +import Modal from "@src/components/Modal"; +import ColorPickerInput from "@src/components/ColorPickerInput"; +import { toColor } from "react-color-palette"; + +interface SelectColorThemeOptions { + light: string; + dark: string; +} + +interface CustomizeColor { + currentColor: SelectColorThemeOptions; + onChange: (value: SelectColorThemeOptions) => void; +} + +const CustomizeColorModal: FC = ({ + currentColor, + onChange, +}) => { + const [color, setColor] = useState(currentColor); + + /* Update color value onFocus */ + useEffect(() => { + setColor(currentColor); + }, [currentColor]); + + /* Pass value to the onChange function */ + const handleChange = (color: SelectColorThemeOptions) => { + setColor(color); + onChange(color); + }; + + /* MUI Specific state */ + const [open, setOpen] = useState(false); + + /* MUI Menu event handlers */ + const handleClick = () => setOpen(true); + const handleClose = () => setOpen(false); + + return ( +
+ + + + {/* Light Theme Customize Color */} + + + handleChange({ ...color, ...{ light: value.hex } }) + } + /> + + + + Light Theme + + + + + + + + + {/* Dark Theme Customize Color */} + + + handleChange({ ...color, ...{ dark: value.hex } }) + } + /> + + + + Dark Theme + + + + + + + + + +
+ ); +}; + +export default CustomizeColorModal; diff --git a/src/components/ColorSelect.tsx b/src/components/SelectColors/index.tsx similarity index 59% rename from src/components/ColorSelect.tsx rename to src/components/SelectColors/index.tsx index 104f6a90..83b59192 100644 --- a/src/components/ColorSelect.tsx +++ b/src/components/SelectColors/index.tsx @@ -1,15 +1,13 @@ -import { FC, useEffect, useState } from "react"; +import { useState } from "react"; import Button from "@mui/material/Button"; import Box from "@mui/material/Box"; import Menu from "@mui/material/Menu"; import Grid from "@mui/material/Grid"; import { Chip, Divider, Typography, useTheme } from "@mui/material"; -import Modal from "./Modal"; import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; import FormatColorResetIcon from "@mui/icons-material/FormatColorReset"; import { paletteToMui, palette } from "@src/theme/palette"; -import ColorPickerInput from "./ColorPickerInput"; -import { toColor } from "react-color-palette"; +import CustomizeColorModal from "./CustomizeColorModal"; interface SelectColorThemeOptions { light: string; @@ -131,7 +129,7 @@ const ColorSelect = () => {
- setColor(color)} /> @@ -171,99 +169,4 @@ const ColorSelect = () => { ); }; -interface CustomizeColor { - currentColor: SelectColorThemeOptions; - onChange: (value: SelectColorThemeOptions) => void; -} - -const CustomSelectColor: FC = ({ currentColor, onChange }) => { - const [color, setColor] = useState(currentColor); - - /* Update color value onFocus */ - useEffect(() => { - setColor(currentColor); - }, [currentColor]); - - /* Pass value to the onChange function */ - const handleChange = (color: SelectColorThemeOptions) => { - setColor(color); - onChange(color); - }; - - /* MUI Specific state */ - const [open, setOpen] = useState(false); - - /* MUI Menu event handlers */ - const handleClick = () => setOpen(true); - const handleClose = () => setOpen(false); - - return ( -
- - - - {/* Light Theme Customize Color */} - - - handleChange({ ...color, ...{ light: value.hex } }) - } - /> - - - - Light Theme - - - - - - - - - {/* Dark Theme Customize Color */} - - - handleChange({ ...color, ...{ dark: value.hex } }) - } - /> - - - - Dark Theme - - - - - - - - - -
- ); -}; - export default ColorSelect; diff --git a/src/components/fields/SingleSelect/Settings.tsx b/src/components/fields/SingleSelect/Settings.tsx index 26362f5d..d0fe7fdb 100644 --- a/src/components/fields/SingleSelect/Settings.tsx +++ b/src/components/fields/SingleSelect/Settings.tsx @@ -14,7 +14,7 @@ import { } from "@mui/material"; import AddIcon from "@mui/icons-material/AddCircle"; import RemoveIcon from "@mui/icons-material/CancelRounded"; -import ColorSelect from "@src/components/ColorSelect"; +import ColorSelect from "@src/components/SelectColors"; export default function Settings({ onChange, config }: ISettingsProps) { const listEndRef: any = useRef(null); From 3866f4d15bd22f34098d0cd12e4ff0f04dfa32f4 Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Fri, 3 Mar 2023 00:31:22 +0100 Subject: [PATCH 05/78] Removed duplicate interface for ColorSelect --- src/components/SelectColors/CustomizeColorModal.tsx | 6 +----- src/components/SelectColors/index.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/components/SelectColors/CustomizeColorModal.tsx b/src/components/SelectColors/CustomizeColorModal.tsx index a9d7e6a8..49462fc4 100644 --- a/src/components/SelectColors/CustomizeColorModal.tsx +++ b/src/components/SelectColors/CustomizeColorModal.tsx @@ -6,11 +6,7 @@ import { Chip, Typography } from "@mui/material"; import Modal from "@src/components/Modal"; import ColorPickerInput from "@src/components/ColorPickerInput"; import { toColor } from "react-color-palette"; - -interface SelectColorThemeOptions { - light: string; - dark: string; -} +import { SelectColorThemeOptions } from "."; interface CustomizeColor { currentColor: SelectColorThemeOptions; diff --git a/src/components/SelectColors/index.tsx b/src/components/SelectColors/index.tsx index 83b59192..cb0a3731 100644 --- a/src/components/SelectColors/index.tsx +++ b/src/components/SelectColors/index.tsx @@ -9,7 +9,7 @@ import FormatColorResetIcon from "@mui/icons-material/FormatColorReset"; import { paletteToMui, palette } from "@src/theme/palette"; import CustomizeColorModal from "./CustomizeColorModal"; -interface SelectColorThemeOptions { +export interface SelectColorThemeOptions { light: string; dark: string; } @@ -35,17 +35,17 @@ const ColorSelect = () => { lightGreen: palette.lightGreen, }); - /* Hold the current state of a given option defaults to `default` */ + /* Hold the current state of a given option defaults to `gray` from the color palette */ const [color, setColor] = useState( paletteToMui(palette["gray"]) ); - /* MUI Specific state */ + /* MUI Specific state for color context menu */ const [colorSelectAnchor, setColorSelectAnchor] = useState(null); const open = Boolean(colorSelectAnchor); - /* MUI Menu event handlers */ + /* MUI Menu event handlers for color context menu */ const handleClick = (event: React.MouseEvent) => { setColorSelectAnchor(event.currentTarget); }; From 0ff87300b46cfc74d7a794b8d78bae8abb4d178a Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Fri, 3 Mar 2023 15:38:18 +0100 Subject: [PATCH 06/78] fixed react-color-palette issue --- src/components/ColorPickerInput.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/ColorPickerInput.tsx b/src/components/ColorPickerInput.tsx index 89ebdb21..b1cc1fc7 100644 --- a/src/components/ColorPickerInput.tsx +++ b/src/components/ColorPickerInput.tsx @@ -43,6 +43,7 @@ export default function ColorPickerInput({ const [localValue, setLocalValue] = useState(value); const [width, setRef] = useResponsiveWidth(); const theme = useTheme(); + const isDark = theme.palette.mode === "dark" ? true : false; return ( @@ -70,6 +74,7 @@ export default function ColorPickerInput({ color={localValue} onChange={(color) => setLocalValue(color)} onChangeComplete={onChangeComplete} + dark={isDark} /> ); From 16c32b0fcec82f3ef674e51882ff2d4b0c8f2729 Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Sat, 4 Mar 2023 23:41:22 +0100 Subject: [PATCH 07/78] Chip colors now being added to config and being returned and consumed in app - last task; showing colors on chips --- src/components/SelectColors/index.tsx | 20 +++++++++---- .../fields/SingleSelect/Settings.tsx | 28 +++++++++++++++++-- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/components/SelectColors/index.tsx b/src/components/SelectColors/index.tsx index cb0a3731..4adbc67b 100644 --- a/src/components/SelectColors/index.tsx +++ b/src/components/SelectColors/index.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { FC, useState } from "react"; import Button from "@mui/material/Button"; import Box from "@mui/material/Box"; import Menu from "@mui/material/Menu"; @@ -14,7 +14,12 @@ export interface SelectColorThemeOptions { dark: string; } -const ColorSelect = () => { +interface IColorSelect { + handleChange: (value: SelectColorThemeOptions) => void; + initialValue: SelectColorThemeOptions; +} + +const ColorSelect: FC = ({ handleChange, initialValue }) => { /* Get current */ const theme = useTheme(); const mode = theme.palette.mode; @@ -37,9 +42,14 @@ const ColorSelect = () => { /* Hold the current state of a given option defaults to `gray` from the color palette */ const [color, setColor] = useState( - paletteToMui(palette["gray"]) + initialValue || paletteToMui(palette["gray"]) ); + const onChange = (color: SelectColorThemeOptions) => { + setColor(color); + handleChange(color); + }; + /* MUI Specific state for color context menu */ const [colorSelectAnchor, setColorSelectAnchor] = useState(null); @@ -121,7 +131,7 @@ const ColorSelect = () => { }, }} size="small" - onClick={() => setColor(paletteToMui(palettes[key]))} + onClick={() => onChange(paletteToMui(palettes[key]))} key={index} />
@@ -131,7 +141,7 @@ const ColorSelect = () => { setColor(color)} + onChange={(color) => onChange(color)} /> diff --git a/src/components/fields/SingleSelect/Settings.tsx b/src/components/fields/SingleSelect/Settings.tsx index d0fe7fdb..c2c242a0 100644 --- a/src/components/fields/SingleSelect/Settings.tsx +++ b/src/components/fields/SingleSelect/Settings.tsx @@ -14,12 +14,21 @@ import { } from "@mui/material"; import AddIcon from "@mui/icons-material/AddCircle"; import RemoveIcon from "@mui/icons-material/CancelRounded"; -import ColorSelect from "@src/components/SelectColors"; +import ColorSelect, { + SelectColorThemeOptions, +} from "@src/components/SelectColors"; export default function Settings({ onChange, config }: ISettingsProps) { const listEndRef: any = useRef(null); const options = config.options ?? []; const [newOption, setNewOption] = useState(""); + + /* State for holding Chip Colors for Select and MultiSelect */ + const colors = config.colors ?? []; + const [chipColors, setChipColors] = useState<{}>( + Object.assign({}, colors) || {} + ); + const handleAdd = () => { if (newOption.trim() !== "") { if (options.includes(newOption)) { @@ -32,6 +41,14 @@ export default function Settings({ onChange, config }: ISettingsProps) { } }; + const handleChipColorChange = ( + index: number, + color: SelectColorThemeOptions + ) => { + setChipColors((current) => ({ ...current, [index]: color })); + onChange("colors")(Object.values(chipColors)); + }; + return (
Options @@ -43,7 +60,7 @@ export default function Settings({ onChange, config }: ISettingsProps) { marginBottom: 5, }} > - {options?.map((option: string) => ( + {options?.map((option: string, index: number) => ( <> - + + handleChipColorChange(index, color) + } + /> {option} From 4a3867b8b0ebac58c5be820959bf7637b22f5f90 Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Mon, 6 Mar 2023 02:25:02 +0100 Subject: [PATCH 08/78] Select and MultiSelect chips are now colorized; working on fixing and implementing some logic --- src/components/FormattedChip.tsx | 7 ++++- .../fields/MultiSelect/DisplayCell.tsx | 19 ++++++++++-- .../fields/SingleSelect/DisplayCell.tsx | 25 ++++++++++++++-- .../fields/SingleSelect/Settings.tsx | 29 +++++++++++-------- 4 files changed, 63 insertions(+), 17 deletions(-) diff --git a/src/components/FormattedChip.tsx b/src/components/FormattedChip.tsx index 6e145d50..be3216e7 100644 --- a/src/components/FormattedChip.tsx +++ b/src/components/FormattedChip.tsx @@ -16,7 +16,12 @@ export default function FormattedChip(props: ChipProps) { return ( ); diff --git a/src/components/fields/MultiSelect/DisplayCell.tsx b/src/components/fields/MultiSelect/DisplayCell.tsx index fe7d6b87..38c54681 100644 --- a/src/components/fields/MultiSelect/DisplayCell.tsx +++ b/src/components/fields/MultiSelect/DisplayCell.tsx @@ -1,12 +1,13 @@ import { IDisplayCellProps } from "@src/components/fields/types"; -import { ButtonBase, Grid, Tooltip } from "@mui/material"; +import { ButtonBase, Grid, Tooltip, useTheme } from "@mui/material"; import WarningIcon from "@mui/icons-material/WarningAmber"; import { ChevronDown } from "@src/assets/icons"; import { sanitiseValue } from "./utils"; import ChipList from "@src/components/Table/TableCell/ChipList"; import FormattedChip from "@src/components/FormattedChip"; +import palette, { paletteToMui } from "@src/theme/palette"; export default function MultiSelect({ value, @@ -14,7 +15,12 @@ export default function MultiSelect({ disabled, tabIndex, rowHeight, + column, }: IDisplayCellProps) { + const defaultColor = paletteToMui(palette.aGray); + const colors = column?.config?.colors ?? {}; + const { mode } = useTheme().palette; + const rendered = typeof value === "string" && value !== "" ? (
@@ -30,7 +36,16 @@ export default function MultiSelect({ (item) => typeof item === "string" && ( - + 0 && + colors[item.toLocaleLowerCase()] + ? colors[item.toLocaleLowerCase()][mode] + : defaultColor[mode], + }} + /> ) )} diff --git a/src/components/fields/SingleSelect/DisplayCell.tsx b/src/components/fields/SingleSelect/DisplayCell.tsx index ece750d1..2cb307c3 100644 --- a/src/components/fields/SingleSelect/DisplayCell.tsx +++ b/src/components/fields/SingleSelect/DisplayCell.tsx @@ -1,16 +1,25 @@ import { IDisplayCellProps } from "@src/components/fields/types"; -import { ButtonBase } from "@mui/material"; +import { ButtonBase, Chip } from "@mui/material"; import { ChevronDown } from "@src/assets/icons"; +import { useTheme } from "@mui/material"; import { sanitiseValue } from "./utils"; +import palette, { paletteToMui } from "@src/theme/palette"; +import ChipList from "@src/components/Table/TableCell/ChipList"; export default function SingleSelect({ value, showPopoverCell, disabled, tabIndex, + column, + rowHeight, }: IDisplayCellProps) { + const defaultColor = paletteToMui(palette.aGray); + const colors = column?.config?.colors ?? {}; + const { mode } = useTheme().palette; + const rendered = (
- {sanitiseValue(value)} + + 0 && + colors[value.toLocaleLowerCase()] + ? colors[value.toLocaleLowerCase()][mode] + : defaultColor[mode], + }} + /> +
); diff --git a/src/components/fields/SingleSelect/Settings.tsx b/src/components/fields/SingleSelect/Settings.tsx index c2c242a0..15563ce7 100644 --- a/src/components/fields/SingleSelect/Settings.tsx +++ b/src/components/fields/SingleSelect/Settings.tsx @@ -24,10 +24,7 @@ export default function Settings({ onChange, config }: ISettingsProps) { const [newOption, setNewOption] = useState(""); /* State for holding Chip Colors for Select and MultiSelect */ - const colors = config.colors ?? []; - const [chipColors, setChipColors] = useState<{}>( - Object.assign({}, colors) || {} - ); + const colors = config.colors ?? {}; const handleAdd = () => { if (newOption.trim() !== "") { @@ -42,11 +39,18 @@ export default function Settings({ onChange, config }: ISettingsProps) { }; const handleChipColorChange = ( - index: number, + key: string, color: SelectColorThemeOptions ) => { - setChipColors((current) => ({ ...current, [index]: color })); - onChange("colors")(Object.values(chipColors)); + const _key = key.toLocaleLowerCase(); + colors[_key] = color; + onChange("colors")(Object(colors)); + }; + + const handleChipColorDelete = (key: string) => { + const _key = key.toLocaleLowerCase(); + delete colors[_key]; + onChange("colors")(Object(colors)); }; return ( @@ -72,9 +76,9 @@ export default function Settings({ onChange, config }: ISettingsProps) { - handleChipColorChange(index, color) + handleChipColorChange(option, color) } /> {option} @@ -83,11 +87,12 @@ export default function Settings({ onChange, config }: ISettingsProps) { + onClick={() => { onChange("options")( options.filter((o: string) => o !== option) - ) - } + ); + handleChipColorDelete(option); + }} > {} From 5c6a343161fb49cd09d6d0f161422707eca9e622 Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Mon, 6 Mar 2023 03:05:03 +0100 Subject: [PATCH 09/78] Change check logic for values in SingleSelect and MultiSelect DisplayCells --- .../fields/MultiSelect/DisplayCell.tsx | 8 +++----- .../fields/SingleSelect/DisplayCell.tsx | 18 +++++++++--------- .../fields/SingleSelect/Settings.tsx | 7 +++---- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/components/fields/MultiSelect/DisplayCell.tsx b/src/components/fields/MultiSelect/DisplayCell.tsx index 38c54681..8310acef 100644 --- a/src/components/fields/MultiSelect/DisplayCell.tsx +++ b/src/components/fields/MultiSelect/DisplayCell.tsx @@ -39,11 +39,9 @@ export default function MultiSelect({ 0 && - colors[item.toLocaleLowerCase()] - ? colors[item.toLocaleLowerCase()][mode] - : defaultColor[mode], + backgroundColor: colors[item.toLocaleLowerCase()] + ? colors[item.toLocaleLowerCase()][mode] + : defaultColor[mode], }} /> diff --git a/src/components/fields/SingleSelect/DisplayCell.tsx b/src/components/fields/SingleSelect/DisplayCell.tsx index 2cb307c3..967633b0 100644 --- a/src/components/fields/SingleSelect/DisplayCell.tsx +++ b/src/components/fields/SingleSelect/DisplayCell.tsx @@ -29,17 +29,17 @@ export default function SingleSelect({ }} > - 0 && - colors[value.toLocaleLowerCase()] + {value && ( + + }} + /> + )}
); diff --git a/src/components/fields/SingleSelect/Settings.tsx b/src/components/fields/SingleSelect/Settings.tsx index 15563ce7..908249d1 100644 --- a/src/components/fields/SingleSelect/Settings.tsx +++ b/src/components/fields/SingleSelect/Settings.tsx @@ -87,12 +87,11 @@ export default function Settings({ onChange, config }: ISettingsProps) { { + onClick={() => onChange("options")( options.filter((o: string) => o !== option) - ); - handleChipColorDelete(option); - }} + ) + } > {} From d283a4721d21659e959f40e95c1b28f777ffae25 Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Tue, 7 Mar 2023 00:11:18 +0100 Subject: [PATCH 10/78] Fixed color on multiselect chip in side drawer field and start of logic changes --- .../fields/MultiSelect/SideDrawerField.tsx | 5 +- .../fields/SingleSelect/Settings.tsx | 52 ++++++++++--------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/components/fields/MultiSelect/SideDrawerField.tsx b/src/components/fields/MultiSelect/SideDrawerField.tsx index 99c260be..4482350f 100644 --- a/src/components/fields/MultiSelect/SideDrawerField.tsx +++ b/src/components/fields/MultiSelect/SideDrawerField.tsx @@ -1,6 +1,6 @@ import { ISideDrawerFieldProps } from "@src/components/fields/types"; -import { Grid, Button, Tooltip } from "@mui/material"; +import { Grid, Button, Tooltip, useTheme } from "@mui/material"; import WarningIcon from "@mui/icons-material/WarningAmber"; import MultiSelectComponent from "@rowy/multiselect"; import FormattedChip from "@src/components/FormattedChip"; @@ -16,6 +16,8 @@ export default function MultiSelect({ disabled, }: ISideDrawerFieldProps) { const config = column.config ?? {}; + const colors = column.config?.colors ?? {}; + const { mode } = useTheme().palette; const handleDelete = (index: number) => () => { const newValues = [...value]; @@ -75,6 +77,7 @@ export default function MultiSelect({ ) diff --git a/src/components/fields/SingleSelect/Settings.tsx b/src/components/fields/SingleSelect/Settings.tsx index 288c425f..42ef2a4d 100644 --- a/src/components/fields/SingleSelect/Settings.tsx +++ b/src/components/fields/SingleSelect/Settings.tsx @@ -42,7 +42,7 @@ export default function Settings({ onChange, config }: ISettingsProps) { const [newOption, setNewOption] = useState(""); /* State for holding Chip Colors for Select and MultiSelect */ - const colors = config.colors ?? {}; + let colors = config.colors ?? {}; const handleAdd = () => { if (newOption.trim() !== "") { @@ -65,8 +65,12 @@ export default function Settings({ onChange, config }: ISettingsProps) { onChange("colors")(Object(colors)); }; - const handleChipColorDelete = (key: string) => { - const _key = key.toLocaleLowerCase(); + const handleItemDelete = (option: string) => { + onChange("options")(options.filter((o: string) => o !== option)); + }; + + const handleItemColorDelete = (option: string) => { + const _key = option.toLocaleLowerCase(); delete colors[_key]; onChange("colors")(Object(colors)); }; @@ -114,6 +118,7 @@ export default function Settings({ onChange, config }: ISettingsProps) { {...provided.dragHandleProps} item sx={{ display: "flex" }} + alignItems="center" > - - - - handleChipColorChange(option, color) - } - /> - {option} - + + + handleChipColorChange(option, color) + } + /> + {option} - onChange("options")( - options.filter((o: string) => o !== option) - ) - } + onClick={() => { + handleItemDelete(option); + //handleItemColorDelete(option); + }} > {} From 78cd3deabf25a725f743d25cd029283ff559903c Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Tue, 7 Mar 2023 23:37:37 +0100 Subject: [PATCH 11/78] Adding logic - but have a blocker on deleting colors alongside deleting options --- .../fields/SingleSelect/Settings.tsx | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/components/fields/SingleSelect/Settings.tsx b/src/components/fields/SingleSelect/Settings.tsx index 42ef2a4d..074116fc 100644 --- a/src/components/fields/SingleSelect/Settings.tsx +++ b/src/components/fields/SingleSelect/Settings.tsx @@ -42,7 +42,7 @@ export default function Settings({ onChange, config }: ISettingsProps) { const [newOption, setNewOption] = useState(""); /* State for holding Chip Colors for Select and MultiSelect */ - let colors = config.colors ?? {}; + const colors = config.colors ?? {}; const handleAdd = () => { if (newOption.trim() !== "") { @@ -57,22 +57,20 @@ export default function Settings({ onChange, config }: ISettingsProps) { }; const handleChipColorChange = ( + type: "save" | "delete", key: string, - color: SelectColorThemeOptions + color?: SelectColorThemeOptions ) => { const _key = key.toLocaleLowerCase(); - colors[_key] = color; - onChange("colors")(Object(colors)); + const { [_key]: _, ...newColors } = colors; + if (type === "save") colors[_key] = color; + else if (type === "delete") return newColors; }; const handleItemDelete = (option: string) => { onChange("options")(options.filter((o: string) => o !== option)); - }; - - const handleItemColorDelete = (option: string) => { - const _key = option.toLocaleLowerCase(); - delete colors[_key]; - onChange("colors")(Object(colors)); + onChange("colors")(handleChipColorChange("delete", option)); + console.log(options, colors); // Here for debugging reasons }; const handleOnDragEnd = (result: any) => { @@ -139,7 +137,7 @@ export default function Settings({ onChange, config }: ISettingsProps) { colors[option.toLocaleLowerCase()] } handleChange={(color) => - handleChipColorChange(option, color) + handleChipColorChange("save", option, color) } /> {option} @@ -148,10 +146,7 @@ export default function Settings({ onChange, config }: ISettingsProps) { { - handleItemDelete(option); - //handleItemColorDelete(option); - }} + onClick={() => handleItemDelete(option)} > {} From 5e9b211ff99b62fdc3ccfcff548e0f9b072fe709 Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Wed, 8 Mar 2023 01:23:43 +0100 Subject: [PATCH 12/78] Fixed error on MultiSelect SideDrawerField --- .../fields/MultiSelect/SideDrawerField.tsx | 6 +++++- src/components/fields/SingleSelect/Settings.tsx | 17 ++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/components/fields/MultiSelect/SideDrawerField.tsx b/src/components/fields/MultiSelect/SideDrawerField.tsx index 4482350f..28ef41e4 100644 --- a/src/components/fields/MultiSelect/SideDrawerField.tsx +++ b/src/components/fields/MultiSelect/SideDrawerField.tsx @@ -77,7 +77,11 @@ export default function MultiSelect({ ) diff --git a/src/components/fields/SingleSelect/Settings.tsx b/src/components/fields/SingleSelect/Settings.tsx index 074116fc..b1d33b56 100644 --- a/src/components/fields/SingleSelect/Settings.tsx +++ b/src/components/fields/SingleSelect/Settings.tsx @@ -38,7 +38,7 @@ const getItemStyle = ( export default function Settings({ onChange, config }: ISettingsProps) { const listEndRef: any = useRef(null); - const options = config.options ?? []; + let options = config.options ?? []; const [newOption, setNewOption] = useState(""); /* State for holding Chip Colors for Select and MultiSelect */ @@ -62,15 +62,13 @@ export default function Settings({ onChange, config }: ISettingsProps) { color?: SelectColorThemeOptions ) => { const _key = key.toLocaleLowerCase(); - const { [_key]: _, ...newColors } = colors; if (type === "save") colors[_key] = color; - else if (type === "delete") return newColors; + else if (type === "delete") delete colors[_key]; + onChange("colors")(colors); }; - const handleItemDelete = (option: string) => { + const handleItemDelete = async (option: string) => { onChange("options")(options.filter((o: string) => o !== option)); - onChange("colors")(handleChipColorChange("delete", option)); - console.log(options, colors); // Here for debugging reasons }; const handleOnDragEnd = (result: any) => { @@ -146,7 +144,12 @@ export default function Settings({ onChange, config }: ISettingsProps) { handleItemDelete(option)} + onClick={() => + handleItemDelete(option).then(() => { + handleChipColorChange("delete", option); + console.log(options, colors); // Here for debugging purposes + }) + } > {} From b0b897efd7a155b8ca080e545622547d081102a5 Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Fri, 10 Mar 2023 00:30:30 +0100 Subject: [PATCH 13/78] Deleting options and colors at the same time --- src/atoms/tableScope/columnActions.ts | 1 + .../ColumnModals/ColumnConfigModal/ColumnConfig.tsx | 3 ++- src/components/fields/SingleSelect/Settings.tsx | 11 +++++------ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/atoms/tableScope/columnActions.ts b/src/atoms/tableScope/columnActions.ts index 2f3926e8..1caf94b9 100644 --- a/src/atoms/tableScope/columnActions.ts +++ b/src/atoms/tableScope/columnActions.ts @@ -100,6 +100,7 @@ export const updateColumnAtom = atom( // Reduce array into single object with updated indexes const updatedColumns = tableColumnsOrdered.reduce(tableColumnsReducer, {}); await updateTableSchema({ columns: updatedColumns }); + console.log(updatedColumns); // Testing Purpose Only @devsgnr } ); diff --git a/src/components/ColumnModals/ColumnConfigModal/ColumnConfig.tsx b/src/components/ColumnModals/ColumnConfigModal/ColumnConfig.tsx index 27665606..39ce7b1d 100644 --- a/src/components/ColumnModals/ColumnConfigModal/ColumnConfig.tsx +++ b/src/components/ColumnModals/ColumnConfigModal/ColumnConfig.tsx @@ -78,8 +78,9 @@ export default function ColumnConfigModal({ ) { setShowRebuildPrompt(true); } - const updatedConfig = set({ ...newConfig }, key, update); + const updatedConfig = set(newConfig, key, update); // Modified by @devsgnr, spread operator `{...newConfig}` instead of just `newConfig` was preventing multiple calls from running properly setNewConfig(updatedConfig); + console.log(updatedConfig); // Testing Purpose Only @devsgnr validateSettings(); }; diff --git a/src/components/fields/SingleSelect/Settings.tsx b/src/components/fields/SingleSelect/Settings.tsx index b1d33b56..bc87d088 100644 --- a/src/components/fields/SingleSelect/Settings.tsx +++ b/src/components/fields/SingleSelect/Settings.tsx @@ -38,11 +38,11 @@ const getItemStyle = ( export default function Settings({ onChange, config }: ISettingsProps) { const listEndRef: any = useRef(null); - let options = config.options ?? []; + const options = config.options ?? []; const [newOption, setNewOption] = useState(""); /* State for holding Chip Colors for Select and MultiSelect */ - const colors = config.colors ?? {}; + let colors = config.colors ?? {}; const handleAdd = () => { if (newOption.trim() !== "") { @@ -145,10 +145,9 @@ export default function Settings({ onChange, config }: ISettingsProps) { - handleItemDelete(option).then(() => { - handleChipColorChange("delete", option); - console.log(options, colors); // Here for debugging purposes - }) + handleItemDelete(option).then( + () => handleChipColorChange("delete", option) //@devsgnr + ) } > {} From 7e8b0ed96cdacec7afdd46e8bf16fcfcd1648a93 Mon Sep 17 00:00:00 2001 From: iamanishroy <6275anishroy@gmail.com> Date: Fri, 10 Mar 2023 13:43:36 +0530 Subject: [PATCH 14/78] import files from URL --- src/atoms/tableScope/rowActions.ts | 13 +- src/components/Table/Mock/Cell.tsx | 2 + src/components/Table/Mock/mockValue/file.ts | 11 ++ src/components/Table/Mock/mockValue/index.ts | 20 +++ .../Table/Mock/mockValue/reference.ts | 12 ++ .../ImportCsvWizard/ImportCsvWizard.tsx | 101 ++++++++++++- .../ImportCsvWizard/useConverter.ts | 49 ++++++ .../ImportCsvWizard/useUploadFileFromURL.tsx | 141 ++++++++++++++++++ .../ImportExistingWizard/Step1Columns.tsx | 6 +- .../TableModals/ImportExistingWizard/utils.ts | 5 + 10 files changed, 354 insertions(+), 6 deletions(-) create mode 100644 src/components/Table/Mock/mockValue/file.ts create mode 100644 src/components/Table/Mock/mockValue/index.ts create mode 100644 src/components/Table/Mock/mockValue/reference.ts create mode 100644 src/components/TableModals/ImportCsvWizard/useConverter.ts create mode 100644 src/components/TableModals/ImportCsvWizard/useUploadFileFromURL.tsx diff --git a/src/atoms/tableScope/rowActions.ts b/src/atoms/tableScope/rowActions.ts index 75b496f5..abf15be0 100644 --- a/src/atoms/tableScope/rowActions.ts +++ b/src/atoms/tableScope/rowActions.ts @@ -242,10 +242,15 @@ export interface IBulkAddRowsOptions { rows: Partial; collection: string; onBatchCommit?: Parameters[1]; + type?: "add"; } export const bulkAddRowsAtom = atom( null, - async (get, _, { rows, collection, onBatchCommit }: IBulkAddRowsOptions) => { + async ( + get, + _, + { rows, collection, onBatchCommit, type }: IBulkAddRowsOptions + ) => { const bulkWriteDb = get(_bulkWriteDbAtom); if (!bulkWriteDb) throw new Error("Cannot write to database"); const tableSettings = get(tableSettingsAtom); @@ -277,7 +282,11 @@ export const bulkAddRowsAtom = atom( // Assign a random ID to each row const operations = rows.map((row) => ({ - type: row?._rowy_ref?.id ? ("update" as "update") : ("add" as "add"), + type: type + ? type + : row?._rowy_ref?.id + ? ("update" as "update") + : ("add" as "add"), path: `${collection}/${row?._rowy_ref?.id ?? generateId()}`, data: { ...initialValues, ...omitRowyFields(row) }, })); diff --git a/src/components/Table/Mock/Cell.tsx b/src/components/Table/Mock/Cell.tsx index 959765a0..cffc2c52 100644 --- a/src/components/Table/Mock/Cell.tsx +++ b/src/components/Table/Mock/Cell.tsx @@ -7,6 +7,7 @@ import EmptyState from "@src/components/EmptyState"; import { FieldType } from "@src/constants/fields"; import { getFieldProp } from "@src/components/fields"; import { DEFAULT_ROW_HEIGHT } from "@src/components/Table"; +import mockValue from "./mockValue"; export interface ICellProps extends Partial< @@ -31,6 +32,7 @@ export default function Cell({ ...props }: ICellProps) { const tableCell = type ? getFieldProp("TableCell", type) : null; + value = mockValue(value, type); return ( diff --git a/src/components/Table/Mock/mockValue/file.ts b/src/components/Table/Mock/mockValue/file.ts new file mode 100644 index 00000000..c606527c --- /dev/null +++ b/src/components/Table/Mock/mockValue/file.ts @@ -0,0 +1,11 @@ +export const fileValueConverter = (value: any) => { + if (!value) return []; + if (Array.isArray(value)) return value; + if (typeof value === "string") { + return value.split(",").map((url) => ({ + downloadURL: url.trim(), + name: +new Date() + "-" + Math.round(Math.random() * 1000), + })); + } + return []; +}; diff --git a/src/components/Table/Mock/mockValue/index.ts b/src/components/Table/Mock/mockValue/index.ts new file mode 100644 index 00000000..fd2fa502 --- /dev/null +++ b/src/components/Table/Mock/mockValue/index.ts @@ -0,0 +1,20 @@ +import { FieldType } from "@src/constants/fields"; +import { fileValueConverter } from "./file"; +import { referenceValueConverter } from "./reference"; + +export const VALUE_CONVERTERS: Partial<{ + [key in FieldType]: (value: any) => any; +}> = { + [FieldType.image]: fileValueConverter, + [FieldType.reference]: referenceValueConverter, + [FieldType.file]: fileValueConverter, +}; + +export default function convert(value: any, type: FieldType) { + const converter = VALUE_CONVERTERS[type]; + if (converter) { + return converter(value); + } + + return value; +} diff --git a/src/components/Table/Mock/mockValue/reference.ts b/src/components/Table/Mock/mockValue/reference.ts new file mode 100644 index 00000000..ffab1b0f --- /dev/null +++ b/src/components/Table/Mock/mockValue/reference.ts @@ -0,0 +1,12 @@ +export const referenceValueConverter = (value: any) => { + if (typeof value === "string") { + if ( + value !== "" && + value.split("/").length > 0 && + value.split("/").length % 2 === 0 + ) { + return { path: value }; + } + } + return value; +}; diff --git a/src/components/TableModals/ImportCsvWizard/ImportCsvWizard.tsx b/src/components/TableModals/ImportCsvWizard/ImportCsvWizard.tsx index b40e0e8c..551b69ec 100644 --- a/src/components/TableModals/ImportCsvWizard/ImportCsvWizard.tsx +++ b/src/components/TableModals/ImportCsvWizard/ImportCsvWizard.tsx @@ -37,7 +37,11 @@ import { import { ColumnConfig } from "@src/types/table"; import { getFieldProp } from "@src/components/fields"; import { analytics, logEvent } from "@src/analytics"; +import { FieldType } from "@src/constants/fields"; +import { generateId } from "@src/utils/table"; import { isValidDocId } from "./utils"; +import useUploadFileFromURL from "./useUploadFileFromURL"; +import useConverter from "./useConverter"; export type CsvConfig = { pairs: { csvKey: string; columnKey: string }[]; @@ -46,6 +50,8 @@ export type CsvConfig = { documentIdCsvKey: string | null; }; +const needsUploadTypes = [FieldType.image, FieldType.file]; + export interface IStepProps { csvData: NonNullable; config: CsvConfig; @@ -66,6 +72,10 @@ export default function ImportCsvWizard({ onClose }: ITableModalProps) { const isXs = useMediaQuery(theme.breakpoints.down("sm")); const snackbarProgressRef = useRef(); + const snackbarUploadProgressRef = useRef(); + const { addTask, runBatchUpload, askPermission } = useUploadFileFromURL(); + const { needsConverter, getConverter } = useConverter(); + const columns = useMemoValue(tableSchema.columns ?? {}, isEqual); const [config, setConfig] = useState({ @@ -74,6 +84,7 @@ export default function ImportCsvWizard({ onClose }: ITableModalProps) { documentId: "auto", documentIdCsvKey: null, }); + const updateConfig: IStepProps["updateConfig"] = useCallback((value) => { setConfig((prev) => { const pairs = uniqBy([...prev.pairs, ...(value.pairs ?? [])], "csvKey"); @@ -123,6 +134,35 @@ export default function ImportCsvWizard({ onClose }: ITableModalProps) { ) : { validRows: parsedRows, invalidRows: [] }; + const { requiredConverts, requiredUploads } = useMemo(() => { + const columns = config.pairs.map(({ csvKey, columnKey }) => ({ + csvKey, + columnKey, + ...(tableSchema.columns?.[columnKey] ?? + find(config.newColumns, { key: columnKey }) ?? + {}), + })); + + let requiredConverts: any = {}; + let requiredUploads: any = {}; + columns.forEach((column, index) => { + if (needsConverter(column.type)) { + requiredConverts[index] = getConverter(column.type); + console.log({ needsUploadTypes }, column.type); + if (needsUploadTypes.includes(column.type)) { + requiredUploads[column.fieldName + ""] = true; + } + } + }); + return { requiredConverts, requiredUploads }; + }, [ + config.newColumns, + config.pairs, + getConverter, + needsConverter, + tableSchema.columns, + ]); + const handleFinish = async () => { if (!parsedRows) return; console.time("importCsv"); @@ -176,12 +216,48 @@ export default function ImportCsvWizard({ onClose }: ITableModalProps) { { variant: "warning" } ); } + const newValidRows = validRows.map((row) => { + // Convert required values + Object.keys(row).forEach((key, i) => { + if (requiredConverts[i]) { + row[key] = requiredConverts[i](row[key]); + } + }); + + const id = generateId(); + const newRow = { + _rowy_ref: { + path: `${tableSettings.collection}/${row?._rowy_ref?.id ?? id}`, + id, + }, + ...row, + }; + return newRow; + }); + promises.push( bulkAddRows({ - rows: validRows, + type: "add", + rows: newValidRows, collection: tableSettings.collection, - onBatchCommit: (batchNumber: number) => - snackbarProgressRef.current?.setProgress(batchNumber), + onBatchCommit: async (batchNumber: number) => { + if (Object.keys(requiredUploads).length > 0) { + newValidRows + .slice((batchNumber - 1) * 500, batchNumber * 500 - 1) + .forEach((row) => { + Object.keys(requiredUploads).forEach((key) => { + if (requiredUploads[key]) { + addTask({ + docRef: row._rowy_ref, + fieldName: key, + files: row[key], + }); + } + }); + }); + } + snackbarProgressRef.current?.setProgress(batchNumber); + }, }) ); @@ -192,6 +268,25 @@ export default function ImportCsvWizard({ onClose }: ITableModalProps) { `Imported ${Number(validRows.length).toLocaleString()} rows`, { variant: "success" } ); + if (await askPermission()) { + const uploadingSnackbar = enqueueSnackbar( + `Importing ${Number( + validRows.length + ).toLocaleString()} rows. This might take a while.`, + { + persist: true, + action: ( + + ), + } + ); + await runBatchUpload(snackbarUploadProgressRef.current?.setProgress); + closeSnackbar(uploadingSnackbar); + } } catch (e) { enqueueSnackbar((e as Error).message, { variant: "error" }); } finally { diff --git a/src/components/TableModals/ImportCsvWizard/useConverter.ts b/src/components/TableModals/ImportCsvWizard/useConverter.ts new file mode 100644 index 00000000..33314137 --- /dev/null +++ b/src/components/TableModals/ImportCsvWizard/useConverter.ts @@ -0,0 +1,49 @@ +import { projectScope } from "@src/atoms/projectScope"; +import { FieldType } from "@src/constants/fields"; +import { firebaseDbAtom } from "@src/sources/ProjectSourceFirebase"; +import { doc, DocumentReference as Reference } from "firebase/firestore"; +import { useAtom } from "jotai"; + +const needsConverter = (type: FieldType) => + [FieldType.image, FieldType.reference, FieldType.file].includes(type); + +export default function useConverter() { + const [firebaseDb] = useAtom(firebaseDbAtom, projectScope); + + const referenceConverter = (value: string): Reference | null => { + if (!value) return null; + if (value.split("/").length % 2 !== 0) return null; + return doc(firebaseDb, value); + }; + + const imageOrFileConverter = (urls: string): RowyFile[] => { + return urls.split(",").map((url) => { + url = url.trim(); + return { + downloadURL: url, + name: url.split("/").pop() || "", + lastModifiedTS: +new Date(), + type: "", + }; + }); + }; + + const getConverter = (type: FieldType) => { + switch (type) { + case FieldType.image: + case FieldType.file: + return imageOrFileConverter; + case FieldType.reference: + return referenceConverter; + default: + return null; + } + }; + + return { + needsConverter, + referenceConverter, + imageOrFileConverter, + getConverter, + }; +} diff --git a/src/components/TableModals/ImportCsvWizard/useUploadFileFromURL.tsx b/src/components/TableModals/ImportCsvWizard/useUploadFileFromURL.tsx new file mode 100644 index 00000000..b5fb7511 --- /dev/null +++ b/src/components/TableModals/ImportCsvWizard/useUploadFileFromURL.tsx @@ -0,0 +1,141 @@ +import { useCallback, useRef } from "react"; +import { useSetAtom } from "jotai"; +import { useSnackbar } from "notistack"; +import Button from "@mui/material/Button"; + +import useUploader from "@src/hooks/useFirebaseStorageUploader"; +import { tableScope, updateFieldAtom } from "@src/atoms/tableScope"; +import { TableRowRef } from "@src/types/table"; + +const MAX_PARALLEL_TASKS = 30; + +type UploadParamTypes = { + docRef: TableRowRef; + fieldName: string; + files: RowyFile[]; +}; + +export default function useUploadFileFromURL() { + const { upload } = useUploader(); + const updateField = useSetAtom(updateFieldAtom, tableScope); + const { enqueueSnackbar, closeSnackbar } = useSnackbar(); + const jobs = useRef([]); + + const askPermission = useCallback(async (): Promise => { + return new Promise((resolve) => { + enqueueSnackbar("Upload files to firebase storage?", { + persist: true, + preventDuplicate: true, + action: ( + <> + + + + ), + }); + }); + }, [enqueueSnackbar, closeSnackbar]); + + const handleUpload = useCallback( + async ({ + docRef, + fieldName, + files, + }: UploadParamTypes): Promise => { + try { + const files_ = await getFileFromURL( + files.map((file) => file.downloadURL) + ); + const { uploads, failures } = await upload({ + docRef, + fieldName, + files: files_, + }); + if (failures.length > 0) { + return false; + } + updateField({ + path: docRef.path, + fieldName, + value: uploads, + useArrayUnion: false, + }); + return true; + } catch (error) { + return false; + } + }, + [upload, updateField] + ); + + const batchUpload = useCallback( + async (batch: UploadParamTypes[]) => { + await Promise.all(batch.map((job) => handleUpload(job))); + }, + [handleUpload] + ); + + const runBatchUpload = useCallback( + async (setProgress?: any) => { + let currentJobs: UploadParamTypes[] = []; + + while ( + currentJobs.length < MAX_PARALLEL_TASKS && + jobs.current.length > 0 + ) { + const job = jobs.current.shift(); + if (job) { + currentJobs.push(job); + } + } + + if (setProgress) setProgress((p: number) => p + currentJobs.length); + await batchUpload(currentJobs); + + if (jobs.current.length > 0) { + runBatchUpload(); + } + }, + [batchUpload] + ); + + const addTask = useCallback((job: UploadParamTypes) => { + jobs.current.push(job); + }, []); + + return { + addTask, + runBatchUpload, + askPermission, + }; +} + +function getFileFromURL(urls: string[]): Promise { + const promises = urls.map((url) => { + return fetch(url) + .then((response) => response.blob()) + .then((blob) => new File([blob], +new Date() + url, { type: blob.type })); + }); + return Promise.all(promises); +} diff --git a/src/components/TableModals/ImportExistingWizard/Step1Columns.tsx b/src/components/TableModals/ImportExistingWizard/Step1Columns.tsx index c5d83299..dc339687 100644 --- a/src/components/TableModals/ImportExistingWizard/Step1Columns.tsx +++ b/src/components/TableModals/ImportExistingWizard/Step1Columns.tsx @@ -117,7 +117,11 @@ export default function Step1Columns({ config, setConfig }: IStepProps) { color="default" /> } - label={selectedFields.length == allFields.length ? "Clear all" : "Select all"} + label={ + selectedFields.length === allFields.length + ? "Clear all" + : "Select all" + } sx={{ height: 42, mr: 0, diff --git a/src/components/TableModals/ImportExistingWizard/utils.ts b/src/components/TableModals/ImportExistingWizard/utils.ts index d855da03..ec6ad97d 100644 --- a/src/components/TableModals/ImportExistingWizard/utils.ts +++ b/src/components/TableModals/ImportExistingWizard/utils.ts @@ -18,6 +18,9 @@ export const SELECTABLE_TYPES = [ FieldType.url, FieldType.rating, + FieldType.image, + FieldType.file, + FieldType.singleSelect, FieldType.multiSelect, @@ -26,6 +29,8 @@ export const SELECTABLE_TYPES = [ FieldType.color, FieldType.slider, + + FieldType.reference, ]; export const REGEX_EMAIL = From 2a04ee1bd2a33d8bf3a409afbbc1757a5db8dbfa Mon Sep 17 00:00:00 2001 From: iamanishroy <6275anishroy@gmail.com> Date: Fri, 10 Mar 2023 14:06:09 +0530 Subject: [PATCH 15/78] bug fixes and added progress on snackbar --- src/components/Table/Mock/mockValue/file.ts | 17 +++- .../ImportCsvWizard/ImportCsvWizard.tsx | 24 +----- .../ImportCsvWizard/useConverter.ts | 29 ++++--- .../ImportCsvWizard/useUploadFileFromURL.tsx | 81 +++++++++++++------ .../TableToolbar/ImportData/ImportFromCsv.tsx | 2 +- 5 files changed, 94 insertions(+), 59 deletions(-) diff --git a/src/components/Table/Mock/mockValue/file.ts b/src/components/Table/Mock/mockValue/file.ts index c606527c..990db340 100644 --- a/src/components/Table/Mock/mockValue/file.ts +++ b/src/components/Table/Mock/mockValue/file.ts @@ -2,10 +2,19 @@ export const fileValueConverter = (value: any) => { if (!value) return []; if (Array.isArray(value)) return value; if (typeof value === "string") { - return value.split(",").map((url) => ({ - downloadURL: url.trim(), - name: +new Date() + "-" + Math.round(Math.random() * 1000), - })); + return value + .split(",") + .map((url) => { + url = url.trim(); + if (url !== "") { + return { + downloadURL: url, + name: +new Date() + "-" + Math.round(Math.random() * 1000), + }; + } + return null; + }) + .filter((mockValue) => mockValue !== null); } return []; }; diff --git a/src/components/TableModals/ImportCsvWizard/ImportCsvWizard.tsx b/src/components/TableModals/ImportCsvWizard/ImportCsvWizard.tsx index 551b69ec..421fbc30 100644 --- a/src/components/TableModals/ImportCsvWizard/ImportCsvWizard.tsx +++ b/src/components/TableModals/ImportCsvWizard/ImportCsvWizard.tsx @@ -71,8 +71,6 @@ export default function ImportCsvWizard({ onClose }: ITableModalProps) { const theme = useTheme(); const isXs = useMediaQuery(theme.breakpoints.down("sm")); const snackbarProgressRef = useRef(); - - const snackbarUploadProgressRef = useRef(); const { addTask, runBatchUpload, askPermission } = useUploadFileFromURL(); const { needsConverter, getConverter } = useConverter(); @@ -148,7 +146,7 @@ export default function ImportCsvWizard({ onClose }: ITableModalProps) { columns.forEach((column, index) => { if (needsConverter(column.type)) { requiredConverts[index] = getConverter(column.type); - console.log({ needsUploadTypes }, column.type); + // console.log({ needsUploadTypes }, column.type); if (needsUploadTypes.includes(column.type)) { requiredUploads[column.fieldName + ""] = true; } @@ -268,24 +266,8 @@ export default function ImportCsvWizard({ onClose }: ITableModalProps) { `Imported ${Number(validRows.length).toLocaleString()} rows`, { variant: "success" } ); - if (await askPermission()) { - const uploadingSnackbar = enqueueSnackbar( - `Importing ${Number( - validRows.length - ).toLocaleString()} rows. This might take a while.`, - { - persist: true, - action: ( - - ), - } - ); - await runBatchUpload(snackbarUploadProgressRef.current?.setProgress); - closeSnackbar(uploadingSnackbar); + if (Object.keys(requiredUploads).length && (await askPermission())) { + await runBatchUpload(); } } catch (e) { enqueueSnackbar((e as Error).message, { variant: "error" }); diff --git a/src/components/TableModals/ImportCsvWizard/useConverter.ts b/src/components/TableModals/ImportCsvWizard/useConverter.ts index 33314137..dba43aaa 100644 --- a/src/components/TableModals/ImportCsvWizard/useConverter.ts +++ b/src/components/TableModals/ImportCsvWizard/useConverter.ts @@ -17,15 +17,26 @@ export default function useConverter() { }; const imageOrFileConverter = (urls: string): RowyFile[] => { - return urls.split(",").map((url) => { - url = url.trim(); - return { - downloadURL: url, - name: url.split("/").pop() || "", - lastModifiedTS: +new Date(), - type: "", - }; - }); + if (!urls) return []; + if (typeof urls === "string") { + return urls + .split(",") + .map((url) => { + url = url.trim(); + if (url !== "") { + return { + downloadURL: url, + name: url.split("/").pop() || "", + lastModifiedTS: +new Date(), + type: "", + }; + } + + return null; + }) + .filter((val) => val !== null) as RowyFile[]; + } + return []; }; const getConverter = (type: FieldType) => { diff --git a/src/components/TableModals/ImportCsvWizard/useUploadFileFromURL.tsx b/src/components/TableModals/ImportCsvWizard/useUploadFileFromURL.tsx index b5fb7511..d6727a0a 100644 --- a/src/components/TableModals/ImportCsvWizard/useUploadFileFromURL.tsx +++ b/src/components/TableModals/ImportCsvWizard/useUploadFileFromURL.tsx @@ -1,13 +1,14 @@ import { useCallback, useRef } from "react"; import { useSetAtom } from "jotai"; -import { useSnackbar } from "notistack"; +import { SnackbarKey, useSnackbar } from "notistack"; import Button from "@mui/material/Button"; import useUploader from "@src/hooks/useFirebaseStorageUploader"; import { tableScope, updateFieldAtom } from "@src/atoms/tableScope"; import { TableRowRef } from "@src/types/table"; +import SnackbarProgress from "@src/components/SnackbarProgress"; -const MAX_PARALLEL_TASKS = 30; +const MAX_CONCURRENT_TASKS = 10; type UploadParamTypes = { docRef: TableRowRef; @@ -75,7 +76,7 @@ export default function useUploadFileFromURL() { if (failures.length > 0) { return false; } - updateField({ + await updateField({ path: docRef.path, fieldName, value: uploads, @@ -91,35 +92,67 @@ export default function useUploadFileFromURL() { const batchUpload = useCallback( async (batch: UploadParamTypes[]) => { - await Promise.all(batch.map((job) => handleUpload(job))); + await Promise.all( + batch.map((job) => + handleUpload(job).then(() => { + snackbarProgressRef.current?.setProgress((p: number) => p + 1); + }) + ) + ); }, [handleUpload] ); - const runBatchUpload = useCallback( - async (setProgress?: any) => { - let currentJobs: UploadParamTypes[] = []; - - while ( - currentJobs.length < MAX_PARALLEL_TASKS && - jobs.current.length > 0 - ) { - const job = jobs.current.shift(); - if (job) { - currentJobs.push(job); + const snackbarProgressRef = useRef(null); + const snackbarProgressId = useRef(null); + const showProgress = useCallback( + (totalJobs: number) => { + snackbarProgressId.current = enqueueSnackbar( + `Uploading ${Number( + totalJobs + ).toLocaleString()} files/images. This might take a while.`, + { + persist: true, + action: ( + + ), } - } - - if (setProgress) setProgress((p: number) => p + currentJobs.length); - await batchUpload(currentJobs); - - if (jobs.current.length > 0) { - runBatchUpload(); - } + ); }, - [batchUpload] + [enqueueSnackbar] ); + const runBatchUpload = useCallback(async () => { + if (!snackbarProgressId.current) { + showProgress(jobs.current.length); + } + let currentJobs: UploadParamTypes[] = []; + + while ( + currentJobs.length < MAX_CONCURRENT_TASKS && + jobs.current.length > 0 + ) { + const job = jobs.current.shift(); + if (job) { + currentJobs.push(job); + } + } + + await batchUpload(currentJobs); + + if (jobs.current.length > 0) { + await runBatchUpload(); + } + + if (snackbarProgressId.current) { + closeSnackbar(snackbarProgressId.current); + } + }, [batchUpload, closeSnackbar, showProgress, snackbarProgressId]); + const addTask = useCallback((job: UploadParamTypes) => { jobs.current.push(job); }, []); diff --git a/src/components/TableToolbar/ImportData/ImportFromCsv.tsx b/src/components/TableToolbar/ImportData/ImportFromCsv.tsx index f164f90a..269f306d 100644 --- a/src/components/TableToolbar/ImportData/ImportFromCsv.tsx +++ b/src/components/TableToolbar/ImportData/ImportFromCsv.tsx @@ -162,7 +162,7 @@ export default function ImportFromFile() { {} ) ); - console.log(mappedRows); + // console.log(mappedRows); setImportCsv({ importType: importTypeRef.current, csvData: { columns, rows: mappedRows }, From 4e92dd39b005a18490161ddef160b2cea05f9dc6 Mon Sep 17 00:00:00 2001 From: Anish Roy <6275anishroy@gmail.com> Date: Fri, 10 Mar 2023 14:38:26 +0530 Subject: [PATCH 16/78] made one function for converter --- src/components/Table/Mock/Cell.tsx | 8 ++++---- src/components/Table/Mock/mockValue/file.ts | 20 ------------------- src/components/Table/Mock/mockValue/index.ts | 20 ------------------- .../Table/Mock/mockValue/reference.ts | 12 ----------- .../ImportCsvWizard/useConverter.ts | 9 +++++++++ 5 files changed, 13 insertions(+), 56 deletions(-) delete mode 100644 src/components/Table/Mock/mockValue/file.ts delete mode 100644 src/components/Table/Mock/mockValue/index.ts delete mode 100644 src/components/Table/Mock/mockValue/reference.ts diff --git a/src/components/Table/Mock/Cell.tsx b/src/components/Table/Mock/Cell.tsx index cffc2c52..7d6f501b 100644 --- a/src/components/Table/Mock/Cell.tsx +++ b/src/components/Table/Mock/Cell.tsx @@ -7,7 +7,7 @@ import EmptyState from "@src/components/EmptyState"; import { FieldType } from "@src/constants/fields"; import { getFieldProp } from "@src/components/fields"; import { DEFAULT_ROW_HEIGHT } from "@src/components/Table"; -import mockValue from "./mockValue"; +import useConverter from "@src/components/TableModals/ImportCsvWizard/useConverter"; export interface ICellProps extends Partial< @@ -26,14 +26,14 @@ export interface ICellProps export default function Cell({ field, type, - value, + value: value_, name, rowHeight = DEFAULT_ROW_HEIGHT, ...props }: ICellProps) { const tableCell = type ? getFieldProp("TableCell", type) : null; - value = mockValue(value, type); - + const { checkAndConvert } = useConverter(); + const value = checkAndConvert(value_, type); return ( { - if (!value) return []; - if (Array.isArray(value)) return value; - if (typeof value === "string") { - return value - .split(",") - .map((url) => { - url = url.trim(); - if (url !== "") { - return { - downloadURL: url, - name: +new Date() + "-" + Math.round(Math.random() * 1000), - }; - } - return null; - }) - .filter((mockValue) => mockValue !== null); - } - return []; -}; diff --git a/src/components/Table/Mock/mockValue/index.ts b/src/components/Table/Mock/mockValue/index.ts deleted file mode 100644 index fd2fa502..00000000 --- a/src/components/Table/Mock/mockValue/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { FieldType } from "@src/constants/fields"; -import { fileValueConverter } from "./file"; -import { referenceValueConverter } from "./reference"; - -export const VALUE_CONVERTERS: Partial<{ - [key in FieldType]: (value: any) => any; -}> = { - [FieldType.image]: fileValueConverter, - [FieldType.reference]: referenceValueConverter, - [FieldType.file]: fileValueConverter, -}; - -export default function convert(value: any, type: FieldType) { - const converter = VALUE_CONVERTERS[type]; - if (converter) { - return converter(value); - } - - return value; -} diff --git a/src/components/Table/Mock/mockValue/reference.ts b/src/components/Table/Mock/mockValue/reference.ts deleted file mode 100644 index ffab1b0f..00000000 --- a/src/components/Table/Mock/mockValue/reference.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const referenceValueConverter = (value: any) => { - if (typeof value === "string") { - if ( - value !== "" && - value.split("/").length > 0 && - value.split("/").length % 2 === 0 - ) { - return { path: value }; - } - } - return value; -}; diff --git a/src/components/TableModals/ImportCsvWizard/useConverter.ts b/src/components/TableModals/ImportCsvWizard/useConverter.ts index dba43aaa..34a9d4f0 100644 --- a/src/components/TableModals/ImportCsvWizard/useConverter.ts +++ b/src/components/TableModals/ImportCsvWizard/useConverter.ts @@ -51,10 +51,19 @@ export default function useConverter() { } }; + const checkAndConvert = (value: any, type: FieldType) => { + if (needsConverter(type)) { + const converter = getConverter(type); + if (converter) return converter(value); + } + return value; + }; + return { needsConverter, referenceConverter, imageOrFileConverter, getConverter, + checkAndConvert, }; } From dd02ea1811f13b57547870008d89788b84af56eb Mon Sep 17 00:00:00 2001 From: Anish Roy <6275anishroy@gmail.com> Date: Fri, 10 Mar 2023 15:46:09 +0530 Subject: [PATCH 17/78] export image/ file with JSON --- src/components/Table/Mock/Cell.tsx | 1 + .../ExportModal/ModalContentsExport.tsx | 15 +++++++++++++++ .../TableModals/ImportCsvWizard/useConverter.ts | 3 ++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/components/Table/Mock/Cell.tsx b/src/components/Table/Mock/Cell.tsx index 7d6f501b..0944d3a9 100644 --- a/src/components/Table/Mock/Cell.tsx +++ b/src/components/Table/Mock/Cell.tsx @@ -34,6 +34,7 @@ export default function Cell({ const tableCell = type ? getFieldProp("TableCell", type) : null; const { checkAndConvert } = useConverter(); const value = checkAndConvert(value_, type); + return ( (accumulator: Record, currentColumn: ColumnConfig) => { const value = get(doc, currentColumn.key); + + if ( + currentColumn.type === FieldType.file || + currentColumn.type === FieldType.image + ) { + return { + ...accumulator, + [currentColumn.key]: value + ? value + .map((item: { downloadURL: string }) => item.downloadURL) + .join() + : "", + }; + } + return { ...accumulator, [currentColumn.key]: value, diff --git a/src/components/TableModals/ImportCsvWizard/useConverter.ts b/src/components/TableModals/ImportCsvWizard/useConverter.ts index 34a9d4f0..34593f97 100644 --- a/src/components/TableModals/ImportCsvWizard/useConverter.ts +++ b/src/components/TableModals/ImportCsvWizard/useConverter.ts @@ -16,8 +16,9 @@ export default function useConverter() { return doc(firebaseDb, value); }; - const imageOrFileConverter = (urls: string): RowyFile[] => { + const imageOrFileConverter = (urls: any): RowyFile[] => { if (!urls) return []; + if (Array.isArray(urls)) return urls; if (typeof urls === "string") { return urls .split(",") From aa5e4c00296ebe6dc41746c8fe5eeb22c27238b6 Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Mon, 13 Mar 2023 02:41:40 +0100 Subject: [PATCH 18/78] Made UI fixes on the color select context menu; Grid issue --- src/components/SelectColors/index.tsx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/components/SelectColors/index.tsx b/src/components/SelectColors/index.tsx index 4adbc67b..1c225901 100644 --- a/src/components/SelectColors/index.tsx +++ b/src/components/SelectColors/index.tsx @@ -20,7 +20,7 @@ interface IColorSelect { } const ColorSelect: FC = ({ handleChange, initialValue }) => { - /* Get current */ + /* Get current theme */ const theme = useTheme(); const mode = theme.palette.mode; @@ -38,6 +38,8 @@ const ColorSelect: FC = ({ handleChange, initialValue }) => { cyan: palette.cyan, amber: palette.amber, lightGreen: palette.lightGreen, + lightBlue: palette.lightBlue, + violet: palette.violet, }); /* Hold the current state of a given option defaults to `gray` from the color palette */ @@ -117,9 +119,17 @@ const ColorSelect: FC = ({ handleChange, initialValue }) => { COLOURS - + {Object.keys(palettes).map((key: string, index: number) => ( - + From 60dd1874939d9445c7aedbda152a62fbe9f34420 Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Wed, 15 Mar 2023 11:01:22 +0100 Subject: [PATCH 26/78] Implemented the generalized solution with backwards compatibility --- src/components/FormattedChip.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/FormattedChip.tsx b/src/components/FormattedChip.tsx index 876a5215..c7980427 100644 --- a/src/components/FormattedChip.tsx +++ b/src/components/FormattedChip.tsx @@ -10,7 +10,8 @@ const paletteColor = { no: paletteToMui(palette.aRed), } as const; -// TODO: Create a more generalised solution for this +// Switched to a more generalized solution - adding backwards compatibility to maintain [Yes, No, Maybe] colors even if no color is selected +// Modified by @devsgnr export default function FormattedChip(props: ChipProps) { const defaultColor = paletteToMui(palette.aGray); const { mode } = useTheme().palette; From cf25f7c4b65b0cc3a336cb5734a235fac193d437 Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Wed, 15 Mar 2023 11:19:45 +0100 Subject: [PATCH 27/78] Fixed SideDrawerChips --- src/components/FormattedChip.tsx | 3 ++- src/components/fields/MultiSelect/SideDrawerField.tsx | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/components/FormattedChip.tsx b/src/components/FormattedChip.tsx index c7980427..97946dff 100644 --- a/src/components/FormattedChip.tsx +++ b/src/components/FormattedChip.tsx @@ -16,6 +16,7 @@ export default function FormattedChip(props: ChipProps) { const defaultColor = paletteToMui(palette.aGray); const { mode } = useTheme().palette; const fallback = { backgroundColor: defaultColor[mode] }; + const { sx, ...newProps } = props; const label = typeof props.label === "string" ? props.label.toLowerCase() : ""; @@ -24,7 +25,6 @@ export default function FormattedChip(props: ChipProps) { return ( ); } diff --git a/src/components/fields/MultiSelect/SideDrawerField.tsx b/src/components/fields/MultiSelect/SideDrawerField.tsx index 28ef41e4..8cdaf330 100644 --- a/src/components/fields/MultiSelect/SideDrawerField.tsx +++ b/src/components/fields/MultiSelect/SideDrawerField.tsx @@ -7,6 +7,8 @@ import FormattedChip from "@src/components/FormattedChip"; import { fieldSx } from "@src/components/SideDrawer/utils"; import { sanitiseValue } from "./utils"; +import { getColors } from "@src/components/fields/SingleSelect/Settings"; +import palette, { paletteToMui } from "@src/theme/palette"; export default function MultiSelect({ column, @@ -15,8 +17,9 @@ export default function MultiSelect({ onSubmit, disabled, }: ISideDrawerFieldProps) { + const defaultColor = paletteToMui(palette.aGray); const config = column.config ?? {}; - const colors = column.config?.colors ?? {}; + const colors = column.config?.colors ?? []; const { mode } = useTheme().palette; const handleDelete = (index: number) => () => { @@ -79,8 +82,7 @@ export default function MultiSelect({ onDelete={disabled ? undefined : handleDelete(i)} sx={{ backgroundColor: - colors[item.toLowerCase()] && - colors[item.toLowerCase()][mode], + getColors(colors, item)[mode] || defaultColor[mode], }} /> From 8ecae1060e93de7d23d9cfd8a432fddd9ff253b8 Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Thu, 16 Mar 2023 17:34:51 +0100 Subject: [PATCH 28/78] Changed the short-circuit to a tenary on SingleSelect Chip --- src/components/fields/SingleSelect/DisplayCell.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/fields/SingleSelect/DisplayCell.tsx b/src/components/fields/SingleSelect/DisplayCell.tsx index 6c95922f..6b5e5911 100644 --- a/src/components/fields/SingleSelect/DisplayCell.tsx +++ b/src/components/fields/SingleSelect/DisplayCell.tsx @@ -35,8 +35,9 @@ export default function SingleSelect({ size="small" label={sanitiseValue(value)} sx={{ - backgroundColor: - (value && getColors(colors, value)[mode]) || defaultColor[mode], + backgroundColor: sanitiseValue(value) + ? getColors(colors, value)[mode] + : defaultColor[mode], }} /> )} From a35e5d652473f2cc02cf093ab9270d65b6a25fd3 Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Thu, 16 Mar 2023 19:22:20 +0100 Subject: [PATCH 29/78] Stripped away null check and move them into getColors function - attempting to fix and error --- src/components/fields/MultiSelect/DisplayCell.tsx | 5 +---- src/components/fields/SingleSelect/DisplayCell.tsx | 6 +----- src/components/fields/SingleSelect/Settings.tsx | 5 ++++- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/components/fields/MultiSelect/DisplayCell.tsx b/src/components/fields/MultiSelect/DisplayCell.tsx index a8614651..457e1e28 100644 --- a/src/components/fields/MultiSelect/DisplayCell.tsx +++ b/src/components/fields/MultiSelect/DisplayCell.tsx @@ -7,7 +7,6 @@ import { ChevronDown } from "@src/assets/icons"; import { sanitiseValue } from "./utils"; import ChipList from "@src/components/Table/TableCell/ChipList"; import FormattedChip from "@src/components/FormattedChip"; -import palette, { paletteToMui } from "@src/theme/palette"; import { getColors, IColors, @@ -21,7 +20,6 @@ export default function MultiSelect({ rowHeight, column, }: IDisplayCellProps) { - const defaultColor = paletteToMui(palette.aGray); const colors: IColors[] = column?.config?.colors ?? []; const { mode } = useTheme().palette; @@ -43,8 +41,7 @@ export default function MultiSelect({ diff --git a/src/components/fields/SingleSelect/DisplayCell.tsx b/src/components/fields/SingleSelect/DisplayCell.tsx index 6b5e5911..498a7926 100644 --- a/src/components/fields/SingleSelect/DisplayCell.tsx +++ b/src/components/fields/SingleSelect/DisplayCell.tsx @@ -5,7 +5,6 @@ import { ChevronDown } from "@src/assets/icons"; import { useTheme } from "@mui/material"; import { sanitiseValue } from "./utils"; -import palette, { paletteToMui } from "@src/theme/palette"; import ChipList from "@src/components/Table/TableCell/ChipList"; import { getColors, IColors } from "./Settings"; @@ -17,7 +16,6 @@ export default function SingleSelect({ column, rowHeight, }: IDisplayCellProps) { - const defaultColor = paletteToMui(palette.aGray); const colors: IColors[] = column?.config?.colors ?? []; const { mode } = useTheme().palette; @@ -35,9 +33,7 @@ export default function SingleSelect({ size="small" label={sanitiseValue(value)} sx={{ - backgroundColor: sanitiseValue(value) - ? getColors(colors, value)[mode] - : defaultColor[mode], + backgroundColor: getColors(colors, value)[mode], }} /> )} diff --git a/src/components/fields/SingleSelect/Settings.tsx b/src/components/fields/SingleSelect/Settings.tsx index 45985da2..41766598 100644 --- a/src/components/fields/SingleSelect/Settings.tsx +++ b/src/components/fields/SingleSelect/Settings.tsx @@ -41,7 +41,10 @@ export interface IColors extends SelectColorThemeOptions { name: string; } -export const getColors = (list: IColors[], option: string) => { +export const getColors = ( + list: IColors[], + option: string +): SelectColorThemeOptions => { const defaultColor = paletteToMui(palette.aGray); const key = option.toLocaleLowerCase().replace(" ", "_").trim(); const color = list.find((opt: IColors) => opt.name === key); From d03e62fd565bb09f3e07c2fc786db9f45fc0bc9b Mon Sep 17 00:00:00 2001 From: Emmanuel Watila Date: Fri, 17 Mar 2023 10:36:16 +0100 Subject: [PATCH 30/78] Verified null checker --- src/components/fields/SingleSelect/Settings.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/fields/SingleSelect/Settings.tsx b/src/components/fields/SingleSelect/Settings.tsx index 41766598..b8ee6b5f 100644 --- a/src/components/fields/SingleSelect/Settings.tsx +++ b/src/components/fields/SingleSelect/Settings.tsx @@ -48,7 +48,7 @@ export const getColors = ( const defaultColor = paletteToMui(palette.aGray); const key = option.toLocaleLowerCase().replace(" ", "_").trim(); const color = list.find((opt: IColors) => opt.name === key); - + // Null check in return return color || defaultColor; }; From aded1f795994547f68aebed94888c1034903ddf0 Mon Sep 17 00:00:00 2001 From: Han Tuerker <46192266+htuerker@users.noreply.github.com> Date: Mon, 20 Mar 2023 21:20:39 +0100 Subject: [PATCH 31/78] add set rowy run guard when update roles --- src/components/Settings/UserManagement/UserItem.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/components/Settings/UserManagement/UserItem.tsx b/src/components/Settings/UserManagement/UserItem.tsx index 3b9d2701..b4a53d5d 100644 --- a/src/components/Settings/UserManagement/UserItem.tsx +++ b/src/components/Settings/UserManagement/UserItem.tsx @@ -46,15 +46,18 @@ export default function UserItem({ const [value, setValue] = useState(Array.isArray(rolesProp) ? rolesProp : []); const allRoles = new Set(["ADMIN", ...(projectRoles ?? []), ...value]); + const hasRowyRun = !!projectSettings.rowyRunUrl; const handleSave = async () => { + if (!hasRowyRun) { + openRowyRunModal({ feature: "User Management" }); + return; + } try { if (!user) throw new Error("User is not defined"); if (JSON.stringify(value) === JSON.stringify(rolesProp)) return; - const loadingSnackbarId = enqueueSnackbar("Setting roles…"); - - const res = await rowyRun?.({ + const res = await rowyRun({ route: runRoutes.setUserRoles, body: { email: user!.email, roles: value }, }); @@ -91,7 +94,7 @@ export default function UserItem({ ); const handleDelete = async () => { - if (!projectSettings.rowyRunUrl) { + if (!hasRowyRun) { openRowyRunModal({ feature: "User Management" }); return; } From e7d9b291965db4e12a5517c2a0d78382e9c37bff Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Thu, 23 Mar 2023 16:35:15 +0100 Subject: [PATCH 32/78] exporterRoles table --- src/components/TableToolbar/TableToolbar.tsx | 20 +++++++++++++------- src/types/settings.d.ts | 1 + 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/components/TableToolbar/TableToolbar.tsx b/src/components/TableToolbar/TableToolbar.tsx index 7af0f6b9..398debc9 100644 --- a/src/components/TableToolbar/TableToolbar.tsx +++ b/src/components/TableToolbar/TableToolbar.tsx @@ -103,13 +103,19 @@ export default function TableToolbar() { )} - }> - openTableModal("export")} - icon={} - /> - + {(!projectSettings.exporterRoles || + projectSettings.exporterRoles.length === 0 || + userRoles.some((role) => + projectSettings.exporterRoles?.includes(role) + )) && ( + }> + openTableModal("export")} + icon={} + /> + + )} {userRoles.includes("ADMIN") && ( <>
{/* Spacer */} diff --git a/src/types/settings.d.ts b/src/types/settings.d.ts index 0f3b5761..0e762841 100644 --- a/src/types/settings.d.ts +++ b/src/types/settings.d.ts @@ -32,6 +32,7 @@ export type ProjectSettings = Partial<{ builder: string; terminal: string; }>; + exporterRoles?: string[]; }>; /** User info and settings */ From bb2fcf3b64cc2f2f287c7942376e44a4e4c3ab9b Mon Sep 17 00:00:00 2001 From: Anish Roy <6275anishroy@gmail.com> Date: Tue, 28 Mar 2023 10:21:41 +0530 Subject: [PATCH 33/78] added Airtable import/upload files --- .../ImportAirtableWizard.tsx | 24 +++++- .../ImportCsvWizard/ImportCsvWizard.tsx | 14 ++-- .../ImportCsvWizard/useConverter.ts | 74 ++++++++++++++----- .../ImportCsvWizard/useUploadFileFromURL.tsx | 8 +- 4 files changed, 89 insertions(+), 31 deletions(-) diff --git a/src/components/TableModals/ImportAirtableWizard/ImportAirtableWizard.tsx b/src/components/TableModals/ImportAirtableWizard/ImportAirtableWizard.tsx index 7a6cee3f..193743c2 100644 --- a/src/components/TableModals/ImportAirtableWizard/ImportAirtableWizard.tsx +++ b/src/components/TableModals/ImportAirtableWizard/ImportAirtableWizard.tsx @@ -28,6 +28,8 @@ import { fieldParser } from "@src/components/TableModals/ImportAirtableWizard/ut import Step1Columns from "./Step1Columns"; import Step2NewColumns from "./Step2NewColumns"; import Step3Preview from "./Step3Preview"; +import useConverter from "@src/components/TableModals/ImportCsvWizard/useConverter"; +import useUploadFileFromURL from "@src/components/TableModals/ImportCsvWizard/useUploadFileFromURL"; export type AirtableConfig = { pairs: { fieldKey: string; columnKey: string }[]; @@ -65,6 +67,8 @@ export default function ImportAirtableWizard({ onClose }: ITableModalProps) { newColumns: [], documentId: "recordId", }); + const { needsUploadTypes, getConverter } = useConverter(); + const { addTask, runBatchedUpload, hasUploadJobs } = useUploadFileFromURL(); const updateConfig: IStepProps["updateConfig"] = useCallback((value) => { setConfig((prev) => { @@ -99,10 +103,24 @@ export default function ImportAirtableWizard({ onClose }: ITableModalProps) { const matchingColumn = columns[pair.columnKey] ?? find(config.newColumns, { key: pair.columnKey }); - const parser = fieldParser(matchingColumn.type); + const parser = + getConverter(matchingColumn.type) || fieldParser(matchingColumn.type); const value = parser ? parser(record.fields[pair.fieldKey]) : record.fields[pair.fieldKey]; + + if (needsUploadTypes(matchingColumn.type)) { + if (value && value.length > 0) { + addTask({ + docRef: { + path: `${tableSettings.collection}/${record.id}`, + id: record.id, + }, + fieldName: pair.columnKey, + files: value, + }); + } + } return config.documentId === "recordId" ? { ...a, [pair.columnKey]: value, _rowy_ref: { id: record.id } } : { ...a, [pair.columnKey]: value }; @@ -196,6 +214,10 @@ export default function ImportAirtableWizard({ onClose }: ITableModalProps) { `Imported ${Number(countRef.current).toLocaleString()} rows`, { variant: "success" } ); + + if (hasUploadJobs()) { + await runBatchedUpload(); + } } catch (e) { enqueueSnackbar((e as Error).message, { variant: "error" }); } finally { diff --git a/src/components/TableModals/ImportCsvWizard/ImportCsvWizard.tsx b/src/components/TableModals/ImportCsvWizard/ImportCsvWizard.tsx index 421fbc30..4f3f9a9e 100644 --- a/src/components/TableModals/ImportCsvWizard/ImportCsvWizard.tsx +++ b/src/components/TableModals/ImportCsvWizard/ImportCsvWizard.tsx @@ -37,7 +37,6 @@ import { import { ColumnConfig } from "@src/types/table"; import { getFieldProp } from "@src/components/fields"; import { analytics, logEvent } from "@src/analytics"; -import { FieldType } from "@src/constants/fields"; import { generateId } from "@src/utils/table"; import { isValidDocId } from "./utils"; import useUploadFileFromURL from "./useUploadFileFromURL"; @@ -50,8 +49,6 @@ export type CsvConfig = { documentIdCsvKey: string | null; }; -const needsUploadTypes = [FieldType.image, FieldType.file]; - export interface IStepProps { csvData: NonNullable; config: CsvConfig; @@ -71,8 +68,8 @@ export default function ImportCsvWizard({ onClose }: ITableModalProps) { const theme = useTheme(); const isXs = useMediaQuery(theme.breakpoints.down("sm")); const snackbarProgressRef = useRef(); - const { addTask, runBatchUpload, askPermission } = useUploadFileFromURL(); - const { needsConverter, getConverter } = useConverter(); + const { addTask, runBatchedUpload } = useUploadFileFromURL(); + const { needsUploadTypes, needsConverter, getConverter } = useConverter(); const columns = useMemoValue(tableSchema.columns ?? {}, isEqual); @@ -147,7 +144,7 @@ export default function ImportCsvWizard({ onClose }: ITableModalProps) { if (needsConverter(column.type)) { requiredConverts[index] = getConverter(column.type); // console.log({ needsUploadTypes }, column.type); - if (needsUploadTypes.includes(column.type)) { + if (needsUploadTypes(column.type)) { requiredUploads[column.fieldName + ""] = true; } } @@ -158,6 +155,7 @@ export default function ImportCsvWizard({ onClose }: ITableModalProps) { config.pairs, getConverter, needsConverter, + needsUploadTypes, tableSchema.columns, ]); @@ -266,8 +264,8 @@ export default function ImportCsvWizard({ onClose }: ITableModalProps) { `Imported ${Number(validRows.length).toLocaleString()} rows`, { variant: "success" } ); - if (Object.keys(requiredUploads).length && (await askPermission())) { - await runBatchUpload(); + if (Object.keys(requiredUploads).length > 0) { + await runBatchedUpload(); } } catch (e) { enqueueSnackbar((e as Error).message, { variant: "error" }); diff --git a/src/components/TableModals/ImportCsvWizard/useConverter.ts b/src/components/TableModals/ImportCsvWizard/useConverter.ts index 489a3127..58f597be 100644 --- a/src/components/TableModals/ImportCsvWizard/useConverter.ts +++ b/src/components/TableModals/ImportCsvWizard/useConverter.ts @@ -16,6 +16,9 @@ const needsConverter = (type: FieldType) => FieldType.geoPoint, ].includes(type); +const needsUploadTypes = (type: FieldType) => + [FieldType.image, FieldType.file].includes(type); + export default function useConverter() { const [firebaseDb] = useAtom(firebaseDbAtom, projectScope); @@ -35,27 +38,59 @@ export default function useConverter() { }; const imageOrFileConverter = (urls: any): RowyFile[] => { - if (!urls) return []; - if (Array.isArray(urls)) return urls; - if (typeof urls === "string") { - return urls - .split(",") - .map((url) => { - url = url.trim(); - if (url !== "") { - return { - downloadURL: url, - name: url.split("/").pop() || "", - lastModifiedTS: +new Date(), - type: "", - }; - } + try { + if (!urls) return []; + if (Array.isArray(urls)) { + return urls + .map((url) => { + if (typeof url === "string") { + url = url.trim(); + if (url !== "") { + return { + downloadURL: url, + name: url.split("/").pop() || "", + lastModifiedTS: +new Date(), + type: "", + }; + } + } else if (url && typeof url === "object" && url.downloadURL) { + return url; + } else { + if (url.url) { + return { + downloadURL: url.url, + name: url.filename || url.url.split("/").pop() || "", + lastModifiedTS: +new Date(), + type: "", + }; + } + } + return null; + }) + .filter((val) => val !== null) as RowyFile[]; + } + if (typeof urls === "string") { + return urls + .split(",") + .map((url) => { + url = url.trim(); + if (url !== "") { + return { + downloadURL: url, + name: url.split("/").pop() || "", + lastModifiedTS: +new Date(), + type: "", + }; + } - return null; - }) - .filter((val) => val !== null) as RowyFile[]; + return null; + }) + .filter((val) => val !== null) as RowyFile[]; + } + return []; + } catch (e) { + return []; } - return []; }; const geoPointConverter = (value: any) => { @@ -120,5 +155,6 @@ export default function useConverter() { imageOrFileConverter, getConverter, checkAndConvert, + needsUploadTypes, }; } diff --git a/src/components/TableModals/ImportCsvWizard/useUploadFileFromURL.tsx b/src/components/TableModals/ImportCsvWizard/useUploadFileFromURL.tsx index 0fae28fd..00d99b69 100644 --- a/src/components/TableModals/ImportCsvWizard/useUploadFileFromURL.tsx +++ b/src/components/TableModals/ImportCsvWizard/useUploadFileFromURL.tsx @@ -126,7 +126,7 @@ export default function useUploadFileFromURL() { [enqueueSnackbar] ); - const runBatchUpload = useCallback(async () => { + const runBatchedUpload = useCallback(async () => { if (!snackbarProgressId.current) { showProgress(jobs.current.length); } @@ -145,7 +145,7 @@ export default function useUploadFileFromURL() { await batchUpload(currentJobs); if (jobs.current.length > 0) { - await runBatchUpload(); + await runBatchedUpload(); } if (snackbarProgressId.current) { @@ -157,10 +157,12 @@ export default function useUploadFileFromURL() { jobs.current.push(job); }, []); + const hasUploadJobs = () => jobs.current.length > 0; return { addTask, - runBatchUpload, + runBatchedUpload, askPermission, + hasUploadJobs, }; } From 6ffa689fa6da9eb69c34d559bcc5bb7844688b21 Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Tue, 28 Mar 2023 12:08:57 +0200 Subject: [PATCH 34/78] firebase auth webhook --- .../WebhooksModal/Schemas/firebaseAuth.tsx | 67 +++++++++++++++++++ .../WebhooksModal/Schemas/index.ts | 3 +- .../TableModals/WebhooksModal/utils.tsx | 24 ++++++- 3 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 src/components/TableModals/WebhooksModal/Schemas/firebaseAuth.tsx diff --git a/src/components/TableModals/WebhooksModal/Schemas/firebaseAuth.tsx b/src/components/TableModals/WebhooksModal/Schemas/firebaseAuth.tsx new file mode 100644 index 00000000..21d2d3fd --- /dev/null +++ b/src/components/TableModals/WebhooksModal/Schemas/firebaseAuth.tsx @@ -0,0 +1,67 @@ +import { Typography, Link, TextField } from "@mui/material"; +import InlineOpenInNewIcon from "@src/components/InlineOpenInNewIcon"; +import { TableSettings } from "@src/types/table"; +import { + IWebhook, + ISecret, +} from "@src/components/TableModals/WebhooksModal/utils"; + +export const webhookFirebaseAuth = { + name: "firebaseAuth", + parser: { + additionalVariables: null, + extraLibs: null, + template: ( + table: TableSettings + ) => `const firebaseAuthParser: Parser = async({req, db, ref, logging}) =>{ + // WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY + logging.log("firebaseAuthParser started") + /** + * This is a sample parser for firebase authentication + * creates a user document in the collection if it doesn't exist + // check if document exists, + const userDoc = await ref.doc(user.uid).get() + if(!userDoc.exists){ + await ref.doc(user.uid).set({email:user.email}) + } + */ + return; +};`, + }, + condition: { + additionalVariables: null, + extraLibs: null, + template: ( + table: TableSettings + ) => `const condition: Condition = async({ref, req, db, logging}) => { + // WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY + logging.log("condition started") + + return true; + // WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY +}`, + }, + auth: ( + webhookObject: IWebhook, + setWebhookObject: (w: IWebhook) => void, + secrets: ISecret + ) => { + return ( + <> + + For Firebase authentication, you need to include the following header + in your request: +
+ Authorization: Bear ACCESS_TOKEN +
+ + + Once enabled requests without a valid token will return{" "} + 401 response. + + + ); + }, +}; + +export default webhookFirebaseAuth; diff --git a/src/components/TableModals/WebhooksModal/Schemas/index.ts b/src/components/TableModals/WebhooksModal/Schemas/index.ts index fff6341f..889f31ab 100644 --- a/src/components/TableModals/WebhooksModal/Schemas/index.ts +++ b/src/components/TableModals/WebhooksModal/Schemas/index.ts @@ -1,7 +1,8 @@ import basic from "./basic"; +import firebaseAuth from "./firebaseAuth"; import typeform from "./typeform"; import sendgrid from "./sendgrid"; import webform from "./webform"; import stripe from "./stripe"; -export { basic, typeform, sendgrid, webform, stripe }; +export { basic, typeform, sendgrid, webform, stripe, firebaseAuth }; diff --git a/src/components/TableModals/WebhooksModal/utils.tsx b/src/components/TableModals/WebhooksModal/utils.tsx index cefc6c2f..e43c747b 100644 --- a/src/components/TableModals/WebhooksModal/utils.tsx +++ b/src/components/TableModals/WebhooksModal/utils.tsx @@ -1,12 +1,20 @@ import { TableSettings } from "@src/types/table"; import { generateId } from "@src/utils/table"; -import { typeform, basic, sendgrid, webform, stripe } from "./Schemas"; +import { + typeform, + basic, + sendgrid, + webform, + stripe, + firebaseAuth, +} from "./Schemas"; export const webhookTypes = [ "basic", "typeform", "sendgrid", "webform", + "firebaseAuth", //"shopify", //"twitter", "stripe", @@ -35,6 +43,18 @@ export const parserExtraLibs = [ send: (v:any)=>void; sendStatus: (status:number)=>void }; + user: { + uid: string; + email: string; + email_verified: boolean; + exp: number; + iat: number; + iss: string; + aud: string; + auth_time: number; + phone_number: string; + picture: string; + } | undefined; logging: RowyLogging; auth:firebaseauth.BaseAuth; storage:firebasestorage.Storage; @@ -71,6 +91,7 @@ export type WebhookType = typeof webhookTypes[number]; export const webhookNames: Record = { sendgrid: "SendGrid", typeform: "Typeform", + firebaseAuth: "Firebase Auth", //github:"GitHub", // shopify: "Shopify", // twitter: "Twitter", @@ -110,6 +131,7 @@ export const webhookSchemas = { sendgrid, webform, stripe, + firebaseAuth, }; export function emptyWebhookObject( From 23fd0c77bcaff041fbced8d40de01a88084c2bb4 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Wed, 29 Mar 2023 11:10:45 +1300 Subject: [PATCH 35/78] fix code template typo --- src/components/TableModals/ExtensionsModal/utils.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/TableModals/ExtensionsModal/utils.ts b/src/components/TableModals/ExtensionsModal/utils.ts index 27281625..4a2cbbf1 100644 --- a/src/components/TableModals/ExtensionsModal/utils.ts +++ b/src/components/TableModals/ExtensionsModal/utils.ts @@ -132,8 +132,8 @@ const extensionBodyTemplate = { return({ fieldsToSync: [], // a list of string of column names row: row, // object of data to sync, usually the row itself - index: "", // algolia index to sync to - objectID: ref.id, // algolia object ID, ref.id is one possible choice + index: "", // meili search index to sync to + objectID: ref.id, // meili search object ID, ref.id is one possible choice }) // WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY }`, @@ -144,8 +144,8 @@ const extensionBodyTemplate = { return ({ fieldsToSync: [], // a list of string of column names row: row, // object of data to sync, usually the row itself - index: "", // algolia index to sync to - objectID: ref.id, // algolia object ID, ref.id is one possible choice + index: "", // bigquery dataset to sync to + objectID: ref.id, // bigquery object ID, ref.id is one possible choice }) // WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY }`, From 02eec0050b31b67376b59069e8cdc729fe6f610e Mon Sep 17 00:00:00 2001 From: Han Tuerker <46192266+htuerker@users.noreply.github.com> Date: Wed, 29 Mar 2023 12:34:25 +0300 Subject: [PATCH 36/78] update table schema with id customization --- src/atoms/projectScope/ui.ts | 4 ---- .../Table/ContextMenu/MenuContents.tsx | 4 ++-- .../Table/FinalColumn/FinalColumn.tsx | 11 +++++---- src/components/TableToolbar/AddRow.tsx | 23 ++++++++++++------- src/types/table.d.ts | 3 +++ 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/atoms/projectScope/ui.ts b/src/atoms/projectScope/ui.ts index 6f9d66d8..48af64b0 100644 --- a/src/atoms/projectScope/ui.ts +++ b/src/atoms/projectScope/ui.ts @@ -147,10 +147,6 @@ export const tableSettingsDialogSchemaAtom = atom(async (get) => { /** Open the Get Started checklist from anywhere */ export const getStartedChecklistAtom = atom(false); -/** Persist the state of the add row ID type */ -export const tableAddRowIdTypeAtom = atomWithStorage< - "decrement" | "random" | "custom" ->("__ROWY__ADD_ROW_ID_TYPE", "decrement"); /** Persist when the user dismissed the row out of order warning */ export const tableOutOfOrderDismissedAtom = atomWithStorage( "__ROWY__OUT_OF_ORDER_TOOLTIP_DISMISSED", diff --git a/src/components/Table/ContextMenu/MenuContents.tsx b/src/components/Table/ContextMenu/MenuContents.tsx index 88a973c2..6030b89a 100644 --- a/src/components/Table/ContextMenu/MenuContents.tsx +++ b/src/components/Table/ContextMenu/MenuContents.tsx @@ -21,7 +21,6 @@ import { projectIdAtom, userRolesAtom, altPressAtom, - tableAddRowIdTypeAtom, confirmDialogAtom, } from "@src/atoms/projectScope"; import { @@ -45,7 +44,6 @@ export default function MenuContents({ onClose }: IMenuContentsProps) { const [projectId] = useAtom(projectIdAtom, projectScope); const [userRoles] = useAtom(userRolesAtom, projectScope); const [altPress] = useAtom(altPressAtom, projectScope); - const [addRowIdType] = useAtom(tableAddRowIdTypeAtom, projectScope); const confirm = useSetAtom(confirmDialogAtom, projectScope); const [tableSettings] = useAtom(tableSettingsAtom, tableScope); const [tableSchema] = useAtom(tableSchemaAtom, tableScope); @@ -59,6 +57,8 @@ export default function MenuContents({ onClose }: IMenuContentsProps) { tableScope ); + const addRowIdType = tableSchema.idType || "decrement"; + if (!tableSchema.columns || !selectedCell) return null; const selectedColumn = tableSchema.columns[selectedCell.columnKey]; diff --git a/src/components/Table/FinalColumn/FinalColumn.tsx b/src/components/Table/FinalColumn/FinalColumn.tsx index 28b584e6..e6023e4d 100644 --- a/src/components/Table/FinalColumn/FinalColumn.tsx +++ b/src/components/Table/FinalColumn/FinalColumn.tsx @@ -10,7 +10,6 @@ import MenuIcon from "@mui/icons-material/MoreHoriz"; import { projectScope, userRolesAtom, - tableAddRowIdTypeAtom, altPressAtom, confirmDialogAtom, } from "@src/atoms/projectScope"; @@ -20,6 +19,7 @@ import { addRowAtom, deleteRowAtom, contextMenuTargetAtom, + tableSchemaAtom, } from "@src/atoms/tableScope"; export const FinalColumn = memo(function FinalColumn({ @@ -27,16 +27,19 @@ export const FinalColumn = memo(function FinalColumn({ focusInsideCell, }: IRenderedTableCellProps) { const [userRoles] = useAtom(userRolesAtom, projectScope); - const [addRowIdType] = useAtom(tableAddRowIdTypeAtom, projectScope); - const confirm = useSetAtom(confirmDialogAtom, projectScope); - const [tableSettings] = useAtom(tableSettingsAtom, tableScope); + const [tableSchema] = useAtom(tableSchemaAtom, tableScope); const addRow = useSetAtom(addRowAtom, tableScope); const deleteRow = useSetAtom(deleteRowAtom, tableScope); const setContextMenuTarget = useSetAtom(contextMenuTargetAtom, tableScope); + const confirm = useSetAtom(confirmDialogAtom, projectScope); const [altPress] = useAtom(altPressAtom, projectScope); + + const addRowIdType = tableSchema.idType || "decrement"; + const handleDelete = () => deleteRow(row.original._rowy_ref.path); + const handleDuplicate = () => { addRow({ row: row.original, diff --git a/src/components/TableToolbar/AddRow.tsx b/src/components/TableToolbar/AddRow.tsx index c6372865..0f27da9e 100644 --- a/src/components/TableToolbar/AddRow.tsx +++ b/src/components/TableToolbar/AddRow.tsx @@ -16,33 +16,40 @@ import { ChevronDown as ArrowDropDownIcon, } from "@src/assets/icons"; -import { - projectScope, - userRolesAtom, - tableAddRowIdTypeAtom, -} from "@src/atoms/projectScope"; +import { projectScope, userRolesAtom } from "@src/atoms/projectScope"; import { tableScope, tableSettingsAtom, tableFiltersAtom, tableSortsAtom, addRowAtom, + tableSchemaAtom, + updateTableSchemaAtom, } from "@src/atoms/tableScope"; +import { TableIdType } from "@src/types/table"; export default function AddRow() { const [userRoles] = useAtom(userRolesAtom, projectScope); const [tableSettings] = useAtom(tableSettingsAtom, tableScope); + const [tableSchema] = useAtom(tableSchemaAtom, tableScope); const [tableFilters] = useAtom(tableFiltersAtom, tableScope); const [tableSorts] = useAtom(tableSortsAtom, tableScope); + const [updateTableSchema] = useAtom(updateTableSchemaAtom, tableScope); const addRow = useSetAtom(addRowAtom, tableScope); - const [idType, setIdType] = useAtom(tableAddRowIdTypeAtom, projectScope); - const anchorEl = useRef(null); const [open, setOpen] = useState(false); const [openIdModal, setOpenIdModal] = useState(false); + const idType = tableSchema.idType || "decrement"; const forceRandomId = tableFilters.length > 0 || tableSorts.length > 0; + const handleSetIdType = async (idType: TableIdType) => { + // TODO(han): refactor atom - error handler + await updateTableSchema!({ + idType, + }); + }; + const handleClick = () => { if (idType === "random" || (forceRandomId && idType === "decrement")) { addRow({ @@ -118,7 +125,7 @@ export default function AddRow() { label="Row add position" style={{ display: "none" }} value={forceRandomId && idType === "decrement" ? "random" : idType} - onChange={(e) => setIdType(e.target.value as typeof idType)} + onChange={(e) => handleSetIdType(e.target.value as typeof idType)} MenuProps={{ anchorEl: anchorEl.current, MenuListProps: { "aria-labelledby": "add-row-menu-button" }, diff --git a/src/types/table.d.ts b/src/types/table.d.ts index a0570542..8de72284 100644 --- a/src/types/table.d.ts +++ b/src/types/table.d.ts @@ -95,9 +95,12 @@ export type TableSettings = { readOnly?: boolean; }; +export type TableIdType = "decrement" | "random" | "custom"; + /** Table schema document loaded when table or table settings dialog is open */ export type TableSchema = { columns?: Record; + idType?: TableIdType; rowHeight?: number; filters?: TableFilter[]; filtersOverridable?: boolean; From 41d8feb84b0243db15d731b95d9b8e42bc7a598e Mon Sep 17 00:00:00 2001 From: Anish Roy <6275anishroy@gmail.com> Date: Thu, 30 Mar 2023 15:03:08 +0530 Subject: [PATCH 37/78] =?UTF-8?q?=E2=9C=A8=20feat(App.tsx):=20add=20route?= =?UTF-8?q?=20for=20ProvidedArraySubTablePage=20at=20/array-sub-table/:doc?= =?UTF-8?q?Path/:subTableKey?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/App.tsx b/src/App.tsx index ea283a01..d169bb1e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -23,6 +23,7 @@ import useKeyPressWithAtom from "@src/hooks/useKeyPressWithAtom"; import TableGroupRedirectPage from "./pages/TableGroupRedirectPage"; import SignOutPage from "@src/pages/Auth/SignOutPage"; +import ProvidedArraySubTablePage from "./pages/Table/ProvidedArraySubTablePage"; // prettier-ignore const AuthPage = lazy(() => import("@src/pages/Auth/AuthPage" /* webpackChunkName: "AuthPage" */)); @@ -134,6 +135,27 @@ export default function App() { } /> + + } /> + + + + } + > + + + } + /> + From a91b75199550b0bf446cde5d6a6d76e798aeecf0 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Sat, 1 Apr 2023 02:37:14 +1300 Subject: [PATCH 38/78] fix export crash due to toDate issue --- src/components/fields/Date/index.tsx | 9 +++++++-- src/components/fields/DateTime/index.tsx | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/components/fields/Date/index.tsx b/src/components/fields/Date/index.tsx index a8989d48..8a126c22 100644 --- a/src/components/fields/Date/index.tsx +++ b/src/components/fields/Date/index.tsx @@ -35,8 +35,13 @@ export const config: IFieldConfig = { filter: { operators: filterOperators, valueFormatter }, settings: Settings, csvImportParser: (value, config) => parse(value, DATE_FORMAT, new Date()), - csvExportFormatter: (value: any, config?: any) => - format(value.toDate(), DATE_FORMAT), + csvExportFormatter: (value: any, config?: any) => { + if (typeof value === "number") { + return format(new Date(value), DATE_FORMAT); + } else { + return format(value.toDate(), DATE_FORMAT); + } + }, }; export default config; diff --git a/src/components/fields/DateTime/index.tsx b/src/components/fields/DateTime/index.tsx index 38e0e412..65c77ff5 100644 --- a/src/components/fields/DateTime/index.tsx +++ b/src/components/fields/DateTime/index.tsx @@ -47,8 +47,13 @@ export const config: IFieldConfig = { }, settings: Settings, csvImportParser: (value) => new Date(value), - csvExportFormatter: (value: any, config?: any) => - format(value.toDate(), DATE_TIME_FORMAT), + csvExportFormatter: (value: any, config?: any) => { + if (typeof value === "number") { + return format(new Date(value), config?.format || DATE_TIME_FORMAT); + } else { + return format(value.toDate(), config?.format || DATE_TIME_FORMAT); + } + }, }; export default config; From f66e8b988072c139b52ce9300fc2307a7ba4033f Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Sat, 1 Apr 2023 02:52:00 +1300 Subject: [PATCH 39/78] fix commit history --- src/components/fields/DateTime/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/fields/DateTime/index.tsx b/src/components/fields/DateTime/index.tsx index 65c77ff5..ea0305c8 100644 --- a/src/components/fields/DateTime/index.tsx +++ b/src/components/fields/DateTime/index.tsx @@ -49,9 +49,9 @@ export const config: IFieldConfig = { csvImportParser: (value) => new Date(value), csvExportFormatter: (value: any, config?: any) => { if (typeof value === "number") { - return format(new Date(value), config?.format || DATE_TIME_FORMAT); + return format(new Date(value), DATE_TIME_FORMAT); } else { - return format(value.toDate(), config?.format || DATE_TIME_FORMAT); + return format(value.toDate(), DATE_TIME_FORMAT); } }, }; From cfde5886c43c519ada8a3730d86ec2f01446d845 Mon Sep 17 00:00:00 2001 From: Harini Janakiraman Date: Wed, 5 Apr 2023 19:08:08 +1000 Subject: [PATCH 40/78] Update externalLinks.ts --- src/constants/externalLinks.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/constants/externalLinks.ts b/src/constants/externalLinks.ts index a2b64de4..e501be4b 100644 --- a/src/constants/externalLinks.ts +++ b/src/constants/externalLinks.ts @@ -65,8 +65,10 @@ const WIKI_PATHS = { webhooks: "/webhooks", importAirtable: "/import-export-data/import-airtable", - importAirtableApiKey: "/import-export-data/import-airtable#api-key", - importAirtableTableUrl: "/import-export-data/import-airtable#table-url", + importAirtableApiKey: + "/import-export-data/import-airtable#retrieving-the-airtable-api-key", + importAirtableTableUrl: + "/import-export-data/import-airtable#obtaining-the-airtable-table-url", cloudLogs: "/cloud-logs", }; export const WIKI_LINKS = mapValues( From 60c42d099bef7d7a8851057cc19014c6e3bd0592 Mon Sep 17 00:00:00 2001 From: Anish Roy <6275anishroy@gmail.com> Date: Thu, 6 Apr 2023 11:17:47 +0530 Subject: [PATCH 41/78] fixed - BUG: While changing table name/description --- src/components/TableSettingsDialog/TableName.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/components/TableSettingsDialog/TableName.tsx b/src/components/TableSettingsDialog/TableName.tsx index 989f6716..66a5c9d5 100644 --- a/src/components/TableSettingsDialog/TableName.tsx +++ b/src/components/TableSettingsDialog/TableName.tsx @@ -12,16 +12,21 @@ export interface ITableNameProps extends IShortTextComponentProps { export default function TableName({ watchedField, ...props }: ITableNameProps) { const { - field: { onChange }, + field: { onChange, value }, useFormMethods: { control }, disabled, } = props; const watchedValue = useWatch({ control, name: watchedField } as any); useEffect(() => { - if (!disabled && typeof watchedValue === "string" && !!watchedValue) - onChange(startCase(watchedValue)); - }, [watchedValue, disabled]); + if (!disabled) { + if (typeof value === "string" && value.trim() !== "") { + onChange(value); + } else if (typeof watchedValue === "string" && !!watchedValue) { + onChange(startCase(watchedValue)); + } + } + }, [watchedValue, disabled, onChange, value]); return ; } From 4f7fbb791910f12470f196bfbdb3d4a74f27f9bb Mon Sep 17 00:00:00 2001 From: Anish Roy <6275anishroy@gmail.com> Date: Thu, 6 Apr 2023 11:44:32 +0530 Subject: [PATCH 42/78] fixed - Visual bug: in dropdown menu(Connector field) --- src/components/fields/Connector/Select/PopupContents.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/fields/Connector/Select/PopupContents.tsx b/src/components/fields/Connector/Select/PopupContents.tsx index 0bd770cb..45955cf8 100644 --- a/src/components/fields/Connector/Select/PopupContents.tsx +++ b/src/components/fields/Connector/Select/PopupContents.tsx @@ -108,7 +108,7 @@ export default function PopupContents({ onChange={(e) => setQuery(e.target.value)} fullWidth variant="filled" - label="Search items" + // label="Search items" hiddenLabel placeholder="Search items" InputProps={{ From bd7ef2eb3b11f0b6a613687cc4bed1825ba8831e Mon Sep 17 00:00:00 2001 From: Anish Roy <6275anishroy@gmail.com> Date: Thu, 6 Apr 2023 12:51:31 +0530 Subject: [PATCH 43/78] fixed checked icon getting inverted --- src/components/GetStartedChecklist/GetStartedChecklist.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/GetStartedChecklist/GetStartedChecklist.tsx b/src/components/GetStartedChecklist/GetStartedChecklist.tsx index ad6ba46a..e15b91bc 100644 --- a/src/components/GetStartedChecklist/GetStartedChecklist.tsx +++ b/src/components/GetStartedChecklist/GetStartedChecklist.tsx @@ -80,6 +80,9 @@ export default function GetStartedChecklist({ marginRight: `max(env(safe-area-inset-right), 8px)`, width: 360, }, + ".MuiStepLabel-iconContainer.Mui-active svg": { + transform: "rotate(0deg) !important", + }, }, ]} > From bc815afe74dc543c58a5f970406701b539128597 Mon Sep 17 00:00:00 2001 From: Yaman Katby Date: Thu, 6 Apr 2023 17:16:26 +0300 Subject: [PATCH 44/78] update the connector field default value --- src/components/fields/Connector/utils.ts | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/components/fields/Connector/utils.ts b/src/components/fields/Connector/utils.ts index 921997ad..ecbe3f52 100644 --- a/src/components/fields/Connector/utils.ts +++ b/src/components/fields/Connector/utils.ts @@ -11,16 +11,19 @@ export const replacer = (data: any) => (m: string, key: string) => { return get(data, objKey, defaultValue); }; -export const baseFunction = `const connectorFn: Connector = async ({query, row, user, logging}) => { - // WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY - logging.log("connectorFn started") - - // Import any NPM package needed - // const lodash = require('lodash'); - - return []; - // WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY -};`; +export const baseFunction = `// Import any NPM package needed +import lodash from "lodash"; + +const connector: Connector = async ({ query, row, user, logging }) => { + logging.log("connector started"); + // return [ + // { id: "a", name: "Apple" }, + // { id: "b", name: "Banana" }, + // ]; +}; + +export default connector; +`; export const getLabel = (config: any, row: TableRow) => { if (!config.labelFormatter) { From 0bc104d07e8c72404f169c88ed83923b82aebe98 Mon Sep 17 00:00:00 2001 From: Yaman Katby Date: Thu, 6 Apr 2023 17:18:59 +0300 Subject: [PATCH 45/78] convert the import into comment --- src/components/fields/Connector/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/fields/Connector/utils.ts b/src/components/fields/Connector/utils.ts index ecbe3f52..88a90ed2 100644 --- a/src/components/fields/Connector/utils.ts +++ b/src/components/fields/Connector/utils.ts @@ -12,7 +12,7 @@ export const replacer = (data: any) => (m: string, key: string) => { }; export const baseFunction = `// Import any NPM package needed -import lodash from "lodash"; +// import _ from "lodash"; const connector: Connector = async ({ query, row, user, logging }) => { logging.log("connector started"); From 13c1b693864d419998d9ccfc7b0b778078bdff55 Mon Sep 17 00:00:00 2001 From: Yaman Katby Date: Thu, 6 Apr 2023 17:26:03 +0300 Subject: [PATCH 46/78] update the action and the redo code templates --- src/components/fields/Action/templates.ts | 110 +++++++++++----------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/src/components/fields/Action/templates.ts b/src/components/fields/Action/templates.ts index 46b0a0b5..294eab3e 100644 --- a/src/components/fields/Action/templates.ts +++ b/src/components/fields/Action/templates.ts @@ -1,67 +1,67 @@ -export const RUN_ACTION_TEMPLATE = `const action:Action = async ({row,ref,db,storage,auth,actionParams,user,logging}) => { - // WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY - logging.log("action started") - - // Import any NPM package needed - // const lodash = require('lodash'); - - // Example: - /* - const authToken = await rowy.secrets.get("service") - try { - const resp = await fetch('https://example.com/api/v1/users/'+ref.id,{ - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - 'Authorization': authToken - }, - body: JSON.stringify(row) - }) - return { - success: true, - message: 'User updated successfully on example service', - status: "upto date" - } - } catch (error) { - return { - success: false, - message: 'User update failed on example service', - } - } - */ - // WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY -}`; +export const RUN_ACTION_TEMPLATE = `// Import any NPM package needed +// import _ from "lodash"; + +const action: Action = async ({ row, ref, db, storage, auth, actionParams, user, logging }) => { + logging.log("action started"); -export const UNDO_ACTION_TEMPLATE = `const action : Action = async ({row,ref,db,storage,auth,actionParams,user,logging}) => { - // WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY - logging.log("action started") - - // Import any NPM package needed - // const lodash = require('lodash'); - - // Example: /* - const authToken = await rowy.secrets.get("service") + // Example: + const authToken = await rowy.secrets.get("service"); try { - const resp = await fetch('https://example.com/api/v1/users/'+ref.id,{ - method: 'DELETE', + const resp = await fetch("https://example.com/api/v1/users/" + ref.id, { + method: "PUT", headers: { - 'Content-Type': 'application/json', - 'Authorization': authToken + "Content-Type": "application/json", + Authorization: authToken, }, - body: JSON.stringify(row) - }) + body: JSON.stringify(row), + }); return { success: true, - message: 'User deleted successfully on example service', - status: null - } + message: "User updated successfully on example service", + status: "upto date", + }; } catch (error) { return { success: false, - message: 'User delete failed on example service', - } + message: "User update failed on example service", + }; } */ - // WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY -}`; +}; + +export default action; +`; + +export const UNDO_ACTION_TEMPLATE = `// Import any NPM package needed +// import _ from "lodash"; + +const action: Action = async ({ row, ref, db, storage, auth, actionParams, user, logging }) => { + logging.log("action started"); + + /* + // Example: + const authToken = await rowy.secrets.get("service"); + try { + const resp = await fetch("https://example.com/api/v1/users/" + ref.id, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + Authorization: authToken, + }, + body: JSON.stringify(row), + }); + return { + success: true, + message: "User deleted successfully on example service", + status: null, + }; + } catch (error) { + return { + success: false, + message: "User delete failed on example service", + }; + } + */ +}; +`; From e841c994e5a174965a154613c20afd2e44393b15 Mon Sep 17 00:00:00 2001 From: Yaman Katby Date: Thu, 6 Apr 2023 17:30:21 +0300 Subject: [PATCH 47/78] Update the derivative default template --- src/components/fields/Derivative/Settings.tsx | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/components/fields/Derivative/Settings.tsx b/src/components/fields/Derivative/Settings.tsx index 1c2486d2..0ca5dd51 100644 --- a/src/components/fields/Derivative/Settings.tsx +++ b/src/components/fields/Derivative/Settings.tsx @@ -75,18 +75,19 @@ export default function Settings({ ${config.script.replace(/utilFns.getSecret/g, "rowy.secrets.get")} // WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY }` - : `const derivative:Derivative = async ({row,ref,db,storage,auth,logging})=>{ - // WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY - logging.log("derivative started") - - // Import any NPM package needed - // const lodash = require('lodash'); - + : `// Import any NPM package needed +// import _ from "lodash"; + +const derivative: Derivative = async ({ row, ref, db, storage, auth, logging }) => { + logging.log("derivative started"); + // Example: // const sum = row.a + row.b; // return sum; - // WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY -}`; +}; + +export default derivative; +`; return ( <> From 8254623c2cbafa8fb7e56927c25554cf1d5c2479 Mon Sep 17 00:00:00 2001 From: Yaman Katby Date: Thu, 6 Apr 2023 17:38:40 +0300 Subject: [PATCH 48/78] fix redo action template --- src/components/fields/Action/templates.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/fields/Action/templates.ts b/src/components/fields/Action/templates.ts index 294eab3e..3a9baf7a 100644 --- a/src/components/fields/Action/templates.ts +++ b/src/components/fields/Action/templates.ts @@ -64,4 +64,6 @@ const action: Action = async ({ row, ref, db, storage, auth, actionParams, user, } */ }; + +export default action; `; From d0dd89b00b177102c3951cf7040289907a6f0498 Mon Sep 17 00:00:00 2001 From: Yaman Katby Date: Thu, 6 Apr 2023 17:38:53 +0300 Subject: [PATCH 49/78] update default value function template --- .../ColumnConfigModal/DefaultValueInput.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/components/ColumnModals/ColumnConfigModal/DefaultValueInput.tsx b/src/components/ColumnModals/ColumnConfigModal/DefaultValueInput.tsx index 5146c387..b5e3dc05 100644 --- a/src/components/ColumnModals/ColumnConfigModal/DefaultValueInput.tsx +++ b/src/components/ColumnModals/ColumnConfigModal/DefaultValueInput.tsx @@ -61,15 +61,19 @@ function CodeEditor({ type, column, handleChange }: ICodeEditorProps) { // WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY }`; } else { - dynamicValueFn = `const dynamicValueFn: DefaultValue = async ({row,ref,db,storage,auth,logging})=>{ - // WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY - logging.log("dynamicValueFn started") - + dynamicValueFn = `// Import any NPM package needed +// import _ from "lodash"; + +const defaultValue: DefaultValue = async ({ row, ref, db, storage, auth, logging }) => { + logging.log("dynamicValueFn started"); + // Example: generate random hex color // const color = "#" + Math.floor(Math.random() * 16777215).toString(16); // return color; - // WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY -}`; +}; + +export default defaultValue; +`; } return ( From 4fc88e36f8f21a70e18d5322ea3d279888d201ac Mon Sep 17 00:00:00 2001 From: Harini Janakiraman Date: Sun, 9 Apr 2023 11:18:33 +1000 Subject: [PATCH 50/78] Update README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e4aa71b8..c064ca7e 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,12 @@ Low-code for Firebase and Google Cloud.
-[![Discord](https://img.shields.io/discord/853498675484819476?color=%234200FF&label=Chat%20with%20us&logo=discord&logoColor=%23FFFFFF&style=for-the-badge)](https://discord.gg/fjBugmvzZP) +[![Rowy Discord](https://dcbadge.vercel.app/api/server/fjBugmvzZP)](https://discord.gg/fjBugmvzZP)

WebsiteDocumentation • - Discord • + Chat with usTwitter

@@ -27,11 +27,11 @@ Low-code for Firebase and Google Cloud.
-## Live Demo +## Live Demo 🛝 -💥 Check out the [live demo](https://demo.rowy.io/) of Rowy 💥 +💥 Explore Rowy on [live demo playground](https://demo.rowy.io/) 💥 -## Features +## Features ✨