From f14e77b415fbb887af5ccac7f6cc31f226dd4115 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Mon, 26 Jun 2023 20:16:27 +1000 Subject: [PATCH 01/20] implement secret manager popup --- src/App.tsx | 7 + src/atoms/projectScope/ui.ts | 20 ++ .../ProjectSettingsDialog.tsx | 285 ++++++++++++++++++ .../SecretDetailsModal.tsx | 158 ++++++++++ src/components/ProjectSettingsDialog/index.ts | 2 + .../WebhooksModal/Schemas/stripe.tsx | 10 +- .../TableSettingsDialog.tsx | 2 +- src/constants/runRoutes.ts | 3 + 8 files changed, 484 insertions(+), 3 deletions(-) create mode 100644 src/components/ProjectSettingsDialog/ProjectSettingsDialog.tsx create mode 100644 src/components/ProjectSettingsDialog/SecretDetailsModal.tsx create mode 100644 src/components/ProjectSettingsDialog/index.ts diff --git a/src/App.tsx b/src/App.tsx index 653b6a88e..9612ff03b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -41,6 +41,12 @@ const SetupPage = lazy(() => import("@src/pages/SetupPage" /* webpackChunkName: const Navigation = lazy(() => import("@src/layouts/Navigation" /* webpackChunkName: "Navigation" */)); // prettier-ignore const TableSettingsDialog = lazy(() => import("@src/components/TableSettingsDialog" /* webpackChunkName: "TableSettingsDialog" */)); +const ProjectSettingsDialog = lazy( + () => + import( + "@src/components/ProjectSettingsDialog" /* webpackChunkName: "ProjectSettingsDialog" */ + ) +); // prettier-ignore const TablesPage = lazy(() => import("@src/pages/TablesPage" /* webpackChunkName: "TablesPage" */)); @@ -99,6 +105,7 @@ export default function App() { + } diff --git a/src/atoms/projectScope/ui.ts b/src/atoms/projectScope/ui.ts index 48af64b02..01fc14996 100644 --- a/src/atoms/projectScope/ui.ts +++ b/src/atoms/projectScope/ui.ts @@ -131,6 +131,26 @@ export const tableSettingsDialogAtom = atom( } ); +export type ProjectSettingsDialogTab = + | "general" + | "rowy-run" + | "services" + | "secrets"; +export type ProjectSettingsDialogState = { + open: boolean; + tab: ProjectSettingsDialogTab; +}; +export const projectSettingsDialogAtom = atom( + { open: false, tab: "secrets" } as ProjectSettingsDialogState, + (_, set, update?: Partial) => { + set(projectSettingsDialogAtom, { + open: true, + tab: "secrets", + ...update, + }); + } +); + /** * Store the current ID of the table being edited in tableSettingsDialog * to derive tableSettingsDialogSchemaAtom diff --git a/src/components/ProjectSettingsDialog/ProjectSettingsDialog.tsx b/src/components/ProjectSettingsDialog/ProjectSettingsDialog.tsx new file mode 100644 index 000000000..6087c3e88 --- /dev/null +++ b/src/components/ProjectSettingsDialog/ProjectSettingsDialog.tsx @@ -0,0 +1,285 @@ +import React from "react"; +import { useAtom } from "jotai"; +import { + projectScope, + projectSettingsDialogAtom, + ProjectSettingsDialogTab, + rowyRunAtom, + secretNamesAtom, + updateSecretNamesAtom, +} from "@src/atoms/projectScope"; +import Modal from "@src/components/Modal"; +import { Box, Button, Paper, Tab, Tooltip, Typography } from "@mui/material"; +import { TabContext, TabPanel, TabList } from "@mui/lab"; +import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline"; +import EditIcon from "@mui/icons-material/Edit"; +import SecretDetailsModal from "./SecretDetailsModal"; +import { runRoutes } from "@src/constants/runRoutes"; + +export default function ProjectSettingsDialog() { + const [{ open, tab }, setProjectSettingsDialog] = useAtom( + projectSettingsDialogAtom, + projectScope + ); + const [secretNames] = useAtom(secretNamesAtom, projectScope); + const [secretDetailsModal, setSecretDetailsModal] = React.useState<{ + open: boolean; + loading?: boolean; + mode?: "add" | "edit" | "delete"; + secretName?: string; + error?: string; + }>({ + open: false, + }); + const [rowyRun] = useAtom(rowyRunAtom, projectScope); + const [updateSecretNames] = useAtom(updateSecretNamesAtom, projectScope); + + console.log("open", open); + console.log("tab", tab); + + if (!open) return null; + + const handleClose = () => { + setProjectSettingsDialog({ open: false }); + }; + + const handleTabChange = ( + event: React.SyntheticEvent, + newTab: ProjectSettingsDialogTab + ) => { + setProjectSettingsDialog({ tab: newTab }); + }; + + console.log(secretDetailsModal); + + return ( + <> + + + + + + + + + + + + Secrets + + + + {secretNames.secretNames?.map((secretName) => ( + + + {secretName} + + + + + + + + + + + ))} + + + + + } + /> + { + setSecretDetailsModal({ ...secretDetailsModal, open: false }); + }} + handleAdd={async (newSecretName, secretValue) => { + setSecretDetailsModal({ + ...secretDetailsModal, + loading: true, + }); + try { + await rowyRun({ + route: runRoutes.addSecret, + body: { + name: newSecretName, + value: secretValue, + }, + }); + setSecretDetailsModal({ + ...secretDetailsModal, + open: false, + loading: false, + }); + // update secret name causes an unknown modal-related bug, to be fixed + // updateSecretNames?.(); + } catch (error: any) { + console.error(error); + setSecretDetailsModal({ + ...secretDetailsModal, + error: error.message, + }); + } + }} + handleEdit={async (secretName, secretValue) => { + setSecretDetailsModal({ + ...secretDetailsModal, + loading: true, + }); + try { + await rowyRun({ + route: runRoutes.editSecret, + body: { + name: secretName, + value: secretValue, + }, + }); + setSecretDetailsModal({ + ...secretDetailsModal, + open: false, + loading: false, + }); + // update secret name causes an unknown modal-related bug, to be fixed + // updateSecretNames?.(); + } catch (error: any) { + console.error(error); + setSecretDetailsModal({ + ...secretDetailsModal, + error: error.message, + }); + } + }} + handleDelete={async (secretName) => { + setSecretDetailsModal({ + ...secretDetailsModal, + loading: true, + }); + try { + await rowyRun({ + route: runRoutes.deleteSecret, + body: { + name: secretName, + }, + }); + console.log("Setting", { + ...secretDetailsModal, + open: false, + loading: false, + }); + setSecretDetailsModal({ + ...secretDetailsModal, + open: false, + loading: false, + }); + // update secret name causes an unknown modal-related bug, to be fixed + // updateSecretNames?.(); + } catch (error: any) { + console.error(error); + setSecretDetailsModal({ + ...secretDetailsModal, + error: error.message, + }); + } + }} + /> + + ); +} diff --git a/src/components/ProjectSettingsDialog/SecretDetailsModal.tsx b/src/components/ProjectSettingsDialog/SecretDetailsModal.tsx new file mode 100644 index 000000000..11d436d12 --- /dev/null +++ b/src/components/ProjectSettingsDialog/SecretDetailsModal.tsx @@ -0,0 +1,158 @@ +import React, { useState } from "react"; +import Modal from "@src/components/Modal"; +import { Box, Button, TextField, Typography } from "@mui/material"; +import { capitalize } from "lodash-es"; +import LoadingButton from "@mui/lab/LoadingButton"; + +export interface ISecretDetailsModalProps { + open: boolean; + loading?: boolean; + mode?: "add" | "edit" | "delete"; + error?: string; + secretName?: string; + handleClose: () => void; + handleAdd: (secretName: string, secretValue: string) => void; + handleEdit: (secretName: string, secretValue: string) => void; + handleDelete: (secretName: string) => void; +} + +export default function SecretDetailsModal({ + open, + loading, + mode, + error, + secretName, + handleClose, + handleAdd, + handleEdit, + handleDelete, +}: ISecretDetailsModalProps) { + const [newSecretName, setNewSecretName] = useState(""); + const [secretValue, setSecretValue] = useState(""); + + console.log(open); + return ( + + {mode === "add" && ( + + Secret Name + setNewSecretName(e.target.value)} + /> + + This will create a secret key on Google Cloud. + + + )} + {mode === "delete" ? ( + + Are you sure you want to delete this secret key {secretName}? + + ) : ( + + Secret Value + setSecretValue(e.target.value)} + /> + + Paste your secret key here. + + + )} + {error?.length && ( + + {error} + + )} + + + { + switch (mode) { + case "add": + handleAdd(newSecretName, secretValue); + break; + case "edit": + handleEdit(secretName ?? "", secretValue); + break; + case "delete": + handleDelete(secretName ?? ""); + break; + } + }} + > + {mode === "delete" ? "Delete" : "Save"} + + + + } + /> + ); +} diff --git a/src/components/ProjectSettingsDialog/index.ts b/src/components/ProjectSettingsDialog/index.ts new file mode 100644 index 000000000..e57386ddc --- /dev/null +++ b/src/components/ProjectSettingsDialog/index.ts @@ -0,0 +1,2 @@ +export * from "./ProjectSettingsDialog"; +export { default } from "./ProjectSettingsDialog"; diff --git a/src/components/TableModals/WebhooksModal/Schemas/stripe.tsx b/src/components/TableModals/WebhooksModal/Schemas/stripe.tsx index 9c34383f6..0f146e7b0 100644 --- a/src/components/TableModals/WebhooksModal/Schemas/stripe.tsx +++ b/src/components/TableModals/WebhooksModal/Schemas/stripe.tsx @@ -7,6 +7,7 @@ import { projectScope, secretNamesAtom, updateSecretNamesAtom, + projectSettingsDialogAtom, } from "@src/atoms/projectScope"; import InputLabel from "@mui/material/InputLabel"; import MenuItem from "@mui/material/MenuItem"; @@ -56,6 +57,10 @@ export const webhookStripe = { Auth: (webhookObject: IWebhook, setWebhookObject: (w: IWebhook) => void) => { const [secretNames] = useAtom(secretNamesAtom, projectScope); const [updateSecretNames] = useAtom(updateSecretNamesAtom, projectScope); + const [{ open, tab }, setProjectSettingsDialog] = useAtom( + projectSettingsDialogAtom, + projectScope + ); return ( <> @@ -118,8 +123,9 @@ export const webhookStripe = { })} { - const secretManagerLink = `https://console.cloud.google.com/security/secret-manager/create`; - window?.open?.(secretManagerLink, "_blank")?.focus(); + setProjectSettingsDialog({ + open: true, + }); }} > Add a key in Secret Manager diff --git a/src/components/TableSettingsDialog/TableSettingsDialog.tsx b/src/components/TableSettingsDialog/TableSettingsDialog.tsx index 8424ce1ac..ecd94e4d4 100644 --- a/src/components/TableSettingsDialog/TableSettingsDialog.tsx +++ b/src/components/TableSettingsDialog/TableSettingsDialog.tsx @@ -411,7 +411,7 @@ export default function TableSettingsDialog() { }, /* * TODO: Figure out where to store this settings - + { id: "function", title: "Cloud Function", diff --git a/src/constants/runRoutes.ts b/src/constants/runRoutes.ts index b1504c3e0..96916b5f1 100644 --- a/src/constants/runRoutes.ts +++ b/src/constants/runRoutes.ts @@ -37,6 +37,9 @@ export const runRoutes = { setFirestoreRules: { path: "/setFirestoreRules", method: "POST" } as RunRoute, listCollections: { path: "/listCollections", method: "GET" } as RunRoute, listSecrets: { path: "/listSecrets", method: "GET" } as RunRoute, + addSecret: { path: "/addSecret", method: "POST" } as RunRoute, + editSecret: { path: "/editSecret", method: "POST" } as RunRoute, + deleteSecret: { path: "/deleteSecret", method: "POST" } as RunRoute, serviceAccountAccess: { path: "/serviceAccountAccess", method: "GET", From a0c59e8252fce0e72a7c9626c0bc8da02e025e7c Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Mon, 26 Jun 2023 21:06:10 +1000 Subject: [PATCH 02/20] remove console logs --- src/components/ProjectSettingsDialog/ProjectSettingsDialog.tsx | 3 --- src/components/ProjectSettingsDialog/SecretDetailsModal.tsx | 1 - 2 files changed, 4 deletions(-) diff --git a/src/components/ProjectSettingsDialog/ProjectSettingsDialog.tsx b/src/components/ProjectSettingsDialog/ProjectSettingsDialog.tsx index 6087c3e88..49e9c1c8b 100644 --- a/src/components/ProjectSettingsDialog/ProjectSettingsDialog.tsx +++ b/src/components/ProjectSettingsDialog/ProjectSettingsDialog.tsx @@ -34,9 +34,6 @@ export default function ProjectSettingsDialog() { const [rowyRun] = useAtom(rowyRunAtom, projectScope); const [updateSecretNames] = useAtom(updateSecretNamesAtom, projectScope); - console.log("open", open); - console.log("tab", tab); - if (!open) return null; const handleClose = () => { diff --git a/src/components/ProjectSettingsDialog/SecretDetailsModal.tsx b/src/components/ProjectSettingsDialog/SecretDetailsModal.tsx index 11d436d12..1e156429d 100644 --- a/src/components/ProjectSettingsDialog/SecretDetailsModal.tsx +++ b/src/components/ProjectSettingsDialog/SecretDetailsModal.tsx @@ -30,7 +30,6 @@ export default function SecretDetailsModal({ const [newSecretName, setNewSecretName] = useState(""); const [secretValue, setSecretValue] = useState(""); - console.log(open); return ( Date: Thu, 14 Sep 2023 01:29:10 +0530 Subject: [PATCH 03/20] tablename first click error fixed --- src/components/TableSettingsDialog/TableName.tsx | 2 +- src/components/TableSettingsDialog/form.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/TableSettingsDialog/TableName.tsx b/src/components/TableSettingsDialog/TableName.tsx index 1eebd2d90..36875c11e 100644 --- a/src/components/TableSettingsDialog/TableName.tsx +++ b/src/components/TableSettingsDialog/TableName.tsx @@ -27,7 +27,7 @@ export default function TableName({ watchedField, ...props }: ITableNameProps) { onChange(startCase(watchedValue)); } else if (typeof value === "string") { // otherwise if table name is valid, set watched value to table name - onChange(value.trim()); + onChange(startCase(value.trim())); } } }, [watchedValue, disabled, onChange, value]); diff --git a/src/components/TableSettingsDialog/form.tsx b/src/components/TableSettingsDialog/form.tsx index 9d611e068..31802e14b 100644 --- a/src/components/TableSettingsDialog/form.tsx +++ b/src/components/TableSettingsDialog/form.tsx @@ -213,7 +213,7 @@ export const tableSettings = ( name: "name", label: "Table name", required: true, - watchedField: "collection", + watchedField: "name", assistiveText: "User-facing name for this table", autoFocus: true, gridCols: { xs: 12, sm: 6 }, From e4194801c512f4b7da609763ad32df1bdbd07865 Mon Sep 17 00:00:00 2001 From: Vishnu Nithin Reddy <78612244+nithinrdy@users.noreply.github.com> Date: Thu, 21 Sep 2023 13:06:16 +0530 Subject: [PATCH 04/20] Create a `Table Settings` section. Contains options to customize saving behavior in case of changes to a table's sorting and columns' widths. --- .../Settings/UserSettings/TableSettings.tsx | 103 ++++++++++++++++++ src/pages/Settings/UserSettingsPage.tsx | 2 + src/types/settings.d.ts | 9 +- 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 src/components/Settings/UserSettings/TableSettings.tsx diff --git a/src/components/Settings/UserSettings/TableSettings.tsx b/src/components/Settings/UserSettings/TableSettings.tsx new file mode 100644 index 000000000..b2b441da5 --- /dev/null +++ b/src/components/Settings/UserSettings/TableSettings.tsx @@ -0,0 +1,103 @@ +import { merge } from "lodash-es"; +import { IUserSettingsChildProps } from "@src/pages/Settings/UserSettingsPage"; + +import { + FormControl, + FormControlLabel, + Divider, + Checkbox, + Collapse, +} from "@mui/material"; + +export default function TableSettings({ + settings, + updateSettings, +}: IUserSettingsChildProps) { + return ( + <> + + { + updateSettings({ + defaultTableSettings: merge(settings.defaultTableSettings, { + saveSortingPopupDisabled: e.target.checked, + }), + }); + }} + /> + } + label="Disable popup - to save sorting changes to the team" + style={{ marginLeft: -11, marginBottom: 13 }} + /> + + { + updateSettings({ + defaultTableSettings: merge(settings.defaultTableSettings, { + automaticallyApplySorting: e.target.checked, + }), + }); + }} + /> + } + label="Automatically apply sorting changes to all users" + style={{ marginLeft: 20, marginBottom: 10, marginTop: -13 }} + /> + + + + + { + updateSettings({ + defaultTableSettings: merge(settings.defaultTableSettings, { + saveColumnWidthPopupDisabled: e.target.checked, + }), + }); + }} + /> + } + label="Disable popup - to save column width changes to the team" + style={{ marginLeft: -11, marginTop: 13 }} + /> + + { + updateSettings({ + defaultTableSettings: merge(settings.defaultTableSettings, { + automaticallyApplyColumnWidth: e.target.checked, + }), + }); + }} + /> + } + label="Automatically apply column width changes to all users" + style={{ marginLeft: 20 }} + /> + + + + ); +} diff --git a/src/pages/Settings/UserSettingsPage.tsx b/src/pages/Settings/UserSettingsPage.tsx index 1981157f4..efcaad023 100644 --- a/src/pages/Settings/UserSettingsPage.tsx +++ b/src/pages/Settings/UserSettingsPage.tsx @@ -19,6 +19,7 @@ import { } from "@src/atoms/projectScope"; import { useScrollToHash } from "@src/hooks/useScrollToHash"; import { UserSettings } from "@src/types/settings"; +import TableSettings from "@src/components/Settings/UserSettings/TableSettings"; export interface IUserSettingsChildProps { settings: UserSettings; @@ -57,6 +58,7 @@ export default function UserSettingsPage() { const sections = [ { title: "Account", Component: Account, props: childProps }, { title: "Theme", Component: Theme, props: childProps }, + { title: "Table Settings", Component: TableSettings, props: childProps }, { title: "Personalization", Component: Personalization, props: childProps }, ]; diff --git a/src/types/settings.d.ts b/src/types/settings.d.ts index 334df8b9c..1f9bee100 100644 --- a/src/types/settings.d.ts +++ b/src/types/settings.d.ts @@ -50,7 +50,14 @@ export type UserSettings = Partial<{ theme: Record<"base" | "light" | "dark", ThemeOptions>; favoriteTables: string[]; - /** Stores user overrides */ + /** Stores default user settings for all tables */ + defaultTableSettings: Partial<{ + saveSortingPopupDisabled: boolean; + automaticallyApplySorting: boolean; + saveColumnWidthPopupDisabled: boolean; + automaticallyApplyColumnWidth: boolean; + }>; + /** Stores table-specific user overrides */ tables: Record< string, Partial<{ From 540373dbfd211820480bb94108c31a44d314dc37 Mon Sep 17 00:00:00 2001 From: Vishnu Nithin Reddy <78612244+nithinrdy@users.noreply.github.com> Date: Thu, 21 Sep 2023 20:51:21 +0530 Subject: [PATCH 05/20] Create atom to fetch `defaultTableSettings` from. Use atom in useSave*** hooks to determine if popups are to be shown (and if not, whether changes are to be applied automatically). --- src/atoms/projectScope/user.ts | 7 +++++ .../Table/ColumnHeader/useSaveTableSorts.tsx | 24 ++++++++++++++--- src/components/Table/useSaveColumnSizing.tsx | 26 +++++++++++++++++-- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/atoms/projectScope/user.ts b/src/atoms/projectScope/user.ts index 62bcc1756..e6337df73 100644 --- a/src/atoms/projectScope/user.ts +++ b/src/atoms/projectScope/user.ts @@ -30,6 +30,13 @@ export const themeOverriddenAtom = atomWithStorage( false ); +/** User's default table settings (affecting saving and popup behavior) */ +export const defaultTableSettingsAtom = atom((get) => { + const userSettings = get(userSettingsAtom); + console.log("defaultTableSettings", userSettings.defaultTableSettings); + return userSettings.defaultTableSettings; +}); + /** Customized base theme based on project and user settings */ export const customizedThemesAtom = atom((get) => { const publicSettings = get(publicSettingsAtom); diff --git a/src/components/Table/ColumnHeader/useSaveTableSorts.tsx b/src/components/Table/ColumnHeader/useSaveTableSorts.tsx index c0c239ed1..0d6e88216 100644 --- a/src/components/Table/ColumnHeader/useSaveTableSorts.tsx +++ b/src/components/Table/ColumnHeader/useSaveTableSorts.tsx @@ -1,5 +1,5 @@ import { useCallback, useState } from "react"; -import { useAtom } from "jotai"; +import { useAtom, useAtomValue } from "jotai"; import { SnackbarKey, useSnackbar } from "notistack"; import LoadingButton from "@mui/lab/LoadingButton"; @@ -11,17 +11,25 @@ import { tableScope, updateTableSchemaAtom, } from "@src/atoms/tableScope"; -import { projectScope, updateUserSettingsAtom } from "@src/atoms/projectScope"; +import { + defaultTableSettingsAtom, + projectScope, + updateUserSettingsAtom, +} from "@src/atoms/projectScope"; import { TableSort } from "@src/types/table"; function useSaveTableSorts(canEditColumns: boolean) { const [updateTableSchema] = useAtom(updateTableSchemaAtom, tableScope); const [updateUserSettings] = useAtom(updateUserSettingsAtom, projectScope); const [tableId] = useAtom(tableIdAtom, tableScope); + const defaultTableSettings = useAtomValue( + defaultTableSettingsAtom, + projectScope + ); const { enqueueSnackbar, closeSnackbar } = useSnackbar(); const [snackbarId, setSnackbarId] = useState(null); - // Offer to save when table sorts changes + // Offer to save when table sorts changes, depending on user settings const trigger = useCallback( (sorts: TableSort[]) => { if (!updateTableSchema) throw new Error("Cannot update table schema"); @@ -33,6 +41,15 @@ function useSaveTableSorts(canEditColumns: boolean) { }); } if (!canEditColumns) return; + // If the user has disabled the popup, return early + if (defaultTableSettings?.saveSortingPopupDisabled) { + // If the user has `automaticallyApplySorting` set to true, apply the sorting before returning + if (defaultTableSettings?.automaticallyApplySorting) { + const updateTable = async () => await updateTableSchema({ sorts }); + updateTable(); + } + return; + } if (snackbarId) { closeSnackbar(snackbarId); } @@ -57,6 +74,7 @@ function useSaveTableSorts(canEditColumns: boolean) { tableId, closeSnackbar, updateTableSchema, + defaultTableSettings, ] ); diff --git a/src/components/Table/useSaveColumnSizing.tsx b/src/components/Table/useSaveColumnSizing.tsx index af1a6e378..bae451185 100644 --- a/src/components/Table/useSaveColumnSizing.tsx +++ b/src/components/Table/useSaveColumnSizing.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { useSetAtom } from "jotai"; +import { useAtomValue, useSetAtom } from "jotai"; import { useSnackbar } from "notistack"; import { useDebounce } from "use-debounce"; import { isEqual, isEmpty } from "lodash-es"; @@ -13,6 +13,10 @@ import { updateColumnAtom, IUpdateColumnOptions, } from "@src/atoms/tableScope"; +import { + defaultTableSettingsAtom, + projectScope, +} from "@src/atoms/projectScope"; import { DEBOUNCE_DELAY } from "./Table"; import { ColumnSizingState } from "@tanstack/react-table"; @@ -26,14 +30,31 @@ export function useSaveColumnSizing( ) { const { enqueueSnackbar, closeSnackbar } = useSnackbar(); const updateColumn = useSetAtom(updateColumnAtom, tableScope); + const defaultTableSettings = useAtomValue( + defaultTableSettingsAtom, + projectScope + ); // Debounce for saving to schema const [debouncedColumnSizing] = useDebounce(columnSizing, DEBOUNCE_DELAY, { equalityFn: isEqual, }); - // Offer to save when column sizing changes + // Offer to save when column sizing changes, depending on user settings useEffect(() => { if (!canEditColumns || isEmpty(debouncedColumnSizing)) return; + // If the user has disabled the popup, return early + if (defaultTableSettings?.saveColumnWidthPopupDisabled) { + // If the user has `automaticallyApplyColumnWidth` set to true, apply the column width before returning + if (defaultTableSettings?.automaticallyApplyColumnWidth) { + const updateTable = async () => { + for (const [key, value] of Object.entries(debouncedColumnSizing)) { + await updateColumn({ key, config: { width: value } }); + } + }; + updateTable(); + } + return; + } const snackbarId = enqueueSnackbar("Save column sizes for all users?", { action: ( @@ -52,6 +73,7 @@ export function useSaveColumnSizing( enqueueSnackbar, closeSnackbar, updateColumn, + defaultTableSettings, ]); return null; From 03bbce2b97a928e758b8306399059fdffc2efd91 Mon Sep 17 00:00:00 2001 From: Vishnu Nithin Reddy <78612244+nithinrdy@users.noreply.github.com> Date: Thu, 21 Sep 2023 21:09:26 +0530 Subject: [PATCH 06/20] Remove stray console.log and better variable naming --- src/atoms/projectScope/user.ts | 1 - .../Settings/UserSettings/TableSettings.tsx | 20 +++++++++---------- .../Table/ColumnHeader/useSaveTableSorts.tsx | 6 +++--- src/components/Table/useSaveColumnSizing.tsx | 6 +++--- src/types/settings.d.ts | 8 ++++---- 5 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/atoms/projectScope/user.ts b/src/atoms/projectScope/user.ts index e6337df73..5c03281e0 100644 --- a/src/atoms/projectScope/user.ts +++ b/src/atoms/projectScope/user.ts @@ -33,7 +33,6 @@ export const themeOverriddenAtom = atomWithStorage( /** User's default table settings (affecting saving and popup behavior) */ export const defaultTableSettingsAtom = atom((get) => { const userSettings = get(userSettingsAtom); - console.log("defaultTableSettings", userSettings.defaultTableSettings); return userSettings.defaultTableSettings; }); diff --git a/src/components/Settings/UserSettings/TableSettings.tsx b/src/components/Settings/UserSettings/TableSettings.tsx index b2b441da5..6c4bfcb9d 100644 --- a/src/components/Settings/UserSettings/TableSettings.tsx +++ b/src/components/Settings/UserSettings/TableSettings.tsx @@ -20,12 +20,12 @@ export default function TableSettings({ control={ { updateSettings({ defaultTableSettings: merge(settings.defaultTableSettings, { - saveSortingPopupDisabled: e.target.checked, + saveSortsPopupDisabled: e.target.checked, }), }); }} @@ -34,17 +34,17 @@ export default function TableSettings({ label="Disable popup - to save sorting changes to the team" style={{ marginLeft: -11, marginBottom: 13 }} /> - + { updateSettings({ defaultTableSettings: merge(settings.defaultTableSettings, { - automaticallyApplySorting: e.target.checked, + automaticallyApplySorts: e.target.checked, }), }); }} @@ -61,12 +61,12 @@ export default function TableSettings({ control={ { updateSettings({ defaultTableSettings: merge(settings.defaultTableSettings, { - saveColumnWidthPopupDisabled: e.target.checked, + saveColumnSizingPopupDisabled: e.target.checked, }), }); }} @@ -76,18 +76,18 @@ export default function TableSettings({ style={{ marginLeft: -11, marginTop: 13 }} /> { updateSettings({ defaultTableSettings: merge(settings.defaultTableSettings, { - automaticallyApplyColumnWidth: e.target.checked, + automaticallyApplyColumnSizing: e.target.checked, }), }); }} diff --git a/src/components/Table/ColumnHeader/useSaveTableSorts.tsx b/src/components/Table/ColumnHeader/useSaveTableSorts.tsx index 0d6e88216..3c8c99806 100644 --- a/src/components/Table/ColumnHeader/useSaveTableSorts.tsx +++ b/src/components/Table/ColumnHeader/useSaveTableSorts.tsx @@ -42,9 +42,9 @@ function useSaveTableSorts(canEditColumns: boolean) { } if (!canEditColumns) return; // If the user has disabled the popup, return early - if (defaultTableSettings?.saveSortingPopupDisabled) { - // If the user has `automaticallyApplySorting` set to true, apply the sorting before returning - if (defaultTableSettings?.automaticallyApplySorting) { + if (defaultTableSettings?.saveSortsPopupDisabled) { + // If the user has `automaticallyApplySorts` set to true, apply the sorting before returning + if (defaultTableSettings?.automaticallyApplySorts) { const updateTable = async () => await updateTableSchema({ sorts }); updateTable(); } diff --git a/src/components/Table/useSaveColumnSizing.tsx b/src/components/Table/useSaveColumnSizing.tsx index bae451185..68ec4668f 100644 --- a/src/components/Table/useSaveColumnSizing.tsx +++ b/src/components/Table/useSaveColumnSizing.tsx @@ -43,9 +43,9 @@ export function useSaveColumnSizing( useEffect(() => { if (!canEditColumns || isEmpty(debouncedColumnSizing)) return; // If the user has disabled the popup, return early - if (defaultTableSettings?.saveColumnWidthPopupDisabled) { - // If the user has `automaticallyApplyColumnWidth` set to true, apply the column width before returning - if (defaultTableSettings?.automaticallyApplyColumnWidth) { + if (defaultTableSettings?.saveColumnSizingPopupDisabled) { + // If the user has `automaticallyApplyColumnSizing` set to true, apply the column width before returning + if (defaultTableSettings?.automaticallyApplyColumnSizing) { const updateTable = async () => { for (const [key, value] of Object.entries(debouncedColumnSizing)) { await updateColumn({ key, config: { width: value } }); diff --git a/src/types/settings.d.ts b/src/types/settings.d.ts index 1f9bee100..0c5321d16 100644 --- a/src/types/settings.d.ts +++ b/src/types/settings.d.ts @@ -52,10 +52,10 @@ export type UserSettings = Partial<{ favoriteTables: string[]; /** Stores default user settings for all tables */ defaultTableSettings: Partial<{ - saveSortingPopupDisabled: boolean; - automaticallyApplySorting: boolean; - saveColumnWidthPopupDisabled: boolean; - automaticallyApplyColumnWidth: boolean; + saveSortsPopupDisabled: boolean; + automaticallyApplySorts: boolean; + saveColumnSizingPopupDisabled: boolean; + automaticallyApplyColumnSizing: boolean; }>; /** Stores table-specific user overrides */ tables: Record< From 6e21feba0d45f160734139c434b190801294428e Mon Sep 17 00:00:00 2001 From: Vishnu Nithin Reddy <78612244+nithinrdy@users.noreply.github.com> Date: Thu, 21 Sep 2023 21:16:23 +0530 Subject: [PATCH 07/20] Group like imports --- src/pages/Settings/UserSettingsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Settings/UserSettingsPage.tsx b/src/pages/Settings/UserSettingsPage.tsx index efcaad023..83b30e789 100644 --- a/src/pages/Settings/UserSettingsPage.tsx +++ b/src/pages/Settings/UserSettingsPage.tsx @@ -9,6 +9,7 @@ import SettingsSkeleton from "@src/components/Settings/SettingsSkeleton"; import SettingsSection from "@src/components/Settings/SettingsSection"; import Account from "@src/components/Settings/UserSettings/Account"; import Theme from "@src/components/Settings/UserSettings/Theme"; +import TableSettings from "@src/components/Settings/UserSettings/TableSettings"; import Personalization from "@src/components/Settings/UserSettings/Personalization"; import { @@ -19,7 +20,6 @@ import { } from "@src/atoms/projectScope"; import { useScrollToHash } from "@src/hooks/useScrollToHash"; import { UserSettings } from "@src/types/settings"; -import TableSettings from "@src/components/Settings/UserSettings/TableSettings"; export interface IUserSettingsChildProps { settings: UserSettings; From d3e89e6014022162c7cc268ca8e618e9d44376b8 Mon Sep 17 00:00:00 2001 From: janvi01 Date: Mon, 2 Oct 2023 11:47:52 +0530 Subject: [PATCH 08/20] feat: added tooltip to buttons --- src/components/TableInformationDrawer/Details.tsx | 2 ++ .../TableInformationDrawer/TableInformationDrawer.tsx | 1 + src/components/TableSettingsDialog/ActionsMenu/ActionsMenu.tsx | 1 + src/components/TableSettingsDialog/DeleteMenu.tsx | 1 + src/pages/TablesPage.tsx | 3 +++ 5 files changed, 8 insertions(+) diff --git a/src/components/TableInformationDrawer/Details.tsx b/src/components/TableInformationDrawer/Details.tsx index 78dd02364..de5a26414 100644 --- a/src/components/TableInformationDrawer/Details.tsx +++ b/src/components/TableInformationDrawer/Details.tsx @@ -100,6 +100,7 @@ export default function Details() { {isAdmin && ( { setEditDescription(!editDescription); }} @@ -147,6 +148,7 @@ export default function Details() { {isAdmin && ( { setEditDetails(!editDetails); }} diff --git a/src/components/TableInformationDrawer/TableInformationDrawer.tsx b/src/components/TableInformationDrawer/TableInformationDrawer.tsx index 25b9a5e8e..22568666b 100644 --- a/src/components/TableInformationDrawer/TableInformationDrawer.tsx +++ b/src/components/TableInformationDrawer/TableInformationDrawer.tsx @@ -114,6 +114,7 @@ export default function SideDrawer() { setSideDrawer(RESET)} aria-label="Close" + title="Close" > diff --git a/src/components/TableSettingsDialog/ActionsMenu/ActionsMenu.tsx b/src/components/TableSettingsDialog/ActionsMenu/ActionsMenu.tsx index 3dc853a4a..49165f784 100644 --- a/src/components/TableSettingsDialog/ActionsMenu/ActionsMenu.tsx +++ b/src/components/TableSettingsDialog/ActionsMenu/ActionsMenu.tsx @@ -53,6 +53,7 @@ export default function ActionsMenu({ openTableSettingsDialog({ mode: "update", data: table }) } @@ -151,6 +152,7 @@ export default function TablesPage() { onChange={handleFavorite(table.id)} checked={favorites.includes(table.id)} icon={} + title="Favorite" checkedIcon={ @@ -163,6 +165,7 @@ export default function TablesPage() { /> Date: Mon, 2 Oct 2023 12:13:07 +0530 Subject: [PATCH 09/20] fix: added mui tooltip component --- .../TableInformationDrawer/Details.tsx | 43 ++++++------ .../TableInformationDrawer.tsx | 16 +++-- .../ActionsMenu/ActionsMenu.tsx | 25 +++---- .../TableSettingsDialog/DeleteMenu.tsx | 31 +++++---- src/pages/TablesPage.tsx | 67 ++++++++++--------- 5 files changed, 99 insertions(+), 83 deletions(-) diff --git a/src/components/TableInformationDrawer/Details.tsx b/src/components/TableInformationDrawer/Details.tsx index de5a26414..b097198a1 100644 --- a/src/components/TableInformationDrawer/Details.tsx +++ b/src/components/TableInformationDrawer/Details.tsx @@ -8,6 +8,7 @@ import { IconButton, Stack, TextField, + Tooltip, Typography, useTheme, } from "@mui/material"; @@ -98,16 +99,17 @@ export default function Details() { Description {isAdmin && ( - { - setEditDescription(!editDescription); - }} - sx={{ top: 4 }} - > - {editDescription ? : } - + + { + setEditDescription(!editDescription); + }} + sx={{ top: 4 }} + > + {editDescription ? : } + + )} {editDescription ? ( @@ -146,16 +148,17 @@ export default function Details() { Details {isAdmin && ( - { - setEditDetails(!editDetails); - }} - sx={{ top: 4 }} - > - {editDetails ? : } - + + { + setEditDetails(!editDetails); + }} + sx={{ top: 4 }} + > + {editDetails ? : } + + )} - setSideDrawer(RESET)} - aria-label="Close" - title="Close" - > - - + + setSideDrawer(RESET)} + aria-label="Close" + > + + + - - {mode === "create" ? : } - + + + {mode === "create" ? : } + + - setAnchorEl(e.currentTarget)} - > - - + + setAnchorEl(e.currentTarget)} + > + + + ( <> {userRoles.includes("ADMIN") && ( - - openTableSettingsDialog({ mode: "update", data: table }) + + + openTableSettingsDialog({ mode: "update", data: table }) + } + size={view === "list" ? "large" : undefined} + > + + + + )} + + } + checkedIcon={ + + + } + name={`favorite-${table.id}`} + inputProps={{ "aria-label": "Favorite" }} + sx={view === "list" ? { p: 1.5 } : undefined} + color="secondary" + /> + + + - + - )} - } - title="Favorite" - checkedIcon={ - - - - } - name={`favorite-${table.id}`} - inputProps={{ "aria-label": "Favorite" }} - sx={view === "list" ? { p: 1.5 } : undefined} - color="secondary" - /> - - - + ); From 9f52e09064e26d7f62eccba40797c2477127c6bd Mon Sep 17 00:00:00 2001 From: Vishnu Nithin Reddy <78612244+nithinrdy@users.noreply.github.com> Date: Tue, 3 Oct 2023 11:01:40 +0530 Subject: [PATCH 10/20] Add Field Key input field to CSV import step 1, next to Column Select field - Update key and fieldName properties onChange --- .../ImportCsvWizard/Step1Columns.tsx | 223 +++++++++++------- 1 file changed, 144 insertions(+), 79 deletions(-) diff --git a/src/components/TableModals/ImportCsvWizard/Step1Columns.tsx b/src/components/TableModals/ImportCsvWizard/Step1Columns.tsx index 888b87e57..5baa86168 100644 --- a/src/components/TableModals/ImportCsvWizard/Step1Columns.tsx +++ b/src/components/TableModals/ImportCsvWizard/Step1Columns.tsx @@ -257,8 +257,16 @@ export default function Step1Columns({ const isNewColumn = !!find(config.newColumns, { key: columnKey }); return ( - - + + - + {selected && ( - { - if (!columnKey) return "Select or add column"; - else - return ( - - - {!isNewColumn ? ( - getFieldProp("icon", matchingColumn?.type) - ) : ( - - )} - - {matchingColumn?.name} - {isNewColumn && ( - - )} - - ); - }, - sx: [ - { - backgroundColor: "background.default", - border: (theme) => - `1px solid ${theme.palette.divider}`, - borderRadius: 0, - boxShadow: "none", - "& .MuiSelect-select": { - boxSizing: "border-box", - height: COLUMN_HEADER_HEIGHT - 2, - typography: "caption", - fontWeight: "medium", - lineHeight: "28px", + <> + + { + if (!columnKey) return "Select or add column"; + else + return ( + + + {!isNewColumn ? ( + getFieldProp( + "icon", + matchingColumn?.type + ) + ) : ( + + )} + + {matchingColumn?.name} + {isNewColumn && ( + + )} + + ); }, + sx: [ + { + backgroundColor: "background.default", + border: (theme) => + `1px solid ${theme.palette.divider}`, + borderRadius: 0, + boxShadow: "none", + "& .MuiSelect-select": { + boxSizing: "border-box", + height: COLUMN_HEADER_HEIGHT - 2, + typography: "caption", + fontWeight: "medium", + lineHeight: "28px", + }, - color: "text.secondary", - "&:hover": { - backgroundColor: "background.default", - color: "text.primary", - boxShadow: "none", - }, + color: "text.secondary", + "&:hover": { + backgroundColor: "background.default", + color: "text.primary", + boxShadow: "none", + }, - "&::before": { content: "none" }, - "&::after": { pointerEvents: "none" }, + "&::before": { content: "none" }, + "&::after": { pointerEvents: "none" }, + }, + !columnKey && { color: "text.disabled" }, + ], + }, + sx: { "& .MuiInputLabel-root": { display: "none" } }, + }} + clearable={false} + displayEmpty + freeText + AddButtonProps={{ children: "Create column…" }} + AddDialogProps={{ + title: "Create column", + textFieldLabel: "Column name", + }} + /> + + + pair.columnKey === columnKey + )?.columnKey ?? + config.newColumns.find( + (pair) => pair.key === columnKey + )?.key + } + onChange={(e) => { + const newKey = e.target.value; + const newPairs = config.pairs.map((pair) => { + if (pair.columnKey === columnKey) { + return { ...pair, columnKey: newKey }; + } else { + return pair; + } + }); + + const newColumns = config.newColumns.map((column) => { + if (column.key === columnKey) { + return { + ...column, + key: newKey, + fieldName: newKey, + }; + } else { + return column; + } + }); + + setConfig((config) => ({ + ...config, + pairs: newPairs, + newColumns, + })); + }} + sx={{ + "& .MuiInputLabel-root": { + position: "absolute", + transform: "translateY(-100%)", + }, + "& .MuiInputBase-root": { + height: 40, }, - !columnKey && { color: "text.disabled" }, - ], - }, - sx: { "& .MuiInputLabel-root": { display: "none" } }, - }} - clearable={false} - displayEmpty - freeText - AddButtonProps={{ children: "Create column…" }} - AddDialogProps={{ - title: "Create column", - textFieldLabel: "Column name", - }} - /> + }} + /> + + )} From 8984f398e2da9f6e629ab87ac2587c1468376fe6 Mon Sep 17 00:00:00 2001 From: Vishnu Nithin Reddy <78612244+nithinrdy@users.noreply.github.com> Date: Tue, 3 Oct 2023 11:11:32 +0530 Subject: [PATCH 11/20] Disable next if fieldKeys are empty strings --- .../TableModals/ImportCsvWizard/ImportCsvWizard.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/TableModals/ImportCsvWizard/ImportCsvWizard.tsx b/src/components/TableModals/ImportCsvWizard/ImportCsvWizard.tsx index 4f3f9a9e2..f7989d264 100644 --- a/src/components/TableModals/ImportCsvWizard/ImportCsvWizard.tsx +++ b/src/components/TableModals/ImportCsvWizard/ImportCsvWizard.tsx @@ -323,7 +323,9 @@ export default function ImportCsvWizard({ onClose }: ITableModalProps) { disableNext: config.pairs.length === 0 || !validRows || - (config.documentId === "column" && !config.documentIdCsvKey), + (config.documentId === "column" && !config.documentIdCsvKey) || + config.pairs.some((pair) => !pair.columnKey) || + config.newColumns.some((col) => !col.key), }, config.newColumns.length > 0 && { title: "Set column types", From c0b04884e66294556a20b0335f7c4f9124deeaca Mon Sep 17 00:00:00 2001 From: Vishnu Nithin Reddy <78612244+nithinrdy@users.noreply.github.com> Date: Wed, 4 Oct 2023 18:17:39 +0530 Subject: [PATCH 12/20] Move save pop-ups out of the way, to the corner --- src/components/Table/ColumnHeader/useSaveTableSorts.tsx | 2 +- src/components/Table/useSaveColumnSizing.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Table/ColumnHeader/useSaveTableSorts.tsx b/src/components/Table/ColumnHeader/useSaveTableSorts.tsx index 3c8c99806..76efdbefc 100644 --- a/src/components/Table/ColumnHeader/useSaveTableSorts.tsx +++ b/src/components/Table/ColumnHeader/useSaveTableSorts.tsx @@ -60,7 +60,7 @@ function useSaveTableSorts(canEditColumns: boolean) { updateTable={async () => await updateTableSchema({ sorts })} /> ), - anchorOrigin: { horizontal: "center", vertical: "top" }, + anchorOrigin: { horizontal: "left", vertical: "bottom" }, }) ); diff --git a/src/components/Table/useSaveColumnSizing.tsx b/src/components/Table/useSaveColumnSizing.tsx index 68ec4668f..b0c1d55c8 100644 --- a/src/components/Table/useSaveColumnSizing.tsx +++ b/src/components/Table/useSaveColumnSizing.tsx @@ -63,7 +63,7 @@ export function useSaveColumnSizing( updateColumn={updateColumn} /> ), - anchorOrigin: { horizontal: "center", vertical: "top" }, + anchorOrigin: { horizontal: "left", vertical: "bottom" }, }); return () => closeSnackbar(snackbarId); From 4ed7a89a31d198aad6b01bac8dc3b82c9c3aa627 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Fri, 13 Oct 2023 18:50:46 +0800 Subject: [PATCH 13/20] add buildship authenticated trigger --- src/components/CodeEditor/extensions.d.ts | 8 ++++++++ .../TableModals/ExtensionsModal/utils.ts | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/components/CodeEditor/extensions.d.ts b/src/components/CodeEditor/extensions.d.ts index 22af57566..a61232b7b 100644 --- a/src/components/CodeEditor/extensions.d.ts +++ b/src/components/CodeEditor/extensions.d.ts @@ -128,4 +128,12 @@ type PushNotificationRequest = { type PushNotificationBody = ( context: ExtensionContext ) => Message | Message[] | Promise; + type TaskBody = (context: ExtensionContext) => Promise; + +type BuildshipAuthenticatedTriggerBody = ( + context: ExtensionContext +) => Promise<{ + url: string; + body: string; +}>; diff --git a/src/components/TableModals/ExtensionsModal/utils.ts b/src/components/TableModals/ExtensionsModal/utils.ts index 8254ff42b..59587a5f4 100644 --- a/src/components/TableModals/ExtensionsModal/utils.ts +++ b/src/components/TableModals/ExtensionsModal/utils.ts @@ -1,4 +1,5 @@ export const extensionTypes = [ + "buildshipAuthenticatedTrigger", "task", "docSync", "historySnapshot", @@ -15,6 +16,7 @@ export const extensionTypes = [ export type ExtensionType = typeof extensionTypes[number]; export const extensionNames: Record = { + buildshipAuthenticatedTrigger: "Buildship Authenticated Trigger", task: "Task", docSync: "Doc Sync", historySnapshot: "History Snapshot", @@ -61,6 +63,18 @@ export interface IRuntimeOptions { export const triggerTypes: ExtensionTrigger[] = ["create", "update", "delete"]; const extensionBodyTemplate = { + buildshipAuthenticatedTrigger: `const extensionBody: BuildshipAuthenticatedTriggerBody = async({row, db, change, ref, logging}) => { + logging.log("extensionBody started") + + // Put your endpoint URL and request body below. + // It will trigger your endpoint with the request body. + return ({ + url: "", + body: JSON.stringify({ + + }) + }) +}`, task: `const extensionBody: TaskBody = async({row, db, change, ref, logging}) => { logging.log("extensionBody started") From fe16570a941bb6631288a34af6384ee5265aff3d Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Wed, 18 Oct 2023 05:54:11 +0800 Subject: [PATCH 14/20] fix buildship typo --- src/components/TableModals/ExtensionsModal/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/TableModals/ExtensionsModal/utils.ts b/src/components/TableModals/ExtensionsModal/utils.ts index 59587a5f4..05c5cb6b7 100644 --- a/src/components/TableModals/ExtensionsModal/utils.ts +++ b/src/components/TableModals/ExtensionsModal/utils.ts @@ -16,7 +16,7 @@ export const extensionTypes = [ export type ExtensionType = typeof extensionTypes[number]; export const extensionNames: Record = { - buildshipAuthenticatedTrigger: "Buildship Authenticated Trigger", + buildshipAuthenticatedTrigger: "BuildShip Authenticated Trigger", task: "Task", docSync: "Doc Sync", historySnapshot: "History Snapshot", From 1646e99e499c6548001d768f956961da6ead5957 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Thu, 19 Oct 2023 06:24:46 +0800 Subject: [PATCH 15/20] add prefilled values for buildship extension --- src/components/TableModals/ExtensionsModal/utils.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/TableModals/ExtensionsModal/utils.ts b/src/components/TableModals/ExtensionsModal/utils.ts index 05c5cb6b7..02a95ffc7 100644 --- a/src/components/TableModals/ExtensionsModal/utils.ts +++ b/src/components/TableModals/ExtensionsModal/utils.ts @@ -71,7 +71,16 @@ const extensionBodyTemplate = { return ({ url: "", body: JSON.stringify({ - + row, + ref: { + id: ref.id, + path: ref.path + }, + change: { + before: change.before.get(), + after: change.after.get(), + }, + // Add your own payload here }) }) }`, From 90f2136fb166351c0b793c03ac8852adfbcc0bf5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Oct 2023 16:54:00 +0000 Subject: [PATCH 16/20] Bump tinymce from 5.10.7 to 5.10.8 Bumps [tinymce](https://github.com/tinymce/tinymce/tree/HEAD/modules/tinymce) from 5.10.7 to 5.10.8. - [Changelog](https://github.com/tinymce/tinymce/blob/5.10.8/modules/tinymce/CHANGELOG.md) - [Commits](https://github.com/tinymce/tinymce/commits/5.10.8/modules/tinymce) --- updated-dependencies: - dependency-name: tinymce dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8ff8ab683..84605ad19 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12043,9 +12043,9 @@ tiny-invariant@^1.0.6: integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== tinymce@^5, tinymce@^5.5.1: - version "5.10.7" - resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-5.10.7.tgz#d89d446f1962f2a1df6b2b70018ce475ec7ffb80" - integrity sha512-9UUjaO0R7FxcFo0oxnd1lMs7H+D0Eh+dDVo5hKbVe1a+VB0nit97vOqlinj+YwgoBDt6/DSCUoWqAYlLI8BLYA== + version "5.10.8" + resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-5.10.8.tgz#c85758fa3cca2cbb4b14dd037a0b315b6462c50e" + integrity sha512-iyoo3VGMAJhLMDdblAefKvYgBRk9kQi58GTwAmoieqsyggGsKZWlQl/YY6nTILFHUCA1FhYu0HdmM5YYjs17UQ== tmp@^0.2.1: version "0.2.1" From 80a408063a30b37e980e3a7fec780428047adccc Mon Sep 17 00:00:00 2001 From: Vishnu Nithin Reddy <78612244+nithinrdy@users.noreply.github.com> Date: Mon, 23 Oct 2023 00:07:35 +0530 Subject: [PATCH 17/20] Retrieve clipboard data from the event instead --- src/components/Table/Table.tsx | 10 +- src/components/Table/useHotKey.tsx | 1 - src/components/Table/useMenuAction.tsx | 138 ++++++++++++++----------- 3 files changed, 87 insertions(+), 62 deletions(-) diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index a4b859572..ba17786ba 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -285,7 +285,7 @@ export default function Table({ const { handler: hotKeysHandler } = useHotKeys([ ["mod+C", handleCopy], ["mod+X", handleCut], - ["mod+V", handlePaste], + ["mod+V", (e) => handlePaste], // So the event isn't passed to the handler ]); // Handle prompt to save local column sizes if user `canEditColumns` @@ -324,6 +324,14 @@ export default function Table({ fetchMoreOnBottomReached(containerRef.current); }, [fetchMoreOnBottomReached, tableNextPage.loading, containerRef]); + useEffect(() => { + document.addEventListener("paste", handlePaste); + + return () => { + document.removeEventListener("paste", handlePaste); + }; + }, [handlePaste]); + // apply user default sort on first render const [applySort, setApplySort] = useState(true); useEffect(() => { diff --git a/src/components/Table/useHotKey.tsx b/src/components/Table/useHotKey.tsx index cf74808e9..e57d9c84b 100644 --- a/src/components/Table/useHotKey.tsx +++ b/src/components/Table/useHotKey.tsx @@ -12,7 +12,6 @@ export default function useHotKeys(actions: HotKeysAction[]) { const event_ = "nativeEvent" in event ? event.nativeEvent : event; actions.forEach(([hotkey, handler_]) => { if (getHotkeyMatcher(hotkey)(event_)) { - event.preventDefault(); handler_(event_); } }); diff --git a/src/components/Table/useMenuAction.tsx b/src/components/Table/useMenuAction.tsx index dbe55907f..9654a30a5 100644 --- a/src/components/Table/useMenuAction.tsx +++ b/src/components/Table/useMenuAction.tsx @@ -161,71 +161,89 @@ export function useMenuAction( handleClose, ]); - const handlePaste = useCallback(async () => { - try { - if (!selectedCell || !selectedCol) return; - let text; + const handlePaste = useCallback( + async (e?: ClipboardEvent) => { try { - text = await navigator.clipboard.readText(); - } catch (e) { - enqueueSnackbar(`Read clipboard permission denied.`, { - variant: "error", - }); - return; - } - const cellDataType = getFieldProp("dataType", getFieldType(selectedCol)); - let parsed; - switch (cellDataType) { - case "number": - parsed = Number(text); - if (isNaN(parsed)) throw new Error(`${text} is not a number`); - break; - case "string": - parsed = text; - break; - case "reference": + if (!selectedCell || !selectedCol) return; + let text: string; + // Firefox doesn't allow for reading clipboard data, hence the workaround + if (navigator.userAgent.includes("Firefox")) { + if (!e || !e.clipboardData) { + enqueueSnackbar(`Cannot read clipboard data.`, { + variant: "error", + }); + return; + } + text = e.clipboardData.getData("text/plain") || ""; + } else { try { - parsed = doc(firebaseDb, text); - } catch (e: any) { - enqueueSnackbar(`Invalid reference.`, { variant: "error" }); + text = await navigator.clipboard.readText(); + } catch (e) { + enqueueSnackbar(`Read clipboard permission denied.`, { + variant: "error", + }); + return; } - break; - default: - parsed = JSON.parse(text); - break; - } + } + const cellDataType = getFieldProp( + "dataType", + getFieldType(selectedCol) + ); + let parsed; + switch (cellDataType) { + case "number": + parsed = Number(text); + if (isNaN(parsed)) throw new Error(`${text} is not a number`); + break; + case "string": + parsed = text; + break; + case "reference": + try { + parsed = doc(firebaseDb, text); + } catch (e: any) { + enqueueSnackbar(`Invalid reference.`, { variant: "error" }); + } + break; + default: + parsed = JSON.parse(text); + break; + } - if (selectedCol.type === FieldType.slider) { - if (parsed < selectedCol.config?.min) parsed = selectedCol.config?.min; - else if (parsed > selectedCol.config?.max) - parsed = selectedCol.config?.max; - } + if (selectedCol.type === FieldType.slider) { + if (parsed < selectedCol.config?.min) + parsed = selectedCol.config?.min; + else if (parsed > selectedCol.config?.max) + parsed = selectedCol.config?.max; + } - if (selectedCol.type === FieldType.rating) { - if (parsed < 0) parsed = 0; - if (parsed > (selectedCol.config?.max || 5)) - parsed = selectedCol.config?.max || 5; - } + if (selectedCol.type === FieldType.rating) { + if (parsed < 0) parsed = 0; + if (parsed > (selectedCol.config?.max || 5)) + parsed = selectedCol.config?.max || 5; + } - if (selectedCol.type === FieldType.percentage) { - parsed = parsed / 100; + if (selectedCol.type === FieldType.percentage) { + parsed = parsed / 100; + } + updateField({ + path: selectedCell.path, + fieldName: selectedCol.fieldName, + value: parsed, + arrayTableData: { + index: selectedCell.arrayIndex, + }, + }); + } catch (error) { + enqueueSnackbar( + `${selectedCol?.type} field does not support the data type being pasted`, + { variant: "error" } + ); } - updateField({ - path: selectedCell.path, - fieldName: selectedCol.fieldName, - value: parsed, - arrayTableData: { - index: selectedCell.arrayIndex, - }, - }); - } catch (error) { - enqueueSnackbar( - `${selectedCol?.type} field does not support the data type being pasted`, - { variant: "error" } - ); - } - if (handleClose) handleClose(); - }, [selectedCell, selectedCol, updateField, enqueueSnackbar, handleClose]); + if (handleClose) handleClose(); + }, + [selectedCell, selectedCol, updateField, enqueueSnackbar, handleClose] + ); useEffect(() => { if (!selectedCell) return setCellValue(""); @@ -276,9 +294,9 @@ export function useMenuAction( }; } const fieldType = getFieldType(selectedCol); - return function () { + return function (e?: ClipboardEvent) { if (SUPPORTED_TYPES_PASTE.has(fieldType)) { - return func(); + return func(e); } else { enqueueSnackbar( `${fieldType} field does not support paste functionality`, From b30395f28ca9ceaaa9ac491699eff1570f3324f6 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Mon, 23 Oct 2023 06:49:53 +0800 Subject: [PATCH 18/20] update buildship trigger body config --- src/components/TableModals/ExtensionsModal/utils.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/TableModals/ExtensionsModal/utils.ts b/src/components/TableModals/ExtensionsModal/utils.ts index 02a95ffc7..fbeb71df6 100644 --- a/src/components/TableModals/ExtensionsModal/utils.ts +++ b/src/components/TableModals/ExtensionsModal/utils.ts @@ -69,7 +69,10 @@ const extensionBodyTemplate = { // Put your endpoint URL and request body below. // It will trigger your endpoint with the request body. return ({ - url: "", + buildshipConfig: { + projectId: "", + workflowId: "" + }, body: JSON.stringify({ row, ref: { From a249b3d20a83a05e3f1e4daecbe05e693601d0e6 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Mon, 23 Oct 2023 06:54:43 +0800 Subject: [PATCH 19/20] update buildship trigger context type --- src/components/CodeEditor/extensions.d.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/CodeEditor/extensions.d.ts b/src/components/CodeEditor/extensions.d.ts index a61232b7b..d57c5e216 100644 --- a/src/components/CodeEditor/extensions.d.ts +++ b/src/components/CodeEditor/extensions.d.ts @@ -134,6 +134,9 @@ type TaskBody = (context: ExtensionContext) => Promise; type BuildshipAuthenticatedTriggerBody = ( context: ExtensionContext ) => Promise<{ - url: string; + buildshipConfig: { + projectId: string; + workflowId: string; + }; body: string; }>; From 7bedf8b47dd62ea62366229c7f52018bf1421a62 Mon Sep 17 00:00:00 2001 From: Vishnu Nithin Reddy <78612244+nithinrdy@users.noreply.github.com> Date: Mon, 23 Oct 2023 12:25:12 +0530 Subject: [PATCH 20/20] Add info snackbar for Firefox users --- src/components/Table/useMenuAction.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/components/Table/useMenuAction.tsx b/src/components/Table/useMenuAction.tsx index 9654a30a5..3a1d45992 100644 --- a/src/components/Table/useMenuAction.tsx +++ b/src/components/Table/useMenuAction.tsx @@ -169,6 +169,13 @@ export function useMenuAction( // Firefox doesn't allow for reading clipboard data, hence the workaround if (navigator.userAgent.includes("Firefox")) { if (!e || !e.clipboardData) { + enqueueSnackbar( + `If you're on Firefox, please use the hotkey instead (Ctrl + V / Cmd + V).`, + { + variant: "info", + autoHideDuration: 7000, + } + ); enqueueSnackbar(`Cannot read clipboard data.`, { variant: "error", });