From 61a6e41250faf7d066d887659a167b32ec42a144 Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Mon, 3 Jan 2022 23:22:29 +0700 Subject: [PATCH 01/36] connect-service config --- .../fields/ConnectService/Settings.tsx | 323 +++++++++++++++++- .../fields/ConnectService/types.d.ts | 5 + src/components/fields/ConnectService/utils.ts | 5 + 3 files changed, 329 insertions(+), 4 deletions(-) create mode 100644 src/components/fields/ConnectService/types.d.ts diff --git a/src/components/fields/ConnectService/Settings.tsx b/src/components/fields/ConnectService/Settings.tsx index f0ed6d685..93702cb83 100644 --- a/src/components/fields/ConnectService/Settings.tsx +++ b/src/components/fields/ConnectService/Settings.tsx @@ -1,8 +1,324 @@ -import { TextField, FormControlLabel, Switch, Grid } from "@mui/material"; +import { lazy, Suspense, useState } from "react"; +import _get from "lodash/get"; +import stringify from "json-stable-stringify-without-jsonify"; + +import { + Stepper, + Step, + StepButton, + StepContent, + Stack, + Grid, + Switch, + TextField, + FormControl, + FormLabel, + FormControlLabel, + RadioGroup, + Radio, + Typography, + InputLabel, + Link, + Checkbox, + FormHelperText, + Fab, +} from "@mui/material"; + +import SteppedAccordion from "@src/components/SteppedAccordion"; +import MultiSelect from "@rowy/multiselect"; +import FieldSkeleton from "@src/components/SideDrawer/Form/FieldSkeleton"; +import CodeEditorHelper from "@src/components/CodeEditor/CodeEditorHelper"; +import InlineOpenInNewIcon from "@src/components/InlineOpenInNewIcon"; + +import { useProjectContext } from "@src/contexts/ProjectContext"; +import { WIKI_LINKS } from "@src/constants/externalLinks"; +import { useAppContext } from "@src/contexts/AppContext"; +import { baseFunction } from "./utils"; + +//import typeDefs from "!!raw-loader!./types.d.ts"; +const CodeEditor = lazy( + () => + import("@src/components/CodeEditor" /* webpackChunkName: "CodeEditor" */) +); + +// external service requirement +// Web service URL : url +// Results key path :resultsKey +// Primary Key : primaryKey +// Title Key : titleKey + +// rowy managed service +// function that takes query & user then returns a list of objects with an array of objects +// Primary Key : primaryKey +// label Key : labelKey + +const diagnosticsOptions = { + noSemanticValidation: false, + noSyntaxValidation: false, + noSuggestionDiagnostics: true, +}; export default function Settings({ config, onChange }) { + const { projectId } = useAppContext(); return ( - <> + + + + Select the service mode: + + onChange("mode")(e.target.value)} + > + } + label={ + <> + Managed + + Write JavaScript code below that will be executed by + Rowy Run to return list of options displayed in the + dropdown{" "} + + Requires Rowy Run setup + + + + + } + /> + } + label={ + <> + External + + An existing api endpoint or your own web service, that + will be called when the dropdown is opened. + + Learn more + + + + + } + /> + + + + {config.mode === "external" ? ( + onChange("url")(e.target.value)} + helperText={ + <> + Add the url of the endpoint. If you have deployed it to + Cloud Run you can find it{" "} + + here + + +
+ Your endpoint must be compatible with Rowy Connect service + columns.{" "} + + View requirements + + + + } + /> + ) : ( + <> + + Service Function + }> + Promise;`, + ]} + /> + + + + + )} + + ), + }, + { + id: "Interface", + title: "Interface", + content: ( + + + {/* Primary Key */} + onChange("primaryKey")(e.target.value)} + helperText={ + <> + The key that will be used to uniquely identify the + selected option.{" "} + + Learn more + + + + } + /> + + + {/* Title Key */} + onChange("titleKey")(e.target.value)} + helperText={ + <> + The key that will be used to display the selected option.{" "} + + Learn more + + + + } + /> + + {config.mode === "external" && ( + + {/* Results Key */} + onChange("resultsKey")(e.target.value)} + helperText={ + <> + (Optional)The key that will be used to retrieve the list + of results, if the service doesn't not return an array + options directly{" "} + + Learn more + + + + } + /> + + )} + + ), + }, + + { + id: "optionsSettings", + title: "Options Settings", + content: ( + + + + + Allow for multiple item selection + + onChange("multiple")(e.target.checked)} + /> + + + + {config.multiple && ( + <> + onChange("max")(e.target.value)} + helperText="The maximum number of items that can be selected, or 0 for no limit." + /> + + )} + + + ), + }, + ]} + /> + ); +} + +/* +<> - ); -} +*/ diff --git a/src/components/fields/ConnectService/types.d.ts b/src/components/fields/ConnectService/types.d.ts new file mode 100644 index 000000000..9017df1f8 --- /dev/null +++ b/src/components/fields/ConnectService/types.d.ts @@ -0,0 +1,5 @@ +type ConnectService = (request: { + query: string; + row: any; + user: any; +}) => Promise; diff --git a/src/components/fields/ConnectService/utils.ts b/src/components/fields/ConnectService/utils.ts index d2feec47b..8d0a1f4b9 100644 --- a/src/components/fields/ConnectService/utils.ts +++ b/src/components/fields/ConnectService/utils.ts @@ -2,3 +2,8 @@ export const sanitiseValue = (value: any) => { if (value === undefined || value === null || value === "") return []; else return value as string[]; }; + +export const baseFunction = `const serviceFunction: ConnectService = async ({query, row, user}) => { + // TODO: Implement your service function here + return []; +};`; From acc36a7a4d3826ea7d596d2899e4c641112e66a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Mar 2022 11:12:52 +0000 Subject: [PATCH 02/36] Bump urijs from 1.19.8 to 1.19.10 Bumps [urijs](https://github.com/medialize/URI.js) from 1.19.8 to 1.19.10. - [Release notes](https://github.com/medialize/URI.js/releases) - [Changelog](https://github.com/medialize/URI.js/blob/gh-pages/CHANGELOG.md) - [Commits](https://github.com/medialize/URI.js/compare/v1.19.8...v1.19.10) --- updated-dependencies: - dependency-name: urijs 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 642c6f9e8..aa5bd707d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17321,9 +17321,9 @@ uri-js@^4.2.2: punycode "^2.1.0" urijs@^1.19.1: - version "1.19.8" - resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.8.tgz#ee0407a18528934d3c383e691912f47043a58feb" - integrity sha512-iIXHrjomQ0ZCuDRy44wRbyTZVnfVNLVo3Ksz1yxNyE5wV1IDZW2S5Jszy45DTlw/UdsnRT7DyDhIz7Gy+vJumw== + version "1.19.10" + resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.10.tgz#8e2fe70a8192845c180f75074884278f1eea26cb" + integrity sha512-EzauQlgKuJgsXOqoMrCiePBf4At5jVqRhXykF3Wfb8ZsOBMxPcfiVBcsHXug4Aepb/ICm2PIgqAUGMelgdrWEg== urix@^0.1.0: version "0.1.0" From b4cbe8db4180bee36cee79347359da1b6337dd5b Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Tue, 8 Mar 2022 23:08:11 +0800 Subject: [PATCH 03/36] update webhook praser templates --- src/components/TableHeader/Webhooks/Schemas/basic.tsx | 2 +- src/components/TableHeader/Webhooks/Schemas/typeform.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/TableHeader/Webhooks/Schemas/basic.tsx b/src/components/TableHeader/Webhooks/Schemas/basic.tsx index 0ea81a15e..76d47b464 100644 --- a/src/components/TableHeader/Webhooks/Schemas/basic.tsx +++ b/src/components/TableHeader/Webhooks/Schemas/basic.tsx @@ -57,7 +57,7 @@ export const webhookBasic = { // auditField const ${ table.auditFieldCreatedBy ?? "_createdBy" - } = await rowy.getServiceAccountUser() + } = await rowy.metadata.serviceAccountUser() return { ...body, ${table.auditFieldCreatedBy ?? "_createdBy"} diff --git a/src/components/TableHeader/Webhooks/Schemas/typeform.tsx b/src/components/TableHeader/Webhooks/Schemas/typeform.tsx index 92e124a1d..493d6c490 100644 --- a/src/components/TableHeader/Webhooks/Schemas/typeform.tsx +++ b/src/components/TableHeader/Webhooks/Schemas/typeform.tsx @@ -51,7 +51,7 @@ export const webhookTypeform = { // auditField const ${ table.auditFieldCreatedBy ?? "_createdBy" - } = await rowy.getServiceAccountUser() + } = await rowy.metadata.serviceAccountUser() return { ...submission, ${table.auditFieldCreatedBy ?? "_createdBy"} From 7dc56f3b0a8b1453c97c695a78adbe35ec0f5b8e Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Wed, 9 Mar 2022 00:34:59 +0800 Subject: [PATCH 04/36] fix secret getter example code --- src/components/fields/Action/Settings.tsx | 2 +- src/components/fields/Action/templates.ts | 4 ++-- src/components/fields/Derivative/Settings.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/fields/Action/Settings.tsx b/src/components/fields/Action/Settings.tsx index d17e94502..2438e6706 100644 --- a/src/components/fields/Action/Settings.tsx +++ b/src/components/fields/Action/Settings.tsx @@ -107,7 +107,7 @@ const Settings = ({ config, onChange }) => { ? config.derivativeFn : config?.script ? `const action:Action = async ({row,ref,db,storage,auth,actionParams,user}) => { - ${config.script.replace(/utilFns.getSecret/g, "rowy.secrets.getSecret")} + ${config.script.replace(/utilFns.getSecret/g, "rowy.secrets.get")} }` : RUN_ACTION_TEMPLATE; diff --git a/src/components/fields/Action/templates.ts b/src/components/fields/Action/templates.ts index da1129d26..5701ef244 100644 --- a/src/components/fields/Action/templates.ts +++ b/src/components/fields/Action/templates.ts @@ -1,7 +1,7 @@ export const RUN_ACTION_TEMPLATE = `const action:Action = async ({row,ref,db,storage,auth,actionParams,user}) => { // Write your action code here // for example: - // const authToken = await rowy.secrets.getSecret("service") + // const authToken = await rowy.secrets.get("service") // try { // const resp = await fetch('https://example.com/api/v1/users/'+ref.id,{ // method: 'PUT', @@ -29,7 +29,7 @@ export const RUN_ACTION_TEMPLATE = `const action:Action = async ({row,ref,db,sto export const UNDO_ACTION_TEMPLATE = `const action : Action = async ({row,ref,db,storage,auth,actionParams,user}) => { // Write your undo code here // for example: - // const authToken = await rowy.secrets.getSecret("service") + // const authToken = await rowy.secrets.get("service") // try { // const resp = await fetch('https://example.com/api/v1/users/'+ref.id,{ // method: 'DELETE', diff --git a/src/components/fields/Derivative/Settings.tsx b/src/components/fields/Derivative/Settings.tsx index a5e979783..b6171e1ad 100644 --- a/src/components/fields/Derivative/Settings.tsx +++ b/src/components/fields/Derivative/Settings.tsx @@ -58,7 +58,7 @@ export default function Settings({ ? config.derivativeFn : config?.script ? `const derivative:Derivative = async ({row,ref,db,storage,auth})=>{ - ${config.script.replace(/utilFns.getSecret/g, "rowy.secrets.getSecret")} + ${config.script.replace(/utilFns.getSecret/g, "rowy.secrets.get")} }` : `const derivative:Derivative = async ({row,ref,db,storage,auth})=>{ // Write your derivative code here From 124eb337db0648e0a98dff15c6487a433d0018f9 Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Wed, 9 Mar 2022 01:03:56 +0800 Subject: [PATCH 05/36] fix actionscript editor value --- src/components/fields/Action/Settings.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/fields/Action/Settings.tsx b/src/components/fields/Action/Settings.tsx index 2438e6706..36a59ae1b 100644 --- a/src/components/fields/Action/Settings.tsx +++ b/src/components/fields/Action/Settings.tsx @@ -103,8 +103,8 @@ const Settings = ({ config, onChange }) => { const runFn = functionBodyOnly ? config?.script - : config.runFn - ? config.derivativeFn + : config?.runFn + ? config.runFn : config?.script ? `const action:Action = async ({row,ref,db,storage,auth,actionParams,user}) => { ${config.script.replace(/utilFns.getSecret/g, "rowy.secrets.get")} From ae59d35a792284374f985f02a10f807e1fc63110 Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Mon, 14 Mar 2022 16:12:04 +1100 Subject: [PATCH 06/36] add delete_column, delete_table analytics events --- src/components/Table/ColumnMenu/index.tsx | 2 ++ src/components/TableSettings/DeleteMenu.tsx | 13 ++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/Table/ColumnMenu/index.tsx b/src/components/Table/ColumnMenu/index.tsx index a5dcaa19d..eae24b0d2 100644 --- a/src/components/Table/ColumnMenu/index.tsx +++ b/src/components/Table/ColumnMenu/index.tsx @@ -37,6 +37,7 @@ import { getFieldProp } from "@src/components/fields"; import { Column } from "react-data-grid"; import { PopoverProps } from "@mui/material"; import { useConfirmation } from "@src/components/ConfirmationDialog"; +import { analytics } from "@src/analytics"; const INITIAL_MODAL = { type: "", data: {} }; @@ -290,6 +291,7 @@ export default function ColumnMenu() { confirmColor: "error", handleConfirm: () => { actions.remove(column.key); + await analytics.logEvent("delete_column", { type: column.type }); handleClose(); }, }), diff --git a/src/components/TableSettings/DeleteMenu.tsx b/src/components/TableSettings/DeleteMenu.tsx index 1bc2624a8..f12f45bfc 100644 --- a/src/components/TableSettings/DeleteMenu.tsx +++ b/src/components/TableSettings/DeleteMenu.tsx @@ -9,6 +9,7 @@ import Confirmation from "@src/components/Confirmation"; import { Table } from "@src/contexts/ProjectContext"; import { routes } from "@src/constants/routes"; import { db } from "@src/firebase"; +import { analytics } from "@src/analytics"; import { SETTINGS, TABLE_SCHEMAS, @@ -40,13 +41,15 @@ export default function DeleteMenu({ clearDialog, data }: IDeleteMenuProps) { (table) => table.id !== data?.id || table.tableType !== data?.tableType ); tablesDocRef.update({ tables: updatedTables }); - db.collection( - data?.tableType === "primaryCollection" - ? TABLE_SCHEMAS - : TABLE_GROUP_SCHEMAS - ) + await db + .collection( + data?.tableType === "primaryCollection" + ? TABLE_SCHEMAS + : TABLE_GROUP_SCHEMAS + ) .doc(data?.id) .delete(); + await analytics.logEvent("delete_table"); clearDialog(); history.push(routes.home); }; From fc44aa188e5f91d0983819d5270f6a5f3061fa7a Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Wed, 16 Mar 2022 07:58:39 +1100 Subject: [PATCH 07/36] fixed delete and remove duplicates for group tables --- src/components/Table/BulkActions/index.tsx | 2 +- src/components/Table/ColumnMenu/index.tsx | 2 +- src/components/Table/ContextMenu/index.tsx | 2 +- .../Table/formatters/FinalColumn.tsx | 36 ++++++++++--------- src/contexts/ProjectContext.tsx | 14 ++++---- src/hooks/useTable/useTableData.tsx | 22 ++++++------ 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/components/Table/BulkActions/index.tsx b/src/components/Table/BulkActions/index.tsx index cbea8cab5..4ad0859c7 100644 --- a/src/components/Table/BulkActions/index.tsx +++ b/src/components/Table/BulkActions/index.tsx @@ -143,7 +143,7 @@ export default function BulkActions({ selectedRows, columns, clearSelection }) { clearSelection(); }; const handleDelete = () => { - deleteRow!(selectedRows.map((row) => row.ref.id)); + deleteRow!(selectedRows.map((row) => row.ref)); clearSelection(); }; diff --git a/src/components/Table/ColumnMenu/index.tsx b/src/components/Table/ColumnMenu/index.tsx index eae24b0d2..3b5e98d29 100644 --- a/src/components/Table/ColumnMenu/index.tsx +++ b/src/components/Table/ColumnMenu/index.tsx @@ -289,7 +289,7 @@ export default function ColumnMenu() { ), confirm: "Delete", confirmColor: "error", - handleConfirm: () => { + handleConfirm: async () => { actions.remove(column.key); await analytics.logEvent("delete_column", { type: column.type }); handleClose(); diff --git a/src/components/Table/ContextMenu/index.tsx b/src/components/Table/ContextMenu/index.tsx index 8438fcbc7..757fdc128 100644 --- a/src/components/Table/ContextMenu/index.tsx +++ b/src/components/Table/ContextMenu/index.tsx @@ -76,7 +76,7 @@ export default function ContextMenu() { ), confirm: "Delete", confirmColor: "error", - handleConfirm: () => deleteRow?.(row.id), + handleConfirm: () => deleteRow?.(row.ref), }); resetContextMenu(); }, diff --git a/src/components/Table/formatters/FinalColumn.tsx b/src/components/Table/formatters/FinalColumn.tsx index c7a72ac3b..2d0347b29 100644 --- a/src/components/Table/formatters/FinalColumn.tsx +++ b/src/components/Table/formatters/FinalColumn.tsx @@ -9,6 +9,7 @@ import { useConfirmation } from "@src/components/ConfirmationDialog/Context"; import { useAppContext } from "@src/contexts/AppContext"; import { useProjectContext } from "@src/contexts/ProjectContext"; import useKeyPress from "@src/hooks/useKeyPress"; +import { isCollectionGroup } from "@src/utils/fns"; const useStyles = makeStyles((theme) => createStyles({ @@ -34,29 +35,30 @@ export default function FinalColumn({ row }: FormatterProps) { const altPress = useKeyPress("Alt"); const handleDelete = () => { - if (deleteRow) deleteRow(row.id); + if (deleteRow) deleteRow(row.ref); }; if (!userClaims?.roles.includes("ADMIN") && table?.readOnly === true) return null; - return ( - - { - const { ref, ...clonedRow } = row; - addRow!(clonedRow, undefined, { type: "smaller" }); - }} - aria-label="Duplicate row" - className="row-hover-iconButton" - > - - - + {!isCollectionGroup() && ( + + { + const { ref, ...clonedRow } = row; + addRow!(clonedRow, undefined, { type: "smaller" }); + }} + aria-label="Duplicate row" + className="row-hover-iconButton" + > + + + + )} { ); }; - const deleteRow = (rowId: string | string[]) => { - if (Array.isArray(rowId)) { - tableActions.row.delete(rowId, () => { - rowId.forEach((id) => auditChange("DELETE_ROW", id, {})); + const deleteRow = (ref: DocumentReference | DocumentReference[]) => { + if (Array.isArray(ref)) { + tableActions.row.delete(ref, () => { + ref.forEach((r) => auditChange("DELETE_ROW", r.path, {})); }); } else - tableActions.row.delete(rowId, () => - auditChange("DELETE_ROW", rowId, {}) + tableActions.row.delete(ref, () => + auditChange("DELETE_ROW", ref.path, {}) ); }; diff --git a/src/hooks/useTable/useTableData.tsx b/src/hooks/useTable/useTableData.tsx index a0087a786..96b3aec9d 100644 --- a/src/hooks/useTable/useTableData.tsx +++ b/src/hooks/useTable/useTableData.tsx @@ -16,6 +16,7 @@ import { missingFieldsReducer, decrementId, } from "@src/utils/fns"; +import { DocumentReference } from "@google-cloud/firestore"; // Safety parameter sets the upper limit of number of docs fetched by this hook export const CAP = 1000; @@ -253,23 +254,20 @@ const useTableData = () => { * @param documentId firestore document id */ - const deleteRow = async (rowId: string | string[], onSuccess: () => void) => { + const deleteRow = async ( + ref: DocumentReference | DocumentReference[], + onSuccess: () => void + ) => { // Delete document try { - if (Array.isArray(rowId)) { - await Promise.all( - rowId.map((id) => db.collection(tableState.path).doc(id).delete()) - ); + if (Array.isArray(ref)) { + await Promise.all(ref.map((r) => r.delete())); onSuccess(); - rowsDispatch({ type: "deleteMultiple", rowIds: rowId }); + rowsDispatch({ type: "deleteMultiple", rowIds: ref.map((r) => r.id) }); } else { - await db - .collection(tableState.path) - .doc(rowId) - .delete() - .then(onSuccess); + await ref.delete().then(onSuccess); // Remove row locally - return rowsDispatch({ type: "delete", rowId }); + return rowsDispatch({ type: "delete", rowId: ref.id }); } } catch (error: any) { if (error.code === "permission-denied") { From 81d0fc4d7452719da4ca5326b97bc051d449d57a Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Wed, 16 Mar 2022 23:51:08 +1100 Subject: [PATCH 08/36] added response to WebHooks --- src/components/TableHeader/Webhooks/Schemas/basic.tsx | 10 ++++++++-- src/components/TableHeader/Webhooks/utils.tsx | 10 ++++++++-- src/components/TableHeader/Webhooks/webhooks.d.ts | 11 +++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 src/components/TableHeader/Webhooks/webhooks.d.ts diff --git a/src/components/TableHeader/Webhooks/Schemas/basic.tsx b/src/components/TableHeader/Webhooks/Schemas/basic.tsx index 76d47b464..abe57a821 100644 --- a/src/components/TableHeader/Webhooks/Schemas/basic.tsx +++ b/src/components/TableHeader/Webhooks/Schemas/basic.tsx @@ -25,11 +25,17 @@ const requestType = [ export const parserExtraLibs = [ requestType, - `type Parser = (args:{req:WebHookRequest,db: FirebaseFirestore.Firestore,ref: FirebaseFirestore.CollectionReference}) => Promise;`, + `type Parser = (args:{req:WebHookRequest,db: FirebaseFirestore.Firestore,ref: FirebaseFirestore.CollectionReference,res:{ + send:(v:any)=>void + sendStatus:(status:number)=>void + }}) => Promise;`, ]; export const conditionExtraLibs = [ requestType, - `type Condition = (args:{req:WebHookRequest,db: FirebaseFirestore.Firestore,ref: FirebaseFirestore.CollectionReference}) => Promise;`, + `type Condition = (args:{req:WebHookRequest,db: FirebaseFirestore.Firestore,ref: FirebaseFirestore.CollectionReference,res:{ + send:(v:any)=>void + sendStatus:(status:number)=>void + }}) => Promise;`, ]; const additionalVariables = [ diff --git a/src/components/TableHeader/Webhooks/utils.tsx b/src/components/TableHeader/Webhooks/utils.tsx index 7803a5487..b5f955101 100644 --- a/src/components/TableHeader/Webhooks/utils.tsx +++ b/src/components/TableHeader/Webhooks/utils.tsx @@ -23,11 +23,17 @@ const requestType = [ export const parserExtraLibs = [ requestType, - `type Parser = (args:{req:WebHookRequest,db: FirebaseFirestore.Firestore,ref: FirebaseFirestore.CollectionReference}) => Promise;`, + `type Parser = (args:{req:WebHookRequest,db: FirebaseFirestore.Firestore,ref: FirebaseFirestore.CollectionReference,res:{ + send:(v:any)=>void + sendStatus:(status:number)=>void + }}) => Promise;`, ]; export const conditionExtraLibs = [ requestType, - `type Condition = (args:{req:WebHookRequest,db: FirebaseFirestore.Firestore,ref: FirebaseFirestore.CollectionReference}) => Promise;`, + `type Condition = (args:{req:WebHookRequest,db: FirebaseFirestore.Firestore,ref: FirebaseFirestore.CollectionReference,res:{ + send:(v:any)=>void + sendStatus:(status:number)=>void + }}) => Promise;`, ]; const additionalVariables = [ diff --git a/src/components/TableHeader/Webhooks/webhooks.d.ts b/src/components/TableHeader/Webhooks/webhooks.d.ts new file mode 100644 index 000000000..955f77d69 --- /dev/null +++ b/src/components/TableHeader/Webhooks/webhooks.d.ts @@ -0,0 +1,11 @@ +type Condition = (args: { + req: WebHookRequest; + db: FirebaseFirestore.Firestore; + ref: FirebaseFirestore.CollectionReference; + res: Response; +}) => Promise; +type Parser = (args: { + req: WebHookRequest; + db: FirebaseFirestore.Firestore; + ref: FirebaseFirestore.CollectionReference; +}) => Promise; From a967c2b6545193dacc97611aa5a8317cc2bb3204 Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Thu, 17 Mar 2022 10:38:25 +1100 Subject: [PATCH 09/36] upgrade mui --- package.json | 8 ++--- yarn.lock | 94 ++++++++++++++++++++++++++-------------------------- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/package.json b/package.json index 85695216b..a6c8b072f 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,10 @@ "@hookform/resolvers": "^2.8.5", "@mdi/js": "^6.5.95", "@monaco-editor/react": "^4.3.1", - "@mui/icons-material": "^5.4.4", - "@mui/lab": "^5.0.0-alpha.71", - "@mui/material": "^5.4.4", - "@mui/styles": "^5.4.4", + "@mui/icons-material": "^5.5.1", + "@mui/lab": "^5.0.0-alpha.73", + "@mui/material": "^5.5.1", + "@mui/styles": "^5.5.1", "@rowy/form-builder": "^0.5.3", "@rowy/multiselect": "^0.2.3", "@tinymce/tinymce-react": "^3.12.6", diff --git a/yarn.lock b/yarn.lock index aa5bd707d..15df8f4d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2429,38 +2429,38 @@ "@monaco-editor/loader" "^1.2.0" prop-types "^15.7.2" -"@mui/base@5.0.0-alpha.70": - version "5.0.0-alpha.70" - resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.70.tgz#e280ee3b69d86034f2cff445161747940129d576" - integrity sha512-8UZWhz1JYuQnPkAbC37cl4aL1JyNWZ08wDXlp57W7fYQp5xFpBP/7p56AcWg2qG9CNJP0IlFg2Wp4md1v2l4iA== +"@mui/base@5.0.0-alpha.72": + version "5.0.0-alpha.72" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.72.tgz#551d64402ee5065cf81fd1388a3e7ab8c426fe3e" + integrity sha512-WCAooa9eqbsC68LhyKtDBRumH4hV1eRZ0A3SDKFHSwYG9fCOdsFv/H1dIYRJM0rwD45bMnuDiG3Qmx7YsTiptw== dependencies: "@babel/runtime" "^7.17.2" "@emotion/is-prop-valid" "^1.1.2" "@mui/utils" "^5.4.4" - "@popperjs/core" "^2.4.4" + "@popperjs/core" "^2.11.3" clsx "^1.1.1" prop-types "^15.7.2" react-is "^17.0.2" -"@mui/icons-material@^5.4.4": - version "5.4.4" - resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.4.4.tgz#0dc7b4e68cbbdfc675f09f0763be1100aad910af" - integrity sha512-7zoRpjO8vsd+bPvXq6rtXu0V8Saj70X09dtTQogZmxQKabrYW3g7+Yym7SCRA7IYVF3ysz2AvdQrGD1P/sGepg== +"@mui/icons-material@^5.5.1": + version "5.5.1" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.5.1.tgz#848a57972617411370775980cbc6990588d4aafb" + integrity sha512-40f68p5+Yhq3dCn3QYHqQt5RETPyR3AkDw+fma8PtcjqvZ+d+jF84kFmT6NqwA3he7TlwluEtkyAmPzUE4uPdA== dependencies: "@babel/runtime" "^7.17.2" -"@mui/lab@^5.0.0-alpha.71": - version "5.0.0-alpha.71" - resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-5.0.0-alpha.71.tgz#6be1e648b63316dd628c0179b418adfd4c0a5c22" - integrity sha512-ScGfSsiYa2XZl+TYEgDFoCv1DoXoWNQwyJBbDlapacEw10wGmY6sgMkCjsPhpuabgC5FVOaV5k30OxG7cZKXJQ== +"@mui/lab@^5.0.0-alpha.73": + version "5.0.0-alpha.73" + resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-5.0.0-alpha.73.tgz#f1b81682be155d87d492f64202ada8b7fe83be08" + integrity sha512-10Uj0Atc7gBTXKX4VV38P6RdqTQrJZxcl3HeEcytIO1S3NAGfc7gZ3Hdpnhtj5U8kcRJZZPH9LtrBbMZzxU/1A== dependencies: "@babel/runtime" "^7.17.2" "@date-io/date-fns" "^2.13.1" "@date-io/dayjs" "^2.13.1" "@date-io/luxon" "^2.13.1" "@date-io/moment" "^2.13.1" - "@mui/base" "5.0.0-alpha.70" - "@mui/system" "^5.4.4" + "@mui/base" "5.0.0-alpha.72" + "@mui/system" "^5.5.1" "@mui/utils" "^5.4.4" clsx "^1.1.1" prop-types "^15.7.2" @@ -2468,19 +2468,19 @@ react-transition-group "^4.4.2" rifm "^0.12.1" -"@mui/material@^5.4.4": - version "5.4.4" - resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.4.4.tgz#2652a07085bf107da590007286336640f605055e" - integrity sha512-VDJC7GzO1HTFqfMe2zwvaW/sRhABBJXFkKEv5gO3uXx7x9fdwJHQr4udU7NWZCUdOcx9Y0h3BsAILLefYq+WPw== +"@mui/material@^5.5.1": + version "5.5.1" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.5.1.tgz#9ca89a8b32afd59c843a5bc0332b0786cf9bf1d0" + integrity sha512-bJSYgymgSZ7btPTNnWFrr2EmGoVQc4A/0WLfP/ESY2dxnhnbFDwt7twiOKmJp3u84YXriEDt5v9EZQLf7A+y0Q== dependencies: "@babel/runtime" "^7.17.2" - "@mui/base" "5.0.0-alpha.70" - "@mui/system" "^5.4.4" - "@mui/types" "^7.1.2" + "@mui/base" "5.0.0-alpha.72" + "@mui/system" "^5.5.1" + "@mui/types" "^7.1.3" "@mui/utils" "^5.4.4" "@types/react-transition-group" "^4.4.4" clsx "^1.1.1" - csstype "^3.0.10" + csstype "^3.0.11" hoist-non-react-statics "^3.3.2" prop-types "^15.7.2" react-is "^17.0.2" @@ -2504,18 +2504,18 @@ "@emotion/cache" "^11.7.1" prop-types "^15.7.2" -"@mui/styles@^5.4.4": - version "5.4.4" - resolved "https://registry.yarnpkg.com/@mui/styles/-/styles-5.4.4.tgz#e6a18f3528a494d782fd80e7feb01bd75a3570dd" - integrity sha512-w+9VIC1+JiPfF7osomX1j+aX7yyNNw8BnMYo6niK+zbwIxSYX/wcq4Jh7rlt6FSiaKL4Qi1uf7MPlNAhIxXq3g== +"@mui/styles@^5.5.1": + version "5.5.1" + resolved "https://registry.yarnpkg.com/@mui/styles/-/styles-5.5.1.tgz#cfd2b6dbdb4b2cb0e989568bb9cc45f5d7346d2a" + integrity sha512-mxwfjwTwPE+r7/U4Nn/QKPzJ2cIqmRuK3xu44Us613D5jqPeB/ftOsAy0OpCYAwpkUxmQIrRQiilQ8zE+f4rBQ== dependencies: "@babel/runtime" "^7.17.2" "@emotion/hash" "^0.8.0" "@mui/private-theming" "^5.4.4" - "@mui/types" "^7.1.2" + "@mui/types" "^7.1.3" "@mui/utils" "^5.4.4" clsx "^1.1.1" - csstype "^3.0.10" + csstype "^3.0.11" hoist-non-react-statics "^3.3.2" jss "^10.8.2" jss-plugin-camel-case "^10.8.2" @@ -2527,24 +2527,24 @@ jss-plugin-vendor-prefixer "^10.8.2" prop-types "^15.7.2" -"@mui/system@^5.4.4": - version "5.4.4" - resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.4.4.tgz#cd5d3d35c75594abd88708e715b5e39a8874ff51" - integrity sha512-Zjbztq2o/VRuRRCWjG44juRrPKYLQMqtQpMHmMttGu5BnvK6PAPW3WOY0r1JCAwLhbd8Kug9nyhGQYKETjo+tQ== +"@mui/system@^5.5.1": + version "5.5.1" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.5.1.tgz#1f2b2a8c5542db6176e3b5a8ed12aea602cdeb81" + integrity sha512-2hynI4hN8304hOCT8sc4knJviwUUYJ7XK3mXwQ0nagVGOPnWSOad/nYADm7K0vdlCeUXLIbDbe7oNN3Kaiu2kA== dependencies: "@babel/runtime" "^7.17.2" "@mui/private-theming" "^5.4.4" "@mui/styled-engine" "^5.4.4" - "@mui/types" "^7.1.2" + "@mui/types" "^7.1.3" "@mui/utils" "^5.4.4" clsx "^1.1.1" - csstype "^3.0.10" + csstype "^3.0.11" prop-types "^15.7.2" -"@mui/types@^7.1.2": - version "7.1.2" - resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.1.2.tgz#4f3678ae77a7a3efab73b6e040469cc6df2144ac" - integrity sha512-SD7O1nVzqG+ckQpFjDhXPZjRceB8HQFHEvdLLrPhlJy4lLbwEBbxK74Tj4t6Jgk0fTvLJisuwOutrtYe9P/xBQ== +"@mui/types@^7.1.3": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.1.3.tgz#d7636f3046110bcccc63e6acfd100e2ad9ca712a" + integrity sha512-DDF0UhMBo4Uezlk+6QxrlDbchF79XG6Zs0zIewlR4c0Dt6GKVFfUtzPtHCH1tTbcSlq/L2bGEdiaoHBJ9Y1gSA== "@mui/utils@^5.4.4": version "5.4.4" @@ -2620,10 +2620,10 @@ schema-utils "^2.6.5" source-map "^0.7.3" -"@popperjs/core@^2.4.4": - version "2.10.2" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.10.2.tgz#0798c03351f0dea1a5a4cabddf26a55a7cbee590" - integrity sha512-IXf3XA7+XyN7CP9gGh/XB0UxVMlvARGEgGXLubFICsUMGz6Q+DU+i4gGlpOxTjKvXjkJDJC8YdqdKkDj9qZHEQ== +"@popperjs/core@^2.11.3": + version "2.11.4" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.4.tgz#d8c7b8db9226d2d7664553a0741ad7d0397ee503" + integrity sha512-q/ytXxO5NKvyT37pmisQAItCFqA7FD/vNb8dgaJy3/630Fsc+Mz9/9f2SziBoIZ30TJooXyTwZmhi1zjXmObYg== "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" @@ -6252,10 +6252,10 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" -csstype@^3.0.10: - version "3.0.10" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" - integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== +csstype@^3.0.11: + version "3.0.11" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33" + integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw== csstype@^3.0.2: version "3.0.9" From 46e611b34d64719985bef4f68a37161d7300e7ea Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Thu, 17 Mar 2022 10:41:42 +1100 Subject: [PATCH 10/36] add EDITOR, VIEWER as default roles --- src/contexts/ProjectContext.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/contexts/ProjectContext.tsx b/src/contexts/ProjectContext.tsx index 7951d5cec..5be9e2942 100644 --- a/src/contexts/ProjectContext.tsx +++ b/src/contexts/ProjectContext.tsx @@ -166,7 +166,12 @@ export const ProjectContextProvider: React.FC = ({ children }) => { () => Array.isArray(tables) ? Array.from( - new Set(tables.reduce((a, c) => [...a, ...c.roles], ["ADMIN"])) + new Set( + tables.reduce( + (a, c) => [...a, ...c.roles], + ["ADMIN", "EDITOR", "VIEWER"] + ) + ) ) : [], [tables] From 7fc34762d1f44836819047c447179c55527a1720 Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Thu, 17 Mar 2022 10:41:59 +1100 Subject: [PATCH 11/36] bump version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a6c8b072f..1bfba3057 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rowy", - "version": "2.4.0", + "version": "2.5.0-rc.0", "homepage": "https://rowy.io", "repository": { "type": "git", From a23de51f7f6406c37a14390ce98a7a5fdaf1c772 Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Fri, 18 Mar 2022 11:07:49 +1100 Subject: [PATCH 12/36] add border radius to markdown images --- src/components/RenderedMarkdown.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/RenderedMarkdown.tsx b/src/components/RenderedMarkdown.tsx index 4d634920f..689bddf2b 100644 --- a/src/components/RenderedMarkdown.tsx +++ b/src/components/RenderedMarkdown.tsx @@ -9,7 +9,9 @@ const components = { a: (props) => , p: Typography, // eslint-disable-next-line jsx-a11y/alt-text - img: (props) => , + img: (props) => ( + + ), }; const restrictionPresets = { From 38771170ec9c9d2b59fc458c3189149fda4dd463 Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Sat, 19 Mar 2022 22:18:42 +1100 Subject: [PATCH 13/36] support different langs for code field --- src/components/CodeEditor/index.tsx | 4 +- src/components/fields/Code/Settings.tsx | 38 +++++++++++++++++++ .../fields/Code/SideDrawerField.tsx | 7 +++- src/components/fields/Code/index.tsx | 5 +++ 4 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 src/components/fields/Code/Settings.tsx diff --git a/src/components/CodeEditor/index.tsx b/src/components/CodeEditor/index.tsx index 742c93473..2d35f70b4 100644 --- a/src/components/CodeEditor/index.tsx +++ b/src/components/CodeEditor/index.tsx @@ -38,7 +38,7 @@ export default function CodeEditor({ extraLibs, diagnosticsOptions, onUnmount, - + defaultLanguage = "javascript", ...props }: ICodeEditorProps) { const theme = useTheme(); @@ -77,7 +77,7 @@ export default function CodeEditor({ style={fullScreen ? { height: "100%" } : {}} > } className="editor" diff --git a/src/components/fields/Code/Settings.tsx b/src/components/fields/Code/Settings.tsx new file mode 100644 index 000000000..60adcee4b --- /dev/null +++ b/src/components/fields/Code/Settings.tsx @@ -0,0 +1,38 @@ +import MultiSelect from "@rowy/multiselect"; + +const languages = [ + "javascript", + "typescript", + "json", + "html", + "css", + "scss", + "shell", + "yaml", + "xml", + "ruby", + "python", + "php", + "markdown", + "rust", + "csharp", + "cpp", + "c", + "java", + "go", + "plaintext", +]; +export default function Settings({ config, onChange }) { + return ( + { + onChange("language")(value); + }} + label="Language" + /> + ); +} diff --git a/src/components/fields/Code/SideDrawerField.tsx b/src/components/fields/Code/SideDrawerField.tsx index 2549f3f41..6e10fce33 100644 --- a/src/components/fields/Code/SideDrawerField.tsx +++ b/src/components/fields/Code/SideDrawerField.tsx @@ -13,7 +13,12 @@ export default function Code({ control={control} name={column.key} render={({ field: { onChange, value } }) => ( - + )} /> ); diff --git a/src/components/fields/Code/index.tsx b/src/components/fields/Code/index.tsx index 7c2e13d10..e541631fb 100644 --- a/src/components/fields/Code/index.tsx +++ b/src/components/fields/Code/index.tsx @@ -6,6 +6,10 @@ import CodeIcon from "@mui/icons-material/Code"; import BasicCell from "./BasicCell"; import withSideDrawerEditor from "@src/components/Table/editors/withSideDrawerEditor"; +const Settings = lazy( + () => import("./Settings" /* webpackChunkName: "Settings-ConnectService" */) +); + const SideDrawerField = lazy( () => import("./SideDrawerField" /* webpackChunkName: "SideDrawerField-Code" */) @@ -23,5 +27,6 @@ export const config: IFieldConfig = { TableCell: withBasicCell(BasicCell), TableEditor: withSideDrawerEditor(BasicCell), SideDrawerField, + settings: Settings, }; export default config; From 4eaec3fe1b48758d3b8e8424e3f7231f706b806b Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Thu, 24 Mar 2022 14:17:50 +1100 Subject: [PATCH 14/36] stop pushing rowRef to user --- src/components/SideDrawer/index.tsx | 10 ---------- src/components/Table/ContextMenu/index.tsx | 13 ++++++++++++- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/components/SideDrawer/index.tsx b/src/components/SideDrawer/index.tsx index a7ebedadb..bcaaae343 100644 --- a/src/components/SideDrawer/index.tsx +++ b/src/components/SideDrawer/index.tsx @@ -38,13 +38,10 @@ export default function SideDrawer() { const handleNavigate = (direction: "up" | "down") => () => { if (!tableState?.rows) return; - let row = cell!.row; if (direction === "up" && row > 0) row -= 1; if (direction === "down" && row < tableState.rows.length - 1) row += 1; - setCell!((cell) => ({ column: cell!.column, row })); - const idx = tableState?.columns[cell!.column]?.index; dataGridRef?.current?.selectCell({ rowIdx: row, idx }, false); }; @@ -68,13 +65,6 @@ export default function SideDrawer() { useEffect(() => { if (cell && tableState?.rows[cell.row]) { - window.history.pushState( - "", - `${tableState?.config.id}`, - `${window.location.pathname}?rowRef=${encodeURIComponent( - tableState?.rows[cell.row].ref.path - )}` - ); if (urlDocState.doc) { urlDocState.unsubscribe(); dispatchUrlDoc({ path: "", doc: null }); diff --git a/src/components/Table/ContextMenu/index.tsx b/src/components/Table/ContextMenu/index.tsx index 757fdc128..1475f4b60 100644 --- a/src/components/Table/ContextMenu/index.tsx +++ b/src/components/Table/ContextMenu/index.tsx @@ -4,6 +4,7 @@ import { getFieldProp } from "@src/components/fields"; import MenuContents from "./MenuContent"; import DuplicateIcon from "@src/assets/icons/CopyCells"; import DeleteIcon from "@mui/icons-material/DeleteOutlined"; +import LinkIcon from "@mui/icons-material/Link"; import { useProjectContext } from "@src/contexts/ProjectContext"; import { useContextMenuAtom } from "@src/atoms/ContextMenu"; @@ -47,8 +48,18 @@ export default function ContextMenu() { } const row = tableState?.rows[selectedCell!.rowIndex]; - if (userRoles.includes("ADMIN") && row) { + if (row) { const rowActions = [ + { + label: "Copy link to row", + icon: , + onClick: () => { + const rowRef = encodeURIComponent(row.ref.path); + navigator.clipboard.writeText( + window.location.href + `?rowRef=${rowRef}` + ); + }, + }, { label: "Duplicate row", icon: , From 8f8f66d9ca17bc08e0a9f1f729f9bc18c664f5d4 Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Wed, 30 Mar 2022 22:32:19 +0200 Subject: [PATCH 15/36] connect --- src/components/fields/Action/ActionFab.tsx | 6 +- src/components/fields/Connect/InlineCell.tsx | 56 +++++ src/components/fields/Connect/PopoverCell.tsx | 38 ++++ .../fields/Connect/Select/PopupContents.tsx | 202 ++++++++++++++++++ .../fields/Connect/Select/index.tsx | 76 +++++++ .../fields/Connect/Select/styles.ts | 83 +++++++ src/components/fields/Connect/Settings.tsx | 190 ++++++++++++++++ .../fields/Connect/SideDrawerField.tsx | 73 +++++++ src/components/fields/Connect/index.tsx | 41 ++++ src/components/fields/Connect/types.d.ts | 5 + src/components/fields/Connect/utils.ts | 9 + src/components/fields/index.tsx | 2 + src/constants/fields.ts | 1 + src/utils/fns.ts | 6 + 14 files changed, 783 insertions(+), 5 deletions(-) create mode 100644 src/components/fields/Connect/InlineCell.tsx create mode 100644 src/components/fields/Connect/PopoverCell.tsx create mode 100644 src/components/fields/Connect/Select/PopupContents.tsx create mode 100644 src/components/fields/Connect/Select/index.tsx create mode 100644 src/components/fields/Connect/Select/styles.ts create mode 100644 src/components/fields/Connect/Settings.tsx create mode 100644 src/components/fields/Connect/SideDrawerField.tsx create mode 100644 src/components/fields/Connect/index.tsx create mode 100644 src/components/fields/Connect/types.d.ts create mode 100644 src/components/fields/Connect/utils.ts diff --git a/src/components/fields/Action/ActionFab.tsx b/src/components/fields/Action/ActionFab.tsx index 31f12533d..713d8288d 100644 --- a/src/components/fields/Action/ActionFab.tsx +++ b/src/components/fields/Action/ActionFab.tsx @@ -14,11 +14,7 @@ import { useConfirmation } from "@src/components/ConfirmationDialog"; import { useActionParams } from "./FormDialog/Context"; import { runRoutes } from "@src/constants/runRoutes"; -const replacer = (data: any) => (m: string, key: string) => { - const objKey = key.split(":")[0]; - const defaultValue = key.split(":")[1] || ""; - return _get(data, objKey, defaultValue); -}; +import { replacer } from "@src/utils/fns"; const getStateIcon = (actionState, config) => { switch (actionState) { diff --git a/src/components/fields/Connect/InlineCell.tsx b/src/components/fields/Connect/InlineCell.tsx new file mode 100644 index 000000000..95a93c34b --- /dev/null +++ b/src/components/fields/Connect/InlineCell.tsx @@ -0,0 +1,56 @@ +import { forwardRef } from "react"; +import { IPopoverInlineCellProps } from "../types"; + +import { ButtonBase, Grid, Chip } from "@mui/material"; +import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown"; + +import ChipList from "@src/components/Table/formatters/ChipList"; +import { get } from "lodash"; + +export const ConnectService = forwardRef(function ConnectService( + { value, showPopoverCell, disabled, column }: IPopoverInlineCellProps, + ref: React.Ref +) { + const config = column.config ?? {}; + const displayKey = config.titleKey ?? config.primaryKey; + return ( + showPopoverCell(true)} + ref={ref} + disabled={disabled} + className="cell-collapse-padding" + sx={{ + height: "100%", + font: "inherit", + color: "inherit !important", + letterSpacing: "inherit", + textAlign: "inherit", + justifyContent: "flex-start", + }} + > + + {Array.isArray(value) && + value.map((snapshot) => ( + + + + ))} + + + {!disabled && ( + + )} + + ); +}); + +export default ConnectService; diff --git a/src/components/fields/Connect/PopoverCell.tsx b/src/components/fields/Connect/PopoverCell.tsx new file mode 100644 index 000000000..9356d8f76 --- /dev/null +++ b/src/components/fields/Connect/PopoverCell.tsx @@ -0,0 +1,38 @@ +import { IPopoverCellProps } from "../types"; + +import ConnectServiceSelect from "./Select"; + +export default function ConnectService({ + value, + onSubmit, + column, + parentRef, + showPopoverCell, + disabled, + docRef, +}: IPopoverCellProps) { + const config = column.config ?? {}; + if (!config) return null; + + return ( + showPopoverCell(false), + }, + }} + /> + ); +} diff --git a/src/components/fields/Connect/Select/PopupContents.tsx b/src/components/fields/Connect/Select/PopupContents.tsx new file mode 100644 index 000000000..8e765ce66 --- /dev/null +++ b/src/components/fields/Connect/Select/PopupContents.tsx @@ -0,0 +1,202 @@ +import React, { useEffect, useState } from "react"; +import clsx from "clsx"; +import { useDebouncedCallback } from "use-debounce"; +import _get from "lodash/get"; + +import { + Button, + Checkbox, + Divider, + Grid, + InputAdornment, + List, + ListItemIcon, + ListItemText, + MenuItem, + TextField, + Typography, + Radio, +} from "@mui/material"; +import SearchIcon from "@mui/icons-material/Search"; + +import { IConnectServiceSelectProps } from "."; +import useStyles from "./styles"; +import Loading from "@src/components/Loading"; +import { useProjectContext } from "@src/contexts/ProjectContext"; +import { replacer } from "@src/utils/fns"; + +export interface IPopupContentsProps + extends Omit {} + +// TODO: Implement infinite scroll here +export default function PopupContents({ + value = [], + onChange, + config, + docRef, +}: IPopupContentsProps) { + const { rowyRun, tableState } = useProjectContext(); + // const url = config.url ; + const elementId = config.elementId; + const multiple = Boolean(config.multiple); + + const classes = useStyles(); + + // Webservice search query + const [query, setQuery] = useState(""); + // Webservice response + const [response, setResponse] = useState(null); + + const [docData, setDocData] = useState(null); + useEffect(() => { + docRef.get().then((d) => setDocData(d.data())); + }, []); + const hits: any["hits"] = response; + const [search] = useDebouncedCallback( + async (query: string) => { + if (!docData) return; + const resp = await rowyRun!({ + route: { method: "POST", path: "/connect" }, + body: { + columnKey: "game", + query: query, + schemaDocPath: tableState?.config.tableConfig.path, + }, + }); + console.log(resp); + setResponse(resp); + }, + 1000, + { leading: true } + ); + + useEffect(() => { + search(query); + }, [query, docData]); + + if (!response) return ; + + const select = (hit: any) => () => { + if (multiple) onChange([...value, hit]); + else onChange([hit]); + }; + const deselect = (hit: any) => () => { + if (multiple) + onChange(value.filter((v) => v[elementId] !== hit[elementId])); + else onChange([]); + }; + + const selectedValues = value?.map((item) => _get(item, elementId)); + + const clearSelection = () => onChange([]); + + return ( + + + setQuery(e.target.value)} + fullWidth + variant="filled" + margin="dense" + label="Search items" + className={classes.noMargins} + InputProps={{ + endAdornment: ( + + + + ), + }} + onClick={(e) => e.stopPropagation()} + onKeyDown={(e) => e.stopPropagation()} + /> + + + + + {hits.map((hit) => { + const isSelected = selectedValues.some((v) => v === hit[elementId]); + console.log({ + isSelected, + selectedValues, + elementId, + }); + return ( + + + + {multiple ? ( + + ) : ( + + )} + + + + + + ); + })} + + + + {multiple && ( + + + + {value?.length} of {hits?.length} + + + + + + )} + + ); +} diff --git a/src/components/fields/Connect/Select/index.tsx b/src/components/fields/Connect/Select/index.tsx new file mode 100644 index 000000000..90a66ddee --- /dev/null +++ b/src/components/fields/Connect/Select/index.tsx @@ -0,0 +1,76 @@ +import { Suspense } from "react"; +import clsx from "clsx"; + +import { TextField, TextFieldProps } from "@mui/material"; + +import useStyles from "./styles"; +import Loading from "@src/components/Loading"; +import ErrorBoundary from "@src/components/ErrorBoundary"; +import PopupContents from "./PopupContents"; + +export type ServiceValue = { + value: string; + [prop: string]: any; +}; + +export interface IConnectServiceSelectProps { + value: ServiceValue[]; + onChange: (value: ServiceValue[]) => void; + config: { + displayKey: string; + [key: string]: any; + }; + editable?: boolean; + /** Optional style overrides for root MUI `TextField` component */ + className?: string; + /** Override any props of the root MUI `TextField` component */ + TextFieldProps?: Partial; + docRef: firebase.default.firestore.DocumentReference; + disabled?: boolean; +} + +export default function ConnectServiceSelect({ + value = [], + className, + TextFieldProps = {}, + disabled, + ...props +}: IConnectServiceSelectProps) { + const classes = useStyles(); + + const sanitisedValue = Array.isArray(value) ? value : []; + + return ( + `${(value as any[]).length} selected`, + displayEmpty: true, + classes: { select: classes.selectRoot }, + ...TextFieldProps.SelectProps, + // Must have this set to prevent MUI transforming `value` + // prop for this component to a comma-separated string + MenuProps: { + classes: { paper: classes.paper, list: classes.menuChild }, + MenuListProps: { disablePadding: true }, + anchorOrigin: { vertical: "bottom", horizontal: "center" }, + transformOrigin: { vertical: "top", horizontal: "center" }, + ...TextFieldProps.SelectProps?.MenuProps, + }, + }} + disabled={disabled} + > + + }> + + + + + ); +} diff --git a/src/components/fields/Connect/Select/styles.ts b/src/components/fields/Connect/Select/styles.ts new file mode 100644 index 000000000..8398b4684 --- /dev/null +++ b/src/components/fields/Connect/Select/styles.ts @@ -0,0 +1,83 @@ +import { makeStyles, createStyles } from "@mui/styles"; + +export const useStyles = makeStyles((theme) => + createStyles({ + root: { minWidth: 200 }, + selectRoot: { paddingRight: theme.spacing(4) }, + + paper: { overflow: "hidden", maxHeight: "calc(100% - 48px)" }, + menuChild: { + padding: `0 ${theme.spacing(2)}`, + minWidth: 340, + // Need to set fixed height here so popup is positioned correctly + height: 340, + }, + + grid: { outline: 0 }, + + noMargins: { margin: 0 }, + + searchRow: { marginTop: theme.spacing(2) }, + + listRow: { + background: `${theme.palette.background.paper} no-repeat`, + position: "relative", + margin: theme.spacing(0, -2), + maxWidth: `calc(100% + ${theme.spacing(4)})`, + + "&::before, &::after": { + content: '""', + position: "absolute", + top: 0, + left: 0, + right: 0, + zIndex: 9, + + display: "block", + height: 16, + + background: `linear-gradient(to bottom, ${theme.palette.background.paper}, rgba(255, 255, 255, 0))`, + }, + + "&::after": { + top: "auto", + bottom: 0, + background: `linear-gradient(to top, ${theme.palette.background.paper}, rgba(255, 255, 255, 0))`, + }, + }, + list: () => { + let maxHeightDeductions = 0; + maxHeightDeductions -= 64; // search box + maxHeightDeductions -= 48; // multiple + maxHeightDeductions += 8; // footer padding + + return { + padding: theme.spacing(2, 0), + overflowY: "auto" as "auto", + // height: `calc(340px - ${-maxHeightDeductions}px)`, + height: 340 + maxHeightDeductions, + }; + }, + + checkboxContainer: { minWidth: theme.spacing(36 / 8) }, + checkbox: { + padding: theme.spacing(6 / 8, 9 / 8), + "&:hover": { background: "transparent" }, + }, + + divider: { margin: theme.spacing(0, 2, 0, 6.5) }, + + footerRow: { marginBottom: theme.spacing(2) }, + selectedRow: { + "$listRow + &": { marginTop: -theme.spacing(1) }, + "$footerRow + &": { marginTop: -theme.spacing(2) }, + + marginBottom: 0, + "& > div": { height: 48 }, + }, + selectAllButton: { marginRight: -theme.spacing(1) }, + selectedNum: { fontFeatureSettings: '"tnum"' }, + }) +); + +export default useStyles; diff --git a/src/components/fields/Connect/Settings.tsx b/src/components/fields/Connect/Settings.tsx new file mode 100644 index 000000000..6e0126270 --- /dev/null +++ b/src/components/fields/Connect/Settings.tsx @@ -0,0 +1,190 @@ +import { lazy, Suspense, useState } from "react"; +import _get from "lodash/get"; +import stringify from "json-stable-stringify-without-jsonify"; + +import { + Stepper, + Step, + StepButton, + StepContent, + Stack, + Grid, + Switch, + TextField, + FormControl, + FormLabel, + FormControlLabel, + RadioGroup, + Radio, + Typography, + InputLabel, + Link, + Checkbox, + FormHelperText, + Fab, +} from "@mui/material"; + +import SteppedAccordion from "@src/components/SteppedAccordion"; +import FieldSkeleton from "@src/components/SideDrawer/Form/FieldSkeleton"; +import CodeEditorHelper from "@src/components/CodeEditor/CodeEditorHelper"; +import InlineOpenInNewIcon from "@src/components/InlineOpenInNewIcon"; + +import { useProjectContext } from "@src/contexts/ProjectContext"; +import { WIKI_LINKS } from "@src/constants/externalLinks"; +import { useAppContext } from "@src/contexts/AppContext"; +import { baseFunction } from "./utils"; + +//import typeDefs from "!!raw-loader!./types.d.ts"; +const CodeEditor = lazy( + () => + import("@src/components/CodeEditor" /* webpackChunkName: "CodeEditor" */) +); + +// external service requirement +// Web service URL : url +// Results key path :resultsKey +// Primary Key : primaryKey +// Title Key : titleKey + +// rowy managed service +// function that takes query & user then returns a list of objects with an array of objects +// Primary Key : primaryKey +// label Key : labelKey +// single select or multiselect +const diagnosticsOptions = { + noSemanticValidation: false, + noSyntaxValidation: false, + noSuggestionDiagnostics: true, +}; + +export default function Settings({ config, onChange }) { + const { projectId } = useAppContext(); + return ( + + }> + Promise;`, + ]} + /> + + + + ), + }, + { + id: "Interface", + title: "Interface", + content: ( + + + {/* Primary Key */} + onChange("elementId")(e.target.value)} + helperText={ + <> + The key that will be used to uniquely identify the + selected option.{" "} + + Learn more + + + + } + /> + + + {/* Title Key */} + onChange("labelFormatter")(e.target.value)} + helperText={ + <> + The key that will be used to display the selected option.{" "} + + Learn more + + + + } + /> + + + ), + }, + + { + id: "optionsSettings", + title: "Options Settings", + content: ( + + + + + Allow for multiple item selection + + onChange("multiple")(e.target.checked)} + /> + + + + {config.multiple && ( + <> + onChange("max")(e.target.value)} + helperText="The maximum number of items that can be selected, or 0 for no limit." + /> + + )} + + + ), + }, + ]} + /> + ); +} diff --git a/src/components/fields/Connect/SideDrawerField.tsx b/src/components/fields/Connect/SideDrawerField.tsx new file mode 100644 index 000000000..b15b6e9d6 --- /dev/null +++ b/src/components/fields/Connect/SideDrawerField.tsx @@ -0,0 +1,73 @@ +import { Controller } from "react-hook-form"; +import { ISideDrawerFieldProps } from "../types"; +import { get } from "lodash"; + +import { useTheme, Grid, Chip } from "@mui/material"; + +import ConnectServiceSelect from "./Select"; + +export default function ConnectService({ + column, + control, + disabled, + docRef, +}: ISideDrawerFieldProps) { + const theme = useTheme(); + + const config = column.config ?? {}; + const displayKey = config.titleKey ?? config.primaryKey; + + return ( + { + const handleDelete = (hit: any) => () => { + // if (multiple) + onChange( + value.filter( + (v) => get(v, config.primaryKey) !== get(hit, config.primaryKey) + ) + ); + // else form.setFieldValue(field.name, []); + }; + + return ( + <> + {!disabled && ( + `${value?.length ?? 0} selected`, + }, + }} + /> + )} + + {Array.isArray(value) && ( + + {value.map((snapshot) => ( + + + + ))} + + )} + + ); + }} + /> + ); +} diff --git a/src/components/fields/Connect/index.tsx b/src/components/fields/Connect/index.tsx new file mode 100644 index 000000000..6266427ac --- /dev/null +++ b/src/components/fields/Connect/index.tsx @@ -0,0 +1,41 @@ +import { lazy } from "react"; +import { IFieldConfig, FieldType } from "@src/components/fields/types"; +import withPopoverCell from "../_withTableCell/withPopoverCell"; +import ConnectorIcon from "@mui/icons-material/Cable"; +import BasicCell from "../_BasicCell/BasicCellNull"; +import InlineCell from "./InlineCell"; +import NullEditor from "@src/components/Table/editors/NullEditor"; + +const PopoverCell = lazy( + () => + import("./PopoverCell" /* webpackChunkName: "PopoverCell-ConnectService" */) +); +const SideDrawerField = lazy( + () => + import( + "./SideDrawerField" /* webpackChunkName: "SideDrawerField-ConnectService" */ + ) +); +const Settings = lazy( + () => import("./Settings" /* webpackChunkName: "Settings-ConnectService" */) +); + +export const config: IFieldConfig = { + type: FieldType.connector, + name: "connector", + group: "Connection", + dataType: "any", + initialValue: [], + icon: , + description: + "Connects to any table or API to fetch a list of results based on a text query or row data.", + TableCell: withPopoverCell(BasicCell, InlineCell, PopoverCell, { + anchorOrigin: { horizontal: "left", vertical: "bottom" }, + transparent: true, + }), + TableEditor: NullEditor as any, + SideDrawerField, + requireConfiguration: true, + settings: Settings, +}; +export default config; diff --git a/src/components/fields/Connect/types.d.ts b/src/components/fields/Connect/types.d.ts new file mode 100644 index 000000000..9017df1f8 --- /dev/null +++ b/src/components/fields/Connect/types.d.ts @@ -0,0 +1,5 @@ +type ConnectService = (request: { + query: string; + row: any; + user: any; +}) => Promise; diff --git a/src/components/fields/Connect/utils.ts b/src/components/fields/Connect/utils.ts new file mode 100644 index 000000000..8d0a1f4b9 --- /dev/null +++ b/src/components/fields/Connect/utils.ts @@ -0,0 +1,9 @@ +export const sanitiseValue = (value: any) => { + if (value === undefined || value === null || value === "") return []; + else return value as string[]; +}; + +export const baseFunction = `const serviceFunction: ConnectService = async ({query, row, user}) => { + // TODO: Implement your service function here + return []; +};`; diff --git a/src/components/fields/index.tsx b/src/components/fields/index.tsx index d43402958..c68f65303 100644 --- a/src/components/fields/index.tsx +++ b/src/components/fields/index.tsx @@ -39,6 +39,7 @@ import UpdatedAt from "./UpdatedAt"; import User from "./User"; import Id from "./Id"; import Status from "./Status"; +import Connect from "./Connect"; import { TableColumn } from "../Table"; // Export field configs in order for FieldsDropdown @@ -68,6 +69,7 @@ export const FIELDS: IFieldConfig[] = [ Image_, File_, // CONNECTION + Connect, SubTable, ConnectTable, ConnectService, diff --git a/src/constants/fields.ts b/src/constants/fields.ts index 991a34f02..71a806661 100644 --- a/src/constants/fields.ts +++ b/src/constants/fields.ts @@ -26,6 +26,7 @@ export enum FieldType { file = "FILE", // CONNECTION subTable = "SUB_TABLE", + connector = "CONNECTOR", connectTable = "DOCUMENT_SELECT", connectService = "SERVICE_SELECT", // CODE diff --git a/src/utils/fns.ts b/src/utils/fns.ts index 3f20d77ec..2e404262e 100644 --- a/src/utils/fns.ts +++ b/src/utils/fns.ts @@ -195,3 +195,9 @@ export const isTargetInsideBox = (target, box) => { const boxRect = box.getBoundingClientRect(); return targetRect.y < boxRect.y + boxRect.height; }; + +export const replacer = (data: any) => (m: string, key: string) => { + const objKey = key.split(":")[0]; + const defaultValue = key.split(":")[1] || ""; + return _get(data, objKey, defaultValue); +}; From fa28e48361bb4e73e13710a414a3c9ae5f173dc5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Mar 2022 13:57:40 +0000 Subject: [PATCH 16/36] Bump minimist from 1.2.5 to 1.2.6 Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6. - [Release notes](https://github.com/substack/minimist/releases) - [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6) --- updated-dependencies: - dependency-name: minimist 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 642c6f9e8..3a9861da0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11864,9 +11864,9 @@ minimatch@3.0.4, minimatch@^3.0.4: brace-expansion "^1.1.7" minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== minipass-collect@^1.0.2: version "1.0.2" From ce18d1a824967c62ba2d8001666cfd5e7f6ac7a3 Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Thu, 31 Mar 2022 16:48:16 +0200 Subject: [PATCH 17/36] connector field --- src/components/fields/Connect/utils.ts | 9 ----- .../{Connect => Connector}/InlineCell.tsx | 7 ++-- .../{Connect => Connector}/PopoverCell.tsx | 5 +-- .../Select/PopupContents.tsx | 22 +++++-------- .../{Connect => Connector}/Select/index.tsx | 6 +--- .../{Connect => Connector}/Select/styles.ts | 0 .../{Connect => Connector}/Settings.tsx | 19 +++-------- .../SideDrawerField.tsx | 33 ++++++++++--------- .../fields/Connector/connector.d.ts | 22 +++++++++++++ .../fields/{Connect => Connector}/index.tsx | 2 +- .../fields/{Connect => Connector}/types.d.ts | 0 src/components/fields/Connector/utils.ts | 21 ++++++++++++ src/components/fields/index.tsx | 4 +-- 13 files changed, 83 insertions(+), 67 deletions(-) delete mode 100644 src/components/fields/Connect/utils.ts rename src/components/fields/{Connect => Connector}/InlineCell.tsx (88%) rename src/components/fields/{Connect => Connector}/PopoverCell.tsx (88%) rename src/components/fields/{Connect => Connector}/Select/PopupContents.tsx (92%) rename src/components/fields/{Connect => Connector}/Select/index.tsx (97%) rename src/components/fields/{Connect => Connector}/Select/styles.ts (100%) rename src/components/fields/{Connect => Connector}/Settings.tsx (93%) rename src/components/fields/{Connect => Connector}/SideDrawerField.tsx (67%) create mode 100644 src/components/fields/Connector/connector.d.ts rename src/components/fields/{Connect => Connector}/index.tsx (98%) rename src/components/fields/{Connect => Connector}/types.d.ts (100%) create mode 100644 src/components/fields/Connector/utils.ts diff --git a/src/components/fields/Connect/utils.ts b/src/components/fields/Connect/utils.ts deleted file mode 100644 index 8d0a1f4b9..000000000 --- a/src/components/fields/Connect/utils.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const sanitiseValue = (value: any) => { - if (value === undefined || value === null || value === "") return []; - else return value as string[]; -}; - -export const baseFunction = `const serviceFunction: ConnectService = async ({query, row, user}) => { - // TODO: Implement your service function here - return []; -};`; diff --git a/src/components/fields/Connect/InlineCell.tsx b/src/components/fields/Connector/InlineCell.tsx similarity index 88% rename from src/components/fields/Connect/InlineCell.tsx rename to src/components/fields/Connector/InlineCell.tsx index 95a93c34b..bdd05840b 100644 --- a/src/components/fields/Connect/InlineCell.tsx +++ b/src/components/fields/Connector/InlineCell.tsx @@ -6,6 +6,7 @@ import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown"; import ChipList from "@src/components/Table/formatters/ChipList"; import { get } from "lodash"; +import { getLabel } from "./utils"; export const ConnectService = forwardRef(function ConnectService( { value, showPopoverCell, disabled, column }: IPopoverInlineCellProps, @@ -30,9 +31,9 @@ export const ConnectService = forwardRef(function ConnectService( > {Array.isArray(value) && - value.map((snapshot) => ( - - + value.map((item) => ( + + ))} diff --git a/src/components/fields/Connect/PopoverCell.tsx b/src/components/fields/Connector/PopoverCell.tsx similarity index 88% rename from src/components/fields/Connect/PopoverCell.tsx rename to src/components/fields/Connector/PopoverCell.tsx index 9356d8f76..e2d4beb55 100644 --- a/src/components/fields/Connect/PopoverCell.tsx +++ b/src/components/fields/Connector/PopoverCell.tsx @@ -11,14 +11,11 @@ export default function ConnectService({ disabled, docRef, }: IPopoverCellProps) { - const config = column.config ?? {}; - if (!config) return null; - return ( {} @@ -32,11 +33,12 @@ export interface IPopupContentsProps export default function PopupContents({ value = [], onChange, - config, + column, docRef, }: IPopupContentsProps) { const { rowyRun, tableState } = useProjectContext(); // const url = config.url ; + const { config } = column; const elementId = config.elementId; const multiple = Boolean(config.multiple); @@ -47,23 +49,17 @@ export default function PopupContents({ // Webservice response const [response, setResponse] = useState(null); - const [docData, setDocData] = useState(null); - useEffect(() => { - docRef.get().then((d) => setDocData(d.data())); - }, []); const hits: any["hits"] = response; const [search] = useDebouncedCallback( async (query: string) => { - if (!docData) return; const resp = await rowyRun!({ route: { method: "POST", path: "/connect" }, body: { - columnKey: "game", + columnKey: column.key, query: query, schemaDocPath: tableState?.config.tableConfig.path, }, }); - console.log(resp); setResponse(resp); }, 1000, @@ -72,7 +68,7 @@ export default function PopupContents({ useEffect(() => { search(query); - }, [query, docData]); + }, [query]); if (!response) return ; @@ -127,6 +123,9 @@ export default function PopupContents({ = config.max + } > {multiple ? ( @@ -157,10 +156,7 @@ export default function PopupContents({ diff --git a/src/components/fields/Connect/Select/index.tsx b/src/components/fields/Connector/Select/index.tsx similarity index 97% rename from src/components/fields/Connect/Select/index.tsx rename to src/components/fields/Connector/Select/index.tsx index 90a66ddee..9356737ac 100644 --- a/src/components/fields/Connect/Select/index.tsx +++ b/src/components/fields/Connector/Select/index.tsx @@ -16,10 +16,7 @@ export type ServiceValue = { export interface IConnectServiceSelectProps { value: ServiceValue[]; onChange: (value: ServiceValue[]) => void; - config: { - displayKey: string; - [key: string]: any; - }; + column: any; editable?: boolean; /** Optional style overrides for root MUI `TextField` component */ className?: string; @@ -39,7 +36,6 @@ export default function ConnectServiceSelect({ const classes = useStyles(); const sanitisedValue = Array.isArray(value) ? value : []; - return ( Promise;`, - ]} + extraLibs={[connectorDefs]} /> @@ -144,15 +144,6 @@ export default function Settings({ config, onChange }) { } /> - - ), - }, - - { - id: "optionsSettings", - title: "Options Settings", - content: ( - diff --git a/src/components/fields/Connect/SideDrawerField.tsx b/src/components/fields/Connector/SideDrawerField.tsx similarity index 67% rename from src/components/fields/Connect/SideDrawerField.tsx rename to src/components/fields/Connector/SideDrawerField.tsx index b15b6e9d6..32e0c077d 100644 --- a/src/components/fields/Connect/SideDrawerField.tsx +++ b/src/components/fields/Connector/SideDrawerField.tsx @@ -5,6 +5,7 @@ import { get } from "lodash"; import { useTheme, Grid, Chip } from "@mui/material"; import ConnectServiceSelect from "./Select"; +import { getLabel } from "./utils"; export default function ConnectService({ column, @@ -22,13 +23,9 @@ export default function ConnectService({ control={control} name={column.key} render={({ field: { onChange, onBlur, value } }) => { - const handleDelete = (hit: any) => () => { + const handleDelete = (id: any) => () => { // if (multiple) - onChange( - value.filter( - (v) => get(v, config.primaryKey) !== get(hit, config.primaryKey) - ) - ); + onChange(value.filter((v) => get(v, config.elementId) !== id)); // else form.setFieldValue(field.name, []); }; @@ -36,7 +33,7 @@ export default function ConnectService({ <> {!disabled && ( - {value.map((snapshot) => ( - - - - ))} + {value.map((item) => { + const key = get(item, config.elementId); + console.log(key, item); + return ( + + + + ); + })} )} diff --git a/src/components/fields/Connector/connector.d.ts b/src/components/fields/Connector/connector.d.ts new file mode 100644 index 000000000..d031d64bd --- /dev/null +++ b/src/components/fields/Connector/connector.d.ts @@ -0,0 +1,22 @@ +type ConnectorUser = { + timestamp: Date; + displayName: string; + email: string; + uid: string; + emailVerified: boolean; + photoURL: string; + roles: string[]; +}; +type ConnectorContext = { + row: Row; + ref: FirebaseFirestore.DocumentReference; + storage: firebasestorage.Storage; + db: FirebaseFirestore.Firestore; + auth: firebaseauth.BaseAuth; + query: string; + user: ConnectorUser; +}; +type ConnectorResult = any[]; +type Connector = ( + context: ConnectorContext +) => Promise | ActionResult; diff --git a/src/components/fields/Connect/index.tsx b/src/components/fields/Connector/index.tsx similarity index 98% rename from src/components/fields/Connect/index.tsx rename to src/components/fields/Connector/index.tsx index 6266427ac..e15f50ade 100644 --- a/src/components/fields/Connect/index.tsx +++ b/src/components/fields/Connector/index.tsx @@ -22,7 +22,7 @@ const Settings = lazy( export const config: IFieldConfig = { type: FieldType.connector, - name: "connector", + name: "Connector", group: "Connection", dataType: "any", initialValue: [], diff --git a/src/components/fields/Connect/types.d.ts b/src/components/fields/Connector/types.d.ts similarity index 100% rename from src/components/fields/Connect/types.d.ts rename to src/components/fields/Connector/types.d.ts diff --git a/src/components/fields/Connector/utils.ts b/src/components/fields/Connector/utils.ts new file mode 100644 index 000000000..e201d3f05 --- /dev/null +++ b/src/components/fields/Connector/utils.ts @@ -0,0 +1,21 @@ +import { replacer } from "@src/utils/fns"; +import _get from "lodash/get"; +export const sanitiseValue = (value: any) => { + if (value === undefined || value === null || value === "") return []; + else return value as string[]; +}; + +export const baseFunction = `const connectorFn: Connector = async ({query, row, user}) => { + // TODO: Implement your service function here + return []; +};`; + +export const getLabel = (config, row) => { + if (!config.labelFormatter) { + return `⚠️ needs configuration`; + } else if (config.labelFormatter.includes("{{")) { + return config.labelFormatter.replace(/\{\{(.*?)\}\}/g, replacer(row)); + } else { + return _get(row, config.labelFormatter); + } +}; diff --git a/src/components/fields/index.tsx b/src/components/fields/index.tsx index c68f65303..85b893a36 100644 --- a/src/components/fields/index.tsx +++ b/src/components/fields/index.tsx @@ -39,7 +39,7 @@ import UpdatedAt from "./UpdatedAt"; import User from "./User"; import Id from "./Id"; import Status from "./Status"; -import Connect from "./Connect"; +import Connector from "./Connector"; import { TableColumn } from "../Table"; // Export field configs in order for FieldsDropdown @@ -69,7 +69,7 @@ export const FIELDS: IFieldConfig[] = [ Image_, File_, // CONNECTION - Connect, + Connector, SubTable, ConnectTable, ConnectService, From 82273144c7dc9ad553705acb7ef4d3fa8ca4956a Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Thu, 31 Mar 2022 16:48:36 +0200 Subject: [PATCH 18/36] fix action params --- src/components/fields/Action/Settings.tsx | 2 +- src/components/fields/Action/action.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/fields/Action/Settings.tsx b/src/components/fields/Action/Settings.tsx index 36a59ae1b..7f6eec8a8 100644 --- a/src/components/fields/Action/Settings.tsx +++ b/src/components/fields/Action/Settings.tsx @@ -76,7 +76,7 @@ const Settings = ({ config, onChange }) => { const scriptExtraLibs = [ [ - "declare class ActionParams {", + "declare interface actionParams {", " /**", " * actionParams are provided by dialog popup form", " */", diff --git a/src/components/fields/Action/action.d.ts b/src/components/fields/Action/action.d.ts index 82ecf5e9c..a43399782 100644 --- a/src/components/fields/Action/action.d.ts +++ b/src/components/fields/Action/action.d.ts @@ -13,7 +13,7 @@ type ActionContext = { storage: firebasestorage.Storage; db: FirebaseFirestore.Firestore; auth: firebaseauth.BaseAuth; - actionParams: ActionParams; + actionParams: actionParams; user: ActionUser; }; From b306a1cd6d59777f0ef7aff3001e2abb9e70ca35 Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Thu, 31 Mar 2022 16:48:55 +0200 Subject: [PATCH 19/36] debounce color picker --- src/components/fields/Color/PopoverCell.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/components/fields/Color/PopoverCell.tsx b/src/components/fields/Color/PopoverCell.tsx index 0e6e90e60..6607b0b41 100644 --- a/src/components/fields/Color/PopoverCell.tsx +++ b/src/components/fields/Color/PopoverCell.tsx @@ -1,16 +1,23 @@ import { IPopoverCellProps } from "../types"; import { ColorPicker, toColor } from "react-color-palette"; +import { useDebouncedCallback } from "use-debounce"; import "react-color-palette/lib/css/styles.css"; +import { useEffect, useState } from "react"; export default function Color({ value, onSubmit }: IPopoverCellProps) { - const handleChangeComplete = (color: any) => onSubmit(color); - + const [localValue, setLocalValue] = useState(value); + const [handleChangeComplete] = useDebouncedCallback((color) => { + onSubmit(color); + }, 400); + useEffect(() => { + handleChangeComplete(localValue); + }, [localValue]); return ( ); From d2c300f08e52eae2e32df09f1f183233f6c214cc Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Thu, 31 Mar 2022 18:37:32 +0200 Subject: [PATCH 20/36] connector branding --- src/components/CodeEditor/rowy.d.ts | 5 +++- .../fields/Connector/Select/PopupContents.tsx | 23 +++++++++++++++---- .../fields/Connector/Select/index.tsx | 6 ++--- src/components/fields/Connector/Settings.tsx | 6 ++--- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/components/CodeEditor/rowy.d.ts b/src/components/CodeEditor/rowy.d.ts index 86d7b144e..f6852cce2 100644 --- a/src/components/CodeEditor/rowy.d.ts +++ b/src/components/CodeEditor/rowy.d.ts @@ -48,7 +48,10 @@ interface Rowy { /** * Get an existing secret from the secret manager. */ - get: (name: SecretNames, version?: string) => Promise; + get: ( + name: SecretNames, + version?: string + ) => Promise; }; /** * Gives access to the Cloud Storage. diff --git a/src/components/fields/Connector/Select/PopupContents.tsx b/src/components/fields/Connector/Select/PopupContents.tsx index 34911c6a6..1d4c79d5c 100644 --- a/src/components/fields/Connector/Select/PopupContents.tsx +++ b/src/components/fields/Connector/Select/PopupContents.tsx @@ -19,15 +19,16 @@ import { } from "@mui/material"; import SearchIcon from "@mui/icons-material/Search"; -import { IConnectServiceSelectProps } from "."; +import { IConnectorSelectProps } from "."; import useStyles from "./styles"; import Loading from "@src/components/Loading"; import { useProjectContext } from "@src/contexts/ProjectContext"; import { replacer } from "@src/utils/fns"; import { getLabel } from "../utils"; +import { useSnackbar } from "notistack"; export interface IPopupContentsProps - extends Omit {} + extends Omit {} // TODO: Implement infinite scroll here export default function PopupContents({ @@ -37,6 +38,8 @@ export default function PopupContents({ docRef, }: IPopupContentsProps) { const { rowyRun, tableState } = useProjectContext(); + + const { enqueueSnackbar } = useSnackbar(); // const url = config.url ; const { config } = column; const elementId = config.elementId; @@ -48,16 +51,28 @@ export default function PopupContents({ const [query, setQuery] = useState(""); // Webservice response const [response, setResponse] = useState(null); + const [hits, setHits] = useState([]); - const hits: any["hits"] = response; + useEffect(() => { + console.log(response); + if (response?.success === false) { + enqueueSnackbar(response.message, { variant: "error" }); + } else if (Array.isArray(response?.hits)) { + setHits(response.hits); + } else { + setHits([]); + //enqueueSnackbar("response is not any array", { variant: "error" }); + } + }, [response]); const [search] = useDebouncedCallback( async (query: string) => { const resp = await rowyRun!({ - route: { method: "POST", path: "/connect" }, + route: { method: "POST", path: "/connector" }, body: { columnKey: column.key, query: query, schemaDocPath: tableState?.config.tableConfig.path, + rowDocPath: docRef.path, }, }); setResponse(resp); diff --git a/src/components/fields/Connector/Select/index.tsx b/src/components/fields/Connector/Select/index.tsx index 9356737ac..7508b7cfc 100644 --- a/src/components/fields/Connector/Select/index.tsx +++ b/src/components/fields/Connector/Select/index.tsx @@ -13,7 +13,7 @@ export type ServiceValue = { [prop: string]: any; }; -export interface IConnectServiceSelectProps { +export interface IConnectorSelectProps { value: ServiceValue[]; onChange: (value: ServiceValue[]) => void; column: any; @@ -26,13 +26,13 @@ export interface IConnectServiceSelectProps { disabled?: boolean; } -export default function ConnectServiceSelect({ +export default function ConnectorSelect({ value = [], className, TextFieldProps = {}, disabled, ...props -}: IConnectServiceSelectProps) { +}: IConnectorSelectProps) { const classes = useStyles(); const sanitisedValue = Array.isArray(value) ? value : []; diff --git a/src/components/fields/Connector/Settings.tsx b/src/components/fields/Connector/Settings.tsx index c30016bb6..023438a66 100644 --- a/src/components/fields/Connector/Settings.tsx +++ b/src/components/fields/Connector/Settings.tsx @@ -66,14 +66,14 @@ export default function Settings({ config, onChange }) { steps={[ { id: "function", - title: "Connect Function", + title: "Connector Function", content: ( }> From 8679b2e50192e78e126195e1dbefeaf92e937b35 Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Thu, 31 Mar 2022 18:52:05 +0200 Subject: [PATCH 21/36] fix adding columns when filters or orderBys are applied --- src/hooks/useTable/useTableData.tsx | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/hooks/useTable/useTableData.tsx b/src/hooks/useTable/useTableData.tsx index 96b3aec9d..5f72a8923 100644 --- a/src/hooks/useTable/useTableData.tsx +++ b/src/hooks/useTable/useTableData.tsx @@ -310,14 +310,19 @@ const useTableData = () => { let ref = db.collection(path).doc(); if (typeof id === "string") ref = db.collection(path).doc(id); - else if (id?.type === "smaller") - ref = db - .collection(path) - .doc( - decrementId( - rows.find((r) => !r._rowy_outOfOrder)?.id ?? "zzzzzzzzzzzzzzzzzzzz" - ) - ); + else if (id?.type === "smaller") { + let prevId = + rows.find((r) => !r._rowy_outOfOrder)?.id ?? "zzzzzzzzzzzzzzzzzzzz"; + if ( + tableState.orderBy?.length !== 0 || + tableState.filters?.length !== 0 + ) { + const query = await db.collection(tableState.path).limit(1).get(); + prevId = query.empty ? "zzzzzzzzzzzzzzzzzzzz" : query.docs[0].id; + } + ref = db.collection(path).doc(decrementId(prevId)); + } + const newId = ref.id; const missingRequiredFields = requiredFields From 269bf997de6fe3c070d4134353257137e40d4cc9 Mon Sep 17 00:00:00 2001 From: shamsmosowi Date: Sun, 3 Apr 2022 19:54:53 +0200 Subject: [PATCH 22/36] connector --- .../fields/ConnectService/Settings.tsx | 323 +----------------- .../fields/ConnectService/types.d.ts | 5 - src/components/fields/ConnectService/utils.ts | 5 - src/components/fields/Connector/Settings.tsx | 213 ++++++------ src/constants/externalLinks.ts | 1 + 5 files changed, 103 insertions(+), 444 deletions(-) delete mode 100644 src/components/fields/ConnectService/types.d.ts diff --git a/src/components/fields/ConnectService/Settings.tsx b/src/components/fields/ConnectService/Settings.tsx index 93702cb83..f0ed6d685 100644 --- a/src/components/fields/ConnectService/Settings.tsx +++ b/src/components/fields/ConnectService/Settings.tsx @@ -1,324 +1,8 @@ -import { lazy, Suspense, useState } from "react"; -import _get from "lodash/get"; -import stringify from "json-stable-stringify-without-jsonify"; - -import { - Stepper, - Step, - StepButton, - StepContent, - Stack, - Grid, - Switch, - TextField, - FormControl, - FormLabel, - FormControlLabel, - RadioGroup, - Radio, - Typography, - InputLabel, - Link, - Checkbox, - FormHelperText, - Fab, -} from "@mui/material"; - -import SteppedAccordion from "@src/components/SteppedAccordion"; -import MultiSelect from "@rowy/multiselect"; -import FieldSkeleton from "@src/components/SideDrawer/Form/FieldSkeleton"; -import CodeEditorHelper from "@src/components/CodeEditor/CodeEditorHelper"; -import InlineOpenInNewIcon from "@src/components/InlineOpenInNewIcon"; - -import { useProjectContext } from "@src/contexts/ProjectContext"; -import { WIKI_LINKS } from "@src/constants/externalLinks"; -import { useAppContext } from "@src/contexts/AppContext"; -import { baseFunction } from "./utils"; - -//import typeDefs from "!!raw-loader!./types.d.ts"; -const CodeEditor = lazy( - () => - import("@src/components/CodeEditor" /* webpackChunkName: "CodeEditor" */) -); - -// external service requirement -// Web service URL : url -// Results key path :resultsKey -// Primary Key : primaryKey -// Title Key : titleKey - -// rowy managed service -// function that takes query & user then returns a list of objects with an array of objects -// Primary Key : primaryKey -// label Key : labelKey - -const diagnosticsOptions = { - noSemanticValidation: false, - noSyntaxValidation: false, - noSuggestionDiagnostics: true, -}; +import { TextField, FormControlLabel, Switch, Grid } from "@mui/material"; export default function Settings({ config, onChange }) { - const { projectId } = useAppContext(); return ( - - - - Select the service mode: - - onChange("mode")(e.target.value)} - > - } - label={ - <> - Managed - - Write JavaScript code below that will be executed by - Rowy Run to return list of options displayed in the - dropdown{" "} - - Requires Rowy Run setup - - - - - } - /> - } - label={ - <> - External - - An existing api endpoint or your own web service, that - will be called when the dropdown is opened. - - Learn more - - - - - } - /> - - - - {config.mode === "external" ? ( - onChange("url")(e.target.value)} - helperText={ - <> - Add the url of the endpoint. If you have deployed it to - Cloud Run you can find it{" "} - - here - - -
- Your endpoint must be compatible with Rowy Connect service - columns.{" "} - - View requirements - - - - } - /> - ) : ( - <> - - Service Function - }> - Promise;`, - ]} - /> - - - - - )} -
- ), - }, - { - id: "Interface", - title: "Interface", - content: ( - - - {/* Primary Key */} - onChange("primaryKey")(e.target.value)} - helperText={ - <> - The key that will be used to uniquely identify the - selected option.{" "} - - Learn more - - - - } - /> - - - {/* Title Key */} - onChange("titleKey")(e.target.value)} - helperText={ - <> - The key that will be used to display the selected option.{" "} - - Learn more - - - - } - /> - - {config.mode === "external" && ( - - {/* Results Key */} - onChange("resultsKey")(e.target.value)} - helperText={ - <> - (Optional)The key that will be used to retrieve the list - of results, if the service doesn't not return an array - options directly{" "} - - Learn more - - - - } - /> - - )} - - ), - }, - - { - id: "optionsSettings", - title: "Options Settings", - content: ( - - - - - Allow for multiple item selection - - onChange("multiple")(e.target.checked)} - /> - - - - {config.multiple && ( - <> - onChange("max")(e.target.value)} - helperText="The maximum number of items that can be selected, or 0 for no limit." - /> - - )} - - - ), - }, - ]} - /> - ); -} - -/* -<> + <> -*/ + ); +} diff --git a/src/components/fields/ConnectService/types.d.ts b/src/components/fields/ConnectService/types.d.ts deleted file mode 100644 index 9017df1f8..000000000 --- a/src/components/fields/ConnectService/types.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -type ConnectService = (request: { - query: string; - row: any; - user: any; -}) => Promise; diff --git a/src/components/fields/ConnectService/utils.ts b/src/components/fields/ConnectService/utils.ts index 8d0a1f4b9..d2feec47b 100644 --- a/src/components/fields/ConnectService/utils.ts +++ b/src/components/fields/ConnectService/utils.ts @@ -2,8 +2,3 @@ export const sanitiseValue = (value: any) => { if (value === undefined || value === null || value === "") return []; else return value as string[]; }; - -export const baseFunction = `const serviceFunction: ConnectService = async ({query, row, user}) => { - // TODO: Implement your service function here - return []; -};`; diff --git a/src/components/fields/Connector/Settings.tsx b/src/components/fields/Connector/Settings.tsx index 023438a66..7f2400647 100644 --- a/src/components/fields/Connector/Settings.tsx +++ b/src/components/fields/Connector/Settings.tsx @@ -62,120 +62,103 @@ const diagnosticsOptions = { export default function Settings({ config, onChange }) { const { projectId } = useAppContext(); return ( - - }> - - - -
- ), - }, - { - id: "config", - title: "Configuration", - content: ( - - - {/* Primary Key */} - onChange("elementId")(e.target.value)} - helperText={ - <> - The key that will be used to uniquely identify the - selected option.{" "} - - Learn more - - - - } - /> - - - {/* Title Key */} - onChange("labelFormatter")(e.target.value)} - helperText={ - <> - The key that will be used to display the selected option.{" "} - - Learn more - - - - } - /> - - - - - Allow for multiple item selection - - onChange("multiple")(e.target.checked)} - /> - - - - {config.multiple && ( - <> - onChange("max")(e.target.value)} - helperText="The maximum number of items that can be selected, or 0 for no limit." - /> - - )} - - - ), - }, - ]} - /> + <> +
+ Connector Function + }> + + + +
+ + {/* Primary Key */} + onChange("elementId")(e.target.value)} + helperText={ + <> + The key that will be used to uniquely identify the selected + option.{" "} + + Learn more + + + + } + /> + + + {/* Title Key */} + onChange("labelFormatter")(e.target.value)} + helperText={ + <> + The field key or template that will be used to display the + selected option.{" "} + + Learn more + + + + } + /> + + + + + Allow for multiple item selection + + onChange("multiple")(e.target.checked)} + /> + + + + {config.multiple && ( + <> + onChange("max")(e.target.value)} + helperText="The maximum number of items that can be selected, or 0 for no limit." + /> + + )} + + ); } diff --git a/src/constants/externalLinks.ts b/src/constants/externalLinks.ts index 8e069285a..18de531cc 100644 --- a/src/constants/externalLinks.ts +++ b/src/constants/externalLinks.ts @@ -36,6 +36,7 @@ const WIKI_PATHS = { fieldTypesSupportedFields: "/field-types/supported-fields", fieldTypesDerivative: "/field-types/derivative", fieldTypesConnectTable: "/field-types/connect-table", + fieldTypesConnector: "/field-types/connector", fieldTypesConnectService: "/field-types/connect-service", fieldTypesAction: "/field-types/action", fieldTypesAdd: "/field-types/add", From 15b2e3b92df615f0657a271b0f820de60b5f0a71 Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Wed, 6 Apr 2022 16:02:15 +1000 Subject: [PATCH 23/36] RenderedMarkdown: allow components prop overrides --- src/components/RenderedMarkdown.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/RenderedMarkdown.tsx b/src/components/RenderedMarkdown.tsx index 689bddf2b..964739ae4 100644 --- a/src/components/RenderedMarkdown.tsx +++ b/src/components/RenderedMarkdown.tsx @@ -33,7 +33,7 @@ export default function RenderedMarkdown({ unwrapDisallowed linkTarget="_blank" remarkPlugins={remarkPlugins} - components={components} + components={{ ...components, ...props.components }} /> ); } From e148ffcd6561ca99123c390cb075cc0e00399aa5 Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Wed, 6 Apr 2022 16:02:24 +1000 Subject: [PATCH 24/36] add FullScreenModal component --- src/components/Modal/FullScreenModal.tsx | 110 +++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/components/Modal/FullScreenModal.tsx diff --git a/src/components/Modal/FullScreenModal.tsx b/src/components/Modal/FullScreenModal.tsx new file mode 100644 index 000000000..3a30ead74 --- /dev/null +++ b/src/components/Modal/FullScreenModal.tsx @@ -0,0 +1,110 @@ +import { ReactNode, useState } from "react"; + +import { + Dialog, + DialogProps, + Slide, + IconButton, + Container, +} from "@mui/material"; +import CloseIcon from "@mui/icons-material/Close"; + +import ScrollableDialogContent, { + IScrollableDialogContentProps, +} from "./ScrollableDialogContent"; + +export interface IFullScreenModalProps + extends Partial> { + onClose: (setOpen: React.Dispatch>) => void; + disableBackdropClick?: boolean; + disableEscapeKeyDown?: boolean; + + "aria-labelledby": DialogProps["aria-labelledby"]; + header?: ReactNode; + children?: ReactNode; + footer?: ReactNode; + + hideCloseButton?: boolean; + ScrollableDialogContentProps?: Partial; +} + +export default function FullScreenModal({ + onClose, + disableBackdropClick, + disableEscapeKeyDown, + header, + children, + footer, + hideCloseButton, + ScrollableDialogContentProps, + ...props +}: IFullScreenModalProps) { + const [open, setOpen] = useState(true); + const handleClose: NonNullable = (_, reason) => { + if ( + (disableBackdropClick && reason === "backdropClick") || + (disableEscapeKeyDown && reason === "escapeKeyDown") + ) { + setEmphasizeCloseButton(true); + return; + } + + setOpen(false); + setEmphasizeCloseButton(false); + setTimeout(() => onClose(setOpen), 300); + }; + + const [emphasizeCloseButton, setEmphasizeCloseButton] = useState(false); + + return ( + + + {!hideCloseButton && ( + theme.spacing(1), + right: (theme) => theme.spacing(1), + + bgcolor: emphasizeCloseButton ? "error.main" : undefined, + color: emphasizeCloseButton ? "error.contrastText" : undefined, + "&:hover": emphasizeCloseButton + ? { bgcolor: "error.dark" } + : undefined, + }} + className="dialog-close" + > + + + )} + + {header} + + + {children} + + + {footer} + + + ); +} From 7ad3ff2dc28e574d165146bea2660f47007a3dbe Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Wed, 6 Apr 2022 16:05:16 +1000 Subject: [PATCH 25/36] allow table creation with _schema doc preset --- src/components/TableSettings/index.tsx | 8 ++++++++ src/pages/Home.tsx | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/components/TableSettings/index.tsx b/src/components/TableSettings/index.tsx index 8f11b2f8b..a2ccf90f0 100644 --- a/src/components/TableSettings/index.tsx +++ b/src/components/TableSettings/index.tsx @@ -25,6 +25,7 @@ import { TABLE_GROUP_SCHEMAS, TABLE_SCHEMAS, } from "@src/config/dbPaths"; +import { Controller } from "react-hook-form"; export enum TableSettingsDialogModes { create, @@ -203,6 +204,13 @@ export default function TableSettings({ return ( <> + <>} + /> + + const handleCreateTable = (data?: null | (Table & { tableType: string })) => setSettingsDialogState({ mode: TableSettingsDialogModes.create, - data: null, + data: data || null, }); const [settingsDocState] = useDoc( @@ -107,7 +107,7 @@ export default function HomePage() { handleCreateTable()} sx={{ zIndex: "speedDial", position: "fixed", From 9539b03eed56f67b108f874b6122b75ca4ab0f4b Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Wed, 6 Apr 2022 16:05:50 +1000 Subject: [PATCH 26/36] create table: fix table page not opening when user chooses to deploy later --- src/components/ConfirmationDialog/Dialog.tsx | 10 +++++++- src/components/ConfirmationDialog/props.ts | 1 + src/components/TableSettings/index.tsx | 25 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/components/ConfirmationDialog/Dialog.tsx b/src/components/ConfirmationDialog/Dialog.tsx index 0e06760cf..64ac30ac8 100644 --- a/src/components/ConfirmationDialog/Dialog.tsx +++ b/src/components/ConfirmationDialog/Dialog.tsx @@ -21,6 +21,7 @@ export default function Confirmation({ confirm, confirmationCommand, handleConfirm, + handleCancel, confirmColor, open, handleClose, @@ -60,7 +61,14 @@ export default function Confirmation({ {!hideCancel && ( - + )}