From 8e899dad7802b676ab57212cf16ddbe96057c546 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Tue, 22 Nov 2022 03:04:26 +0800 Subject: [PATCH 01/14] enable derivatives logging in code editor --- src/components/CodeEditor/CodeEditorHelper.tsx | 4 ++++ src/components/fields/Derivative/Settings.tsx | 4 ++-- src/components/fields/Derivative/derivative.d.ts | 5 +++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/CodeEditor/CodeEditorHelper.tsx b/src/components/CodeEditor/CodeEditorHelper.tsx index 299c2134..04326e3c 100644 --- a/src/components/CodeEditor/CodeEditorHelper.tsx +++ b/src/components/CodeEditor/CodeEditorHelper.tsx @@ -38,6 +38,10 @@ export default function CodeEditorHelper({ key: "rowy", description: `rowy provides a set of functions that are commonly used, such as easy file uploads & access to GCP Secret Manager`, }, + { + key: "logging", + description: `logging.log is encouraged to replace console.log`, + }, ]; return ( diff --git a/src/components/fields/Derivative/Settings.tsx b/src/components/fields/Derivative/Settings.tsx index 32ce65dc..7fe36869 100644 --- a/src/components/fields/Derivative/Settings.tsx +++ b/src/components/fields/Derivative/Settings.tsx @@ -65,10 +65,10 @@ export default function Settings({ : config.derivativeFn ? config.derivativeFn : config?.script - ? `const derivative:Derivative = async ({row,ref,db,storage,auth})=>{ + ? `const derivative:Derivative = async ({row,ref,db,storage,auth,logging})=>{ ${config.script.replace(/utilFns.getSecret/g, "rowy.secrets.get")} }` - : `const derivative:Derivative = async ({row,ref,db,storage,auth})=>{ + : `const derivative:Derivative = async ({row,ref,db,storage,auth,logging})=>{ // Write your derivative code here // for example: // const sum = row.a + row.b; diff --git a/src/components/fields/Derivative/derivative.d.ts b/src/components/fields/Derivative/derivative.d.ts index 3af58e11..9d01f97c 100644 --- a/src/components/fields/Derivative/derivative.d.ts +++ b/src/components/fields/Derivative/derivative.d.ts @@ -5,6 +5,11 @@ type DerivativeContext = { db: FirebaseFirestore.Firestore; auth: firebaseauth.BaseAuth; change: any; + logging: { + log: (payload: any) => void; + warn: (payload: any) => void; + error: (payload: any) => void; + }; }; type Derivative = (context: DerivativeContext) => "PLACEHOLDER_OUTPUT_TYPE"; From 5baa6386917360273d2424280dd301ecf45821e8 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Wed, 23 Nov 2022 21:26:36 +0800 Subject: [PATCH 02/14] enable actions logging in code editor --- src/components/fields/Action/Settings.tsx | 82 ++++++++++--------- src/components/fields/Action/action.d.ts | 3 + src/components/fields/Action/templates.ts | 4 +- .../fields/Derivative/derivative.d.ts | 8 +- src/components/fields/types.ts | 9 ++ 5 files changed, 59 insertions(+), 47 deletions(-) diff --git a/src/components/fields/Action/Settings.tsx b/src/components/fields/Action/Settings.tsx index 9c2562a1..735423ef 100644 --- a/src/components/fields/Action/Settings.tsx +++ b/src/components/fields/Action/Settings.tsx @@ -130,7 +130,7 @@ const Settings = ({ config, onChange, fieldName }: ISettingsProps) => { : config?.runFn ? config.runFn : config?.script - ? `const action:Action = async ({row,ref,db,storage,auth,actionParams,user}) => { + ? `const action:Action = async ({row,ref,db,storage,auth,actionParams,user,logging}) => { ${config.script.replace(/utilFns.getSecret/g, "rowy.secrets.get")} }` : RUN_ACTION_TEMPLATE; @@ -140,7 +140,7 @@ const Settings = ({ config, onChange, fieldName }: ISettingsProps) => { : config.undoFn ? config.undoFn : get(config, "undo.script") - ? `const action : Action = async ({row,ref,db,storage,auth,actionParams,user}) => { + ? `const action : Action = async ({row,ref,db,storage,auth,actionParams,user,logging}) => { ${get(config, "undo.script")} }` : UNDO_ACTION_TEMPLATE; @@ -303,7 +303,9 @@ const Settings = ({ config, onChange, fieldName }: ISettingsProps) => { aria-label="Action will run" name="isActionScript" value={ - config.isActionScript !== false ? "actionScript" : "cloudFunction" + config.isActionScript !== false + ? "actionScript" + : "cloudFunction" } onChange={(e) => onChange("isActionScript")( @@ -559,45 +561,45 @@ const Settings = ({ config, onChange, fieldName }: ISettingsProps) => { title: "Customization", content: ( <> - - + + onChange("customName.enabled")(e.target.checked) + } + name="customName.enabled" + /> + } + label="Customize label for action" + style={{ marginLeft: -11 }} + /> + {config.customName?.enabled && ( + - onChange("customName.enabled")(e.target.checked) + onChange("customName.actionName")(e.target.value) } - name="customName.enabled" - /> - } - label="Customize label for action" - style={{ marginLeft: -11 }} - /> - {config.customName?.enabled && ( - - onChange("customName.actionName")(e.target.value) - } - label="Action name:" - className="labelHorizontal" - inputProps={{ style: { width: "10ch" } }} - > - )} - - onChange("customIcons.enabled")(e.target.checked) - } - name="customIcons.enabled" - /> - } - label="Customize button icons with emoji" - style={{ marginLeft: -11 }} - /> + label="Action name:" + className="labelHorizontal" + inputProps={{ style: { width: "10ch" } }} + > + )} + + onChange("customIcons.enabled")(e.target.checked) + } + name="customIcons.enabled" + /> + } + label="Customize button icons with emoji" + style={{ marginLeft: -11 }} + /> {config.customIcons?.enabled && ( diff --git a/src/components/fields/Action/action.d.ts b/src/components/fields/Action/action.d.ts index a4339978..933e7dbc 100644 --- a/src/components/fields/Action/action.d.ts +++ b/src/components/fields/Action/action.d.ts @@ -1,3 +1,5 @@ +import { RowyLogging } from "@src/components/fields/types"; + type ActionUser = { timestamp: Date; displayName: string; @@ -15,6 +17,7 @@ type ActionContext = { auth: firebaseauth.BaseAuth; actionParams: actionParams; user: ActionUser; + logging: RowyLogging; }; type ActionResult = { diff --git a/src/components/fields/Action/templates.ts b/src/components/fields/Action/templates.ts index 5701ef24..04b3ab23 100644 --- a/src/components/fields/Action/templates.ts +++ b/src/components/fields/Action/templates.ts @@ -1,4 +1,4 @@ -export const RUN_ACTION_TEMPLATE = `const action:Action = async ({row,ref,db,storage,auth,actionParams,user}) => { +export const RUN_ACTION_TEMPLATE = `const action:Action = async ({row,ref,db,storage,auth,actionParams,user,logging}) => { // Write your action code here // for example: // const authToken = await rowy.secrets.get("service") @@ -26,7 +26,7 @@ export const RUN_ACTION_TEMPLATE = `const action:Action = async ({row,ref,db,sto // checkout the documentation for more info: https://docs.rowy.io/field-types/action#script }`; -export const UNDO_ACTION_TEMPLATE = `const action : Action = async ({row,ref,db,storage,auth,actionParams,user}) => { +export const UNDO_ACTION_TEMPLATE = `const action : Action = async ({row,ref,db,storage,auth,actionParams,user,logging}) => { // Write your undo code here // for example: // const authToken = await rowy.secrets.get("service") diff --git a/src/components/fields/Derivative/derivative.d.ts b/src/components/fields/Derivative/derivative.d.ts index 9d01f97c..d210d497 100644 --- a/src/components/fields/Derivative/derivative.d.ts +++ b/src/components/fields/Derivative/derivative.d.ts @@ -1,3 +1,5 @@ +import { RowyLogging } from "@src/components/fields/types"; + type DerivativeContext = { row: Row; ref: FirebaseFirestore.DocumentReference; @@ -5,11 +7,7 @@ type DerivativeContext = { db: FirebaseFirestore.Firestore; auth: firebaseauth.BaseAuth; change: any; - logging: { - log: (payload: any) => void; - warn: (payload: any) => void; - error: (payload: any) => void; - }; + logging: RowyLogging; }; type Derivative = (context: DerivativeContext) => "PLACEHOLDER_OUTPUT_TYPE"; diff --git a/src/components/fields/types.ts b/src/components/fields/types.ts index 66890472..a0ee73d9 100644 --- a/src/components/fields/types.ts +++ b/src/components/fields/types.ts @@ -49,6 +49,7 @@ export interface IBasicCellProps { type: FieldType; name: string; } + export interface IHeavyCellProps extends IBasicCellProps, FormatterProps { @@ -61,6 +62,7 @@ export interface IHeavyCellProps export interface IPopoverInlineCellProps extends IHeavyCellProps { showPopoverCell: React.Dispatch>; } + export interface IPopoverCellProps extends IPopoverInlineCellProps { parentRef: PopoverProps["anchorEl"]; } @@ -110,5 +112,12 @@ export interface IFilterOperator { export interface IFilterCustomInputProps { onChange: (value: any) => void; operator: TableFilter["operator"]; + [key: string]: any; } + +export interface RowyLogging { + log: (payload: any) => void; + warn: (payload: any) => void; + error: (payload: any) => void; +} From 74852a8a3dc008f01cfa94ca23603c9b3ef9d542 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Wed, 23 Nov 2022 21:32:20 +0800 Subject: [PATCH 03/14] fix action/derivative type hint issue --- src/components/fields/Action/action.d.ts | 8 +++++--- src/components/fields/Derivative/derivative.d.ts | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/components/fields/Action/action.d.ts b/src/components/fields/Action/action.d.ts index 933e7dbc..33fc7489 100644 --- a/src/components/fields/Action/action.d.ts +++ b/src/components/fields/Action/action.d.ts @@ -1,5 +1,3 @@ -import { RowyLogging } from "@src/components/fields/types"; - type ActionUser = { timestamp: Date; displayName: string; @@ -17,7 +15,11 @@ type ActionContext = { auth: firebaseauth.BaseAuth; actionParams: actionParams; user: ActionUser; - logging: RowyLogging; + logging: { + log: (payload: any) => void; + warn: (payload: any) => void; + error: (payload: any) => void; + }; }; type ActionResult = { diff --git a/src/components/fields/Derivative/derivative.d.ts b/src/components/fields/Derivative/derivative.d.ts index d210d497..9d01f97c 100644 --- a/src/components/fields/Derivative/derivative.d.ts +++ b/src/components/fields/Derivative/derivative.d.ts @@ -1,5 +1,3 @@ -import { RowyLogging } from "@src/components/fields/types"; - type DerivativeContext = { row: Row; ref: FirebaseFirestore.DocumentReference; @@ -7,7 +5,11 @@ type DerivativeContext = { db: FirebaseFirestore.Firestore; auth: firebaseauth.BaseAuth; change: any; - logging: RowyLogging; + logging: { + log: (payload: any) => void; + warn: (payload: any) => void; + error: (payload: any) => void; + }; }; type Derivative = (context: DerivativeContext) => "PLACEHOLDER_OUTPUT_TYPE"; From cc2b86027d0cb413c257eb136d2fc40c22158a72 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Wed, 23 Nov 2022 22:08:35 +0800 Subject: [PATCH 04/14] enable connectors logging in code editor --- src/components/fields/Connector/connector.d.ts | 5 +++++ src/components/fields/Connector/utils.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/fields/Connector/connector.d.ts b/src/components/fields/Connector/connector.d.ts index d031d64b..d12041d4 100644 --- a/src/components/fields/Connector/connector.d.ts +++ b/src/components/fields/Connector/connector.d.ts @@ -15,6 +15,11 @@ type ConnectorContext = { auth: firebaseauth.BaseAuth; query: string; user: ConnectorUser; + logging: { + log: (payload: any) => void; + warn: (payload: any) => void; + error: (payload: any) => void; + }; }; type ConnectorResult = any[]; type Connector = ( diff --git a/src/components/fields/Connector/utils.ts b/src/components/fields/Connector/utils.ts index 17687fe7..88959895 100644 --- a/src/components/fields/Connector/utils.ts +++ b/src/components/fields/Connector/utils.ts @@ -11,7 +11,7 @@ export const replacer = (data: any) => (m: string, key: string) => { return get(data, objKey, defaultValue); }; -export const baseFunction = `const connectorFn: Connector = async ({query, row, user}) => { +export const baseFunction = `const connectorFn: Connector = async ({query, row, user, logging}) => { // TODO: Implement your service function here return []; };`; From 35a173fba0e29926a9cd247d032f3d6cf105135d Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Thu, 24 Nov 2022 06:25:23 +0800 Subject: [PATCH 05/14] enable webhooks logging in code editor --- .../WebhooksModal/Schemas/basic.tsx | 89 ++++++++++++------- .../WebhooksModal/Schemas/sendgrid.tsx | 4 +- .../WebhooksModal/Schemas/stripe.tsx | 4 +- .../WebhooksModal/Schemas/typeform.tsx | 4 +- .../WebhooksModal/Schemas/webform.tsx | 4 +- .../TableModals/WebhooksModal/utils.tsx | 40 +++++++-- .../TableModals/WebhooksModal/webhooks.d.ts | 10 +++ 7 files changed, 106 insertions(+), 49 deletions(-) diff --git a/src/components/TableModals/WebhooksModal/Schemas/basic.tsx b/src/components/TableModals/WebhooksModal/Schemas/basic.tsx index 7f9e4d11..54075d43 100644 --- a/src/components/TableModals/WebhooksModal/Schemas/basic.tsx +++ b/src/components/TableModals/WebhooksModal/Schemas/basic.tsx @@ -21,17 +21,41 @@ const requestType = [ export const parserExtraLibs = [ requestType, - `type Parser = (args:{req:WebHookRequest,db: FirebaseFirestore.Firestore,ref: FirebaseFirestore.CollectionReference,res:{ - send:(v:any)=>void - sendStatus:(status:number)=>void - }}) => Promise;`, + `type Parser = ( + args: { + req: WebHookRequest; + db: FirebaseFirestore.Firestore; + ref: FirebaseFirestore.CollectionReference; + res: { + send: (v:any)=>void; + sendStatus: (status:number)=>void + }; + logging: { + log: (payload: any) => void; + warn: (payload: any) => void; + error: (payload: any) => void; + }; + } + ) => Promise;`, ]; export const conditionExtraLibs = [ requestType, - `type Condition = (args:{req:WebHookRequest,db: FirebaseFirestore.Firestore,ref: FirebaseFirestore.CollectionReference,res:{ - send:(v:any)=>void - sendStatus:(status:number)=>void - }}) => Promise;`, + `type Condition = ( + args: { + req: WebHookRequest; + db: FirebaseFirestore.Firestore; + ref: FirebaseFirestore.CollectionReference; + res: { + send: (v:any)=>void; + sendStatus: (status:number)=>void; + }; + logging: { + log: (payload: any) => void; + warn: (payload: any) => void; + error: (payload: any) => void; + }; + } + ) => Promise;`, ]; const additionalVariables = [ @@ -48,30 +72,29 @@ export const webhookBasic = { extraLibs: parserExtraLibs, template: ( table: TableSettings - ) => `const basicParser: Parser = async({req, db,ref}) => { - // request is the request object from the webhook - // db is the database object - // ref is the reference to collection of the table - // the returned object will be added as a new row to the table - // eg: adding the webhook body as row - const {body} = req; - ${ - table.audit !== false - ? ` - // auditField - const ${ - table.auditFieldCreatedBy ?? "_createdBy" - } = await rowy.metadata.serviceAccountUser() - return { - ...body, - ${table.auditFieldCreatedBy ?? "_createdBy"} - } - ` - : ` - return body; - ` - } - + ) => `const basicParser: Parser = async({req, db, ref, logging}) => { + // request is the request object from the webhook + // db is the database object + // ref is the reference to collection of the table + // the returned object will be added as a new row to the table + // eg: adding the webhook body as row + const {body} = req; + ${ + table.audit !== false + ? ` + // auditField + const ${ + table.auditFieldCreatedBy ?? "_createdBy" + } = await rowy.metadata.serviceAccountUser() + return { + ...body, + ${table.auditFieldCreatedBy ?? "_createdBy"} + } + ` + : ` + return body; + ` + } }`, }, condition: { @@ -79,7 +102,7 @@ export const webhookBasic = { extraLibs: conditionExtraLibs, template: ( table: TableSettings - ) => `const condition: Condition = async({ref,req,db}) => { + ) => `const condition: Condition = async({ref, req, db, logging}) => { // feel free to add your own code logic here return true; }`, diff --git a/src/components/TableModals/WebhooksModal/Schemas/sendgrid.tsx b/src/components/TableModals/WebhooksModal/Schemas/sendgrid.tsx index b557dd78..b251697f 100644 --- a/src/components/TableModals/WebhooksModal/Schemas/sendgrid.tsx +++ b/src/components/TableModals/WebhooksModal/Schemas/sendgrid.tsx @@ -13,7 +13,7 @@ export const webhookSendgrid = { extraLibs: null, template: ( table: TableSettings - ) => `const sendgridParser: Parser = async ({ req, db, ref }) => { + ) => `const sendgridParser: Parser = async ({ req, db, ref, logging }) => { const { body } = req const eventHandler = async (sgEvent) => { // Event handlers can be modiefed to preform different actions based on the sendgrid event @@ -35,7 +35,7 @@ export const webhookSendgrid = { extraLibs: null, template: ( table: TableSettings - ) => `const condition: Condition = async({ref,req,db}) => { + ) => `const condition: Condition = async({ref, req, db, logging}) => { // feel free to add your own code logic here return true; }`, diff --git a/src/components/TableModals/WebhooksModal/Schemas/stripe.tsx b/src/components/TableModals/WebhooksModal/Schemas/stripe.tsx index 31eb4aff..acfb2dfe 100644 --- a/src/components/TableModals/WebhooksModal/Schemas/stripe.tsx +++ b/src/components/TableModals/WebhooksModal/Schemas/stripe.tsx @@ -17,7 +17,7 @@ export const webhookStripe = { extraLibs: null, template: ( table: TableSettings - ) => `const sendgridParser: Parser = async ({ req, db, ref }) => { + ) => `const sendgridParser: Parser = async ({ req, db, ref, logging }) => { const event = req.body switch (event.type) { case "payment_intent.succeeded": @@ -34,7 +34,7 @@ export const webhookStripe = { extraLibs: null, template: ( table: TableSettings - ) => `const condition: Condition = async({ref,req,db}) => { + ) => `const condition: Condition = async({ref, req, db, logging}) => { // feel free to add your own code logic here return true; }`, diff --git a/src/components/TableModals/WebhooksModal/Schemas/typeform.tsx b/src/components/TableModals/WebhooksModal/Schemas/typeform.tsx index 5fd4ce7d..9c509efd 100644 --- a/src/components/TableModals/WebhooksModal/Schemas/typeform.tsx +++ b/src/components/TableModals/WebhooksModal/Schemas/typeform.tsx @@ -13,7 +13,7 @@ export const webhookTypeform = { extraLibs: null, template: ( table: TableSettings - ) => `const typeformParser: Parser = async({req, db,ref}) =>{ + ) => `const typeformParser: Parser = async({req, db, ref, logging}) =>{ // this reduces the form submission into a single object of key value pairs // eg: {name: "John", age: 20} // ⚠️ ensure that you have assigned ref values of the fields @@ -73,7 +73,7 @@ export const webhookTypeform = { extraLibs: null, template: ( table: TableSettings - ) => `const condition: Condition = async({ref,req,db}) => { + ) => `const condition: Condition = async({ref, req, db, logging}) => { // feel free to add your own code logic here return true; }`, diff --git a/src/components/TableModals/WebhooksModal/Schemas/webform.tsx b/src/components/TableModals/WebhooksModal/Schemas/webform.tsx index bf5e8cda..7bed061d 100644 --- a/src/components/TableModals/WebhooksModal/Schemas/webform.tsx +++ b/src/components/TableModals/WebhooksModal/Schemas/webform.tsx @@ -14,7 +14,7 @@ export const webhook = { extraLibs: null, template: ( table: TableSettings - ) => `const formParser: Parser = async({req, db,ref}) => { + ) => `const formParser: Parser = async({req, db, ref, logging}) => { // request is the request object from the webhook // db is the database object // ref is the reference to collection of the table @@ -45,7 +45,7 @@ export const webhook = { extraLibs: null, template: ( table: TableSettings - ) => `const condition: Condition = async({ref,req,db}) => { + ) => `const condition: Condition = async({ref, req, db, logging}) => { // feel free to add your own code logic here return true; }`, diff --git a/src/components/TableModals/WebhooksModal/utils.tsx b/src/components/TableModals/WebhooksModal/utils.tsx index 7c338bab..b1ba8601 100644 --- a/src/components/TableModals/WebhooksModal/utils.tsx +++ b/src/components/TableModals/WebhooksModal/utils.tsx @@ -26,17 +26,41 @@ const requestType = [ export const parserExtraLibs = [ requestType, - `type Parser = (args:{req:WebHookRequest,db: FirebaseFirestore.Firestore,ref: FirebaseFirestore.CollectionReference,res:{ - send:(v:any)=>void - sendStatus:(status:number)=>void - }}) => Promise;`, + `type Parser = ( + args: { + req: WebHookRequest; + db: FirebaseFirestore.Firestore; + ref: FirebaseFirestore.CollectionReference; + res: { + send: (v:any)=>void; + sendStatus: (status:number)=>void + }; + logging: { + log: (payload: any) => void; + warn: (payload: any) => void; + error: (payload: any) => void; + }; + } + ) => Promise;`, ]; export const conditionExtraLibs = [ requestType, - `type Condition = (args:{req:WebHookRequest,db: FirebaseFirestore.Firestore,ref: FirebaseFirestore.CollectionReference,res:{ - send:(v:any)=>void - sendStatus:(status:number)=>void - }}) => Promise;`, + `type Condition = ( + args: { + req:WebHookRequest, + db: FirebaseFirestore.Firestore, + ref: FirebaseFirestore.CollectionReference, + res: { + send: (v:any)=>void + sendStatus: (status:number)=>void + }; + logging: { + log: (payload: any) => void; + warn: (payload: any) => void; + error: (payload: any) => void; + }; + } + ) => Promise;`, ]; const additionalVariables = [ diff --git a/src/components/TableModals/WebhooksModal/webhooks.d.ts b/src/components/TableModals/WebhooksModal/webhooks.d.ts index 4a8715f8..fa98341f 100644 --- a/src/components/TableModals/WebhooksModal/webhooks.d.ts +++ b/src/components/TableModals/WebhooksModal/webhooks.d.ts @@ -3,10 +3,20 @@ type Condition = (args: { db: FirebaseFirestore.Firestore; ref: FirebaseFirestore.CollectionReference; res: Response; + logging: { + log: (payload: any) => void; + warn: (payload: any) => void; + error: (payload: any) => void; + }; }) => Promise; type Parser = (args: { req: WebHookRequest; db: FirebaseFirestore.Firestore; ref: FirebaseFirestore.CollectionReference; + logging: { + log: (payload: any) => void; + warn: (payload: any) => void; + error: (payload: any) => void; + }; }) => Promise; From 2c206d2e721da9a603fdfb9171b2bf2933f10d84 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Sun, 27 Nov 2022 20:45:12 +0800 Subject: [PATCH 06/14] enable logging in extensions code editor --- src/components/CodeEditor/extensions.d.ts | 5 ++++ .../TableModals/ExtensionsModal/utils.ts | 25 ++++++++++--------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/components/CodeEditor/extensions.d.ts b/src/components/CodeEditor/extensions.d.ts index dd592d05..3da39ae9 100644 --- a/src/components/CodeEditor/extensions.d.ts +++ b/src/components/CodeEditor/extensions.d.ts @@ -26,6 +26,11 @@ type ExtensionContext = { extensionBody: any; }; RULES_UTILS: any; + logging: { + log: (payload: any) => void; + warn: (payload: any) => void; + error: (payload: any) => void; + }; }; // extension body definition diff --git a/src/components/TableModals/ExtensionsModal/utils.ts b/src/components/TableModals/ExtensionsModal/utils.ts index 28d24fda..48de1a92 100644 --- a/src/components/TableModals/ExtensionsModal/utils.ts +++ b/src/components/TableModals/ExtensionsModal/utils.ts @@ -61,7 +61,7 @@ export interface IRuntimeOptions { export const triggerTypes: ExtensionTrigger[] = ["create", "update", "delete"]; const extensionBodyTemplate = { - task: `const extensionBody: TaskBody = async({row, db, change, ref}) => { + task: `const extensionBody: TaskBody = async({row, db, change, ref, logging}) => { // task extensions are very flexible you can do anything from updating other documents in your database, to making an api request to 3rd party service. // example: @@ -87,7 +87,7 @@ const extensionBodyTemplate = { }) */ }`, - docSync: `const extensionBody: DocSyncBody = async({row, db, change, ref}) => { + docSync: `const extensionBody: DocSyncBody = async({row, db, change, ref, logging}) => { // feel free to add your own code logic here return ({ @@ -96,7 +96,7 @@ const extensionBodyTemplate = { targetPath: "", // fill in the path here }) }`, - historySnapshot: `const extensionBody: HistorySnapshotBody = async({row, db, change, ref}) => { + historySnapshot: `const extensionBody: HistorySnapshotBody = async({row, db, change, ref, logging}) => { // feel free to add your own code logic here return ({ @@ -104,7 +104,7 @@ const extensionBodyTemplate = { collectionId: "historySnapshots", // optionally change the sub-collection id of where the history snapshots are stored }) }`, - algoliaIndex: `const extensionBody: AlgoliaIndexBody = async({row, db, change, ref}) => { + algoliaIndex: `const extensionBody: AlgoliaIndexBody = async({row, db, change, ref, logging}) => { // feel free to add your own code logic here return ({ @@ -114,7 +114,7 @@ const extensionBodyTemplate = { objectID: ref.id, // algolia object ID, ref.id is one possible choice }) }`, - meiliIndex: `const extensionBody: MeiliIndexBody = async({row, db, change, ref}) => { + meiliIndex: `const extensionBody: MeiliIndexBody = async({row, db, change, ref, logging}) => { // feel free to add your own code logic here return({ @@ -124,7 +124,7 @@ const extensionBodyTemplate = { objectID: ref.id, // algolia object ID, ref.id is one possible choice }) }`, - bigqueryIndex: `const extensionBody: BigqueryIndexBody = async({row, db, change, ref}) => { + bigqueryIndex: `const extensionBody: BigqueryIndexBody = async({row, db, change, ref, logging}) => { // feel free to add your own code logic here return ({ @@ -134,7 +134,7 @@ const extensionBodyTemplate = { objectID: ref.id, // algolia object ID, ref.id is one possible choice }) }`, - slackMessage: `const extensionBody: SlackMessageBody = async({row, db, change, ref}) => { + slackMessage: `const extensionBody: SlackMessageBody = async({row, db, change, ref, logging}) => { // feel free to add your own code logic here return ({ @@ -144,7 +144,7 @@ const extensionBodyTemplate = { attachments: [], // the attachments parameter to pass in to slack api }) }`, - sendgridEmail: `const extensionBody: SendgridEmailBody = async({row, db, change, ref}) => { + sendgridEmail: `const extensionBody: SendgridEmailBody = async({row, db, change, ref, logging}) => { // feel free to add your own code logic here return ({ @@ -164,7 +164,7 @@ const extensionBodyTemplate = { }, }) }`, - apiCall: `const extensionBody: ApiCallBody = async({row, db, change, ref}) => { + apiCall: `const extensionBody: ApiCallBody = async({row, db, change, ref, logging}) => { // feel free to add your own code logic here return ({ @@ -174,7 +174,7 @@ const extensionBodyTemplate = { callback: ()=>{}, }) }`, - twilioMessage: `const extensionBody: TwilioMessageBody = async({row, db, change, ref}) => { + twilioMessage: `const extensionBody: TwilioMessageBody = async({row, db, change, ref, logging}) => { /** * * Setup twilio secret key: https://docs.rowy.io/extensions/twilio-message#secret-manager-setup @@ -190,7 +190,7 @@ const extensionBodyTemplate = { body: "Hi there!" // message text }) }`, - pushNotification: `const extensionBody: PushNotificationBody = async({row, db, change, ref}) => { + pushNotification: `const extensionBody: PushNotificationBody = async({row, db, change, ref, logging}) => { // you can FCM token from the row or from the user document in the database // const FCMtoken = row.FCMtoken // or push through topic @@ -238,13 +238,14 @@ export function emptyExtensionObject( extensionBody: extensionBodyTemplate[type] ?? extensionBodyTemplate["task"], requiredFields: [], trackedFields: [], - conditions: `const condition: Condition = async({row, change}) => { + conditions: `const condition: Condition = async({row, change, logging}) => { // feel free to add your own code logic here return true; }`, lastEditor: user, }; } + export function sparkToExtensionObjects( sparkConfig: string, user: IExtensionEditor From 065484aeb21384bb6e0f15fa02a5240988d23f26 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Fri, 9 Dec 2022 03:45:58 +0800 Subject: [PATCH 07/14] add rowy loggin tab --- src/atoms/tableScope/ui.ts | 2 +- .../ColumnModals/ColumnConfigModal/DefaultValueInput.tsx | 4 ++-- .../ColumnModals/ColumnConfigModal/defaultValue.d.ts | 5 +++++ src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx | 2 ++ src/components/TableModals/CloudLogsModal/utils.ts | 3 +++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/atoms/tableScope/ui.ts b/src/atoms/tableScope/ui.ts index 3d11a081..47bdd828 100644 --- a/src/atoms/tableScope/ui.ts +++ b/src/atoms/tableScope/ui.ts @@ -142,7 +142,7 @@ export const selectedCellAtom = atom(null); export const contextMenuTargetAtom = atom(null); export type CloudLogFilters = { - type: "webhook" | "functions" | "audit" | "build"; + type: "rowy" | "webhook" | "functions" | "audit" | "build"; timeRange: | { type: "seconds" | "minutes" | "hours" | "days"; value: number } | { type: "range"; start: Date; end: Date }; diff --git a/src/components/ColumnModals/ColumnConfigModal/DefaultValueInput.tsx b/src/components/ColumnModals/ColumnConfigModal/DefaultValueInput.tsx index 5213eb8a..3cc78e2a 100644 --- a/src/components/ColumnModals/ColumnConfigModal/DefaultValueInput.tsx +++ b/src/components/ColumnModals/ColumnConfigModal/DefaultValueInput.tsx @@ -52,11 +52,11 @@ function CodeEditor({ type, column, handleChange }: ICodeEditorProps) { } else if (column.config?.defaultValue?.dynamicValueFn) { dynamicValueFn = column.config?.defaultValue?.dynamicValueFn; } else if (column.config?.defaultValue?.script) { - dynamicValueFn = `const dynamicValueFn : DefaultValue = async ({row,ref,db,storage,auth})=>{ + dynamicValueFn = `const dynamicValueFn : DefaultValue = async ({row,ref,db,storage,auth,logging})=>{ ${column.config?.defaultValue.script} }`; } else { - dynamicValueFn = `const dynamicValueFn : DefaultValue = async ({row,ref,db,storage,auth})=>{ + dynamicValueFn = `const dynamicValueFn : DefaultValue = async ({row,ref,db,storage,auth,logging})=>{ // Write your default value code here // for example: // generate random hex color diff --git a/src/components/ColumnModals/ColumnConfigModal/defaultValue.d.ts b/src/components/ColumnModals/ColumnConfigModal/defaultValue.d.ts index 0e50bb2d..e3b90e13 100644 --- a/src/components/ColumnModals/ColumnConfigModal/defaultValue.d.ts +++ b/src/components/ColumnModals/ColumnConfigModal/defaultValue.d.ts @@ -4,5 +4,10 @@ type DefaultValueContext = { storage: firebasestorage.Storage; db: FirebaseFirestore.Firestore; auth: firebaseauth.BaseAuth; + logging: { + log: (payload: any) => void; + warn: (payload: any) => void; + error: (payload: any) => void; + }; }; type DefaultValue = (context: DefaultValueContext) => "PLACEHOLDER_OUTPUT_TYPE"; diff --git a/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx b/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx index e69acc44..217b5929 100644 --- a/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx +++ b/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx @@ -118,6 +118,7 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { } aria-label="Filter by log type" > + Rowy Logging Webhooks Functions Audit @@ -139,6 +140,7 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { )} + {cloudLogFilters.type === "rowy" && <>} {cloudLogFilters.type === "webhook" && ( Date: Sat, 10 Dec 2022 17:19:53 +0800 Subject: [PATCH 08/14] rowy logging ui implementation --- src/atoms/tableScope/ui.ts | 14 +- src/components/ColumnMenu/ColumnMenu.tsx | 18 + .../CloudLogsModal/CloudLogItem.tsx | 40 +- .../CloudLogsModal/CloudLogList.tsx | 7 + .../CloudLogsModal/CloudLogSeverityIcon.tsx | 6 + .../CloudLogsModal/CloudLogsModal.tsx | 477 +++++++++++++----- .../TableModals/CloudLogsModal/utils.ts | 58 ++- .../ExtensionsModal/ExtensionList.tsx | 26 + .../TableModals/WebhooksModal/WebhookList.tsx | 3 +- 9 files changed, 503 insertions(+), 146 deletions(-) diff --git a/src/atoms/tableScope/ui.ts b/src/atoms/tableScope/ui.ts index 47bdd828..44afee10 100644 --- a/src/atoms/tableScope/ui.ts +++ b/src/atoms/tableScope/ui.ts @@ -142,14 +142,26 @@ export const selectedCellAtom = atom(null); export const contextMenuTargetAtom = atom(null); export type CloudLogFilters = { - type: "rowy" | "webhook" | "functions" | "audit" | "build"; + type: "rowy" | "audit" | "build"; timeRange: | { type: "seconds" | "minutes" | "hours" | "days"; value: number } | { type: "range"; start: Date; end: Date }; severity?: Array; webhook?: string[]; + extension?: string[]; + column?: string[]; auditRowId?: string; buildLogExpanded?: number; + functionType?: ( + | "connector" + | "derivative-script" + | "action" + | "derivative-function" + | "extension" + | "defaultValue" + | "hooks" + )[]; + loggingSource?: ("backend-scripts" | "backend-function" | "hooks")[]; }; /** Store cloud log modal filters in URL */ export const cloudLogFiltersAtom = atomWithHash( diff --git a/src/components/ColumnMenu/ColumnMenu.tsx b/src/components/ColumnMenu/ColumnMenu.tsx index cf025217..a5f76a67 100644 --- a/src/components/ColumnMenu/ColumnMenu.tsx +++ b/src/components/ColumnMenu/ColumnMenu.tsx @@ -20,6 +20,7 @@ import { ColumnPlusBefore as ColumnPlusBeforeIcon, ColumnPlusAfter as ColumnPlusAfterIcon, ColumnRemove as ColumnRemoveIcon, + CloudLogs as LogsIcon, } from "@src/assets/icons"; import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward"; import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward"; @@ -51,6 +52,8 @@ import { tableFiltersPopoverAtom, tableNextPageAtom, tableSchemaAtom, + cloudLogFiltersAtom, + tableModalAtom, } from "@src/atoms/tableScope"; import { FieldType } from "@src/constants/fields"; import { getFieldProp } from "@src/components/fields"; @@ -107,6 +110,8 @@ export default function ColumnMenu({ ); const [tableNextPage] = useAtom(tableNextPageAtom, tableScope); const [tableSchema] = useAtom(tableSchemaAtom, tableScope); + const setModal = useSetAtom(tableModalAtom, tableScope); + const setCloudLogFilters = useSetAtom(cloudLogFiltersAtom, tableScope); const snackLogContext = useSnackLogContext(); const [altPress] = useAtom(altPressAtom, projectScope); @@ -383,6 +388,19 @@ export default function ColumnMenu({ confirm: "Evaluate", }), }, + { + key: "logs", + label: altPress ? "Logs" : "Logs…", + icon: , + onClick: () => { + setModal("cloudLogs"); + setCloudLogFilters({ + type: "rowy", + timeRange: { type: "days", value: 7 }, + column: [column.key], + }); + }, + }, ]; const columnActions: IMenuContentsProps["menuItems"] = [ diff --git a/src/components/TableModals/CloudLogsModal/CloudLogItem.tsx b/src/components/TableModals/CloudLogsModal/CloudLogItem.tsx index f82a75f1..9e0887f3 100644 --- a/src/components/TableModals/CloudLogsModal/CloudLogItem.tsx +++ b/src/components/TableModals/CloudLogsModal/CloudLogItem.tsx @@ -187,22 +187,32 @@ export default function CloudLogItem({ )} - {data.payload === "textPayload" && data.textPayload} - {get(data, "httpRequest.requestUrl")?.split(".run.app").pop()} - {data.payload === "jsonPayload" && ( - - {data.jsonPayload.error}{" "} - + {data.logName.endsWith("rowy-logging") && data.jsonPayload.payload ? ( + <> + {typeof data.jsonPayload.payload === "string" + ? data.jsonPayload.payload + : JSON.stringify(data.jsonPayload.payload)} + + ) : ( + <> + {data.payload === "textPayload" && data.textPayload} + {get(data, "httpRequest.requestUrl")?.split(".run.app").pop()} + {data.payload === "jsonPayload" && ( + + {data.jsonPayload.error}{" "} + + )} + {data.payload === "jsonPayload" && + stringify(data.jsonPayload.body ?? data.jsonPayload, { + space: 2, + })} + )} - {data.payload === "jsonPayload" && - stringify(data.jsonPayload.body ?? data.jsonPayload, { - space: 2, - })} diff --git a/src/components/TableModals/CloudLogsModal/CloudLogList.tsx b/src/components/TableModals/CloudLogsModal/CloudLogList.tsx index 5e5382ee..93093d38 100644 --- a/src/components/TableModals/CloudLogsModal/CloudLogList.tsx +++ b/src/components/TableModals/CloudLogsModal/CloudLogList.tsx @@ -70,6 +70,13 @@ export default function CloudLogList({ items, ...props }: ICloudLogListProps) { "jsonPayload.rowyUser.displayName", // Webhook event "jsonPayload.params.endpoint", + // Rowy Logging + "jsonPayload.functionType", + "jsonPayload.loggingSource", + "jsonPayload.extensionName", + "jsonPayload.extensionType", + "jsonPayload.webhookName", + "jsonPayload.fieldName", ]} /> diff --git a/src/components/TableModals/CloudLogsModal/CloudLogSeverityIcon.tsx b/src/components/TableModals/CloudLogsModal/CloudLogSeverityIcon.tsx index 0cf0dc6e..f8413f65 100644 --- a/src/components/TableModals/CloudLogsModal/CloudLogSeverityIcon.tsx +++ b/src/components/TableModals/CloudLogsModal/CloudLogSeverityIcon.tsx @@ -22,6 +22,12 @@ export const SEVERITY_LEVELS = { EMERGENCY: "One or more systems are unusable.", }; +export const SEVERITY_LEVELS_ROWY = { + DEFAULT: "The log entry has no assigned severity level.", + WARNING: "Warning events might cause problems.", + ERROR: "Error events are likely to cause problems.", +}; + export interface ICloudLogSeverityIconProps extends SvgIconProps { severity: keyof typeof SEVERITY_LEVELS; } diff --git a/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx b/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx index 217b5929..95af37f1 100644 --- a/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx +++ b/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx @@ -1,6 +1,6 @@ import useSWR from "swr"; import { useAtom } from "jotai"; -import { startCase } from "lodash-es"; +import { startCase, upperCase } from "lodash-es"; import { ITableModalProps } from "@src/components/TableModals"; import { @@ -12,6 +12,7 @@ import { TextField, InputAdornment, Button, + Box, } from "@mui/material"; import RefreshIcon from "@mui/icons-material/Refresh"; import { CloudLogs as LogsIcon } from "@src/assets/icons"; @@ -23,7 +24,10 @@ import TimeRangeSelect from "./TimeRangeSelect"; import CloudLogList from "./CloudLogList"; import BuildLogs from "./BuildLogs"; import EmptyState from "@src/components/EmptyState"; -import CloudLogSeverityIcon, { SEVERITY_LEVELS } from "./CloudLogSeverityIcon"; +import CloudLogSeverityIcon, { + SEVERITY_LEVELS, + SEVERITY_LEVELS_ROWY, +} from "./CloudLogSeverityIcon"; import { projectScope, @@ -119,8 +123,6 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { aria-label="Filter by log type" > Rowy Logging - Webhooks - Functions Audit Build @@ -141,36 +143,6 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { )} {cloudLogFilters.type === "rowy" && <>} - {cloudLogFilters.type === "webhook" && ( - ({ - label: x.name, - value: x.endpoint, - })) - : [] - } - value={cloudLogFilters.webhook ?? []} - onChange={(v) => - setCloudLogFilters((prev) => ({ ...prev, webhook: v })) - } - TextFieldProps={{ - id: "webhook", - className: "labelHorizontal", - sx: { "& .MuiInputBase-root": { width: 180 } }, - fullWidth: false, - }} - itemRenderer={(option) => ( - <> - {option.label} {option.value} - - )} - /> - )} {cloudLogFilters.type === "audit" && ( )} - {/* Spacer */}
{cloudLogFilters.type !== "build" && ( @@ -220,10 +191,311 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { )} + {cloudLogFilters.type !== "rowy" && ( + + setCloudLogFilters((prev) => ({ ...prev, severity })) + } + TextFieldProps={{ + style: { width: 130 }, + placeholder: "Severity", + SelectProps: { + renderValue: () => { + if ( + !Array.isArray(cloudLogFilters.severity) || + cloudLogFilters.severity.length === 0 + ) + return `Severity`; + + if (cloudLogFilters.severity.length === 1) + return ( + <> + Severity{" "} + + + ); + + return `Severity (${cloudLogFilters.severity.length})`; + }, + }, + }} + itemRenderer={(option) => ( + <> + + {startCase(option.value.toLowerCase())} + + )} + /> + )} + + setCloudLogFilters((c) => ({ ...c, timeRange: value })) + } + /> + mutate()} + title="Refresh" + icon={} + disabled={isValidating} + /> + + )} + + + {isValidating && ( + + )} + + } + > + {cloudLogFilters.type === "build" ? ( + + ) : ( + + + {cloudLogFilters.type === "rowy" ? ( + + + { + setCloudLogFilters((prev) => ({ + ...prev, + functionType: v, + })); + }} + TextFieldProps={{ + id: "functionType", + className: "labelHorizontal", + sx: { "& .MuiInputBase-root": { width: 200 } }, + fullWidth: false, + SelectProps: { + renderValue: () => { + if (cloudLogFilters?.functionType?.length === 1) { + return `Type (${cloudLogFilters.functionType[0]})`; + } else if (cloudLogFilters?.functionType?.length) { + return `Type (${cloudLogFilters.functionType.length})`; + } else { + return `Type`; + } + }, + }, + }} + itemRenderer={(option) => <>{upperCase(option.value)}} + /> + { + setCloudLogFilters((prev) => ({ + ...prev, + loggingSource: v, + })); + }} + TextFieldProps={{ + id: "loggingSource", + className: "labelHorizontal", + sx: { "& .MuiInputBase-root": { width: 200 } }, + fullWidth: false, + SelectProps: { + renderValue: () => { + if (cloudLogFilters?.loggingSource?.length === 1) { + return `Source (${cloudLogFilters.loggingSource[0]})`; + } else if (cloudLogFilters?.loggingSource?.length) { + return `Source (${cloudLogFilters.loggingSource.length})`; + } else { + return `Source`; + } + }, + }, + }} + itemRenderer={(option) => <>{upperCase(option.value)}} + /> + ({ + label: x.name, + value: x.endpoint, + })) + : [] + } + value={cloudLogFilters.webhook ?? []} + onChange={(v) => + setCloudLogFilters((prev) => ({ ...prev, webhook: v })) + } + TextFieldProps={{ + id: "webhook", + className: "labelHorizontal", + sx: { "& .MuiInputBase-root": { width: 180 } }, + fullWidth: false, + SelectProps: { + renderValue: () => { + if (cloudLogFilters?.webhook?.length) { + return `Webhook (${cloudLogFilters.webhook.length})`; + } else { + return `Webhook`; + } + }, + }, + }} + itemRenderer={(option) => ( + <> + {option.label} {option.value} + + )} + /> + ({ + label: x.name, + value: x.name, + type: x.type, + })) + : [] + } + value={cloudLogFilters.extension ?? []} + onChange={(v) => + setCloudLogFilters((prev) => ({ ...prev, extension: v })) + } + TextFieldProps={{ + id: "extension", + className: "labelHorizontal", + sx: { "& .MuiInputBase-root": { width: 180 } }, + fullWidth: false, + placeholder: "Extension", + SelectProps: { + renderValue: () => { + if (cloudLogFilters?.extension?.length === 1) { + return `Extension (${cloudLogFilters.extension[0]})`; + } else if (cloudLogFilters?.extension?.length) { + return `Extension (${cloudLogFilters.extension.length})`; + } else { + return `Extension`; + } + }, + }, + }} + itemRenderer={(option) => ( + <> + {option.label} {option.type} + + )} + /> + ({ + label: config.name, + value: key, + type: config.type, + }) + )} + value={cloudLogFilters.column ?? []} + onChange={(v) => + setCloudLogFilters((prev) => ({ ...prev, column: v })) + } + TextFieldProps={{ + id: "column", + className: "labelHorizontal", + sx: { "& .MuiInputBase-root": { width: 200 } }, + fullWidth: false, + placeholder: "Column", + SelectProps: { + renderValue: () => { + if (cloudLogFilters?.column?.length === 1) { + return `Column (${cloudLogFilters.column[0]})`; + } else if (cloudLogFilters?.column?.length) { + return `Column (${cloudLogFilters.column.length})`; + } else { + return `Column`; + } + }, + }, + }} + itemRenderer={(option) => ( + <> + {option.label} {option.value}  + {option.type} + + )} + /> setCloudLogFilters((prev) => ({ ...prev, severity })) @@ -264,86 +536,61 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { )} /> - - setCloudLogFilters((c) => ({ ...c, timeRange: value })) - } - /> - mutate()} - title="Refresh" - icon={} - disabled={isValidating} - /> - + + ) : null} + + + {Array.isArray(data) && data.length > 0 ? ( + + + {cloudLogFilters.timeRange.type !== "range" && ( + + )} + + ) : isValidating ? ( + + ) : ( + )} - - - {isValidating && ( - - )} - - {/* {logQueryUrl} */} - - } - > - {cloudLogFilters.type === "build" ? ( - - ) : Array.isArray(data) && data.length > 0 ? ( - <> - - {cloudLogFilters.timeRange.type !== "range" && ( - - )} - - ) : isValidating ? ( - - ) : ( - + + )} ); diff --git a/src/components/TableModals/CloudLogsModal/utils.ts b/src/components/TableModals/CloudLogsModal/utils.ts index 3c7fddb0..306c4794 100644 --- a/src/components/TableModals/CloudLogsModal/utils.ts +++ b/src/components/TableModals/CloudLogsModal/utils.ts @@ -15,21 +15,55 @@ export const cloudLogFetcher = ( switch (cloudLogFilters.type) { case "rowy": logQuery.push(`logName = "projects/${projectId}/logs/rowy-logging"`); - break; - case "webhook": - logQuery.push( - `logName = "projects/${projectId}/logs/rowy-webhook-events"` - ); - logQuery.push(`jsonPayload.url : "${tablePath}"`); - if ( - Array.isArray(cloudLogFilters.webhook) && - cloudLogFilters.webhook.length > 0 - ) + if (cloudLogFilters?.functionType?.length) + logQuery.push( + cloudLogFilters.functionType + .map((functionType) => { + return `jsonPayload.functionType = "${functionType}"`; + }) + .join(encodeURIComponent(" OR ")) + ); + if (cloudLogFilters?.loggingSource?.length) { + logQuery.push( + cloudLogFilters.loggingSource + .map((loggingSource) => { + return `jsonPayload.loggingSource = "${loggingSource}"`; + }) + .join(encodeURIComponent(" OR ")) + ); + } else { + // mandatory filter to remove unwanted gcp diagnostic logs + logQuery.push( + ["backend-scripts", "backend-function", "hooks"] + .map((loggingSource) => { + return `jsonPayload.loggingSource = "${loggingSource}"`; + }) + .join(encodeURIComponent(" OR ")) + ); + } + if (cloudLogFilters?.webhook?.length) { logQuery.push( cloudLogFilters.webhook .map((id) => `jsonPayload.url : "${id}"`) .join(encodeURIComponent(" OR ")) ); + } + if (cloudLogFilters?.extension?.length) + logQuery.push( + cloudLogFilters.extension + .map((extensionName) => { + return `jsonPayload.extensionName = "${extensionName}"`; + }) + .join(encodeURIComponent(" OR ")) + ); + if (cloudLogFilters?.column?.length) + logQuery.push( + cloudLogFilters.column + .map((column) => { + return `jsonPayload.fieldName = "${column}"`; + }) + .join(encodeURIComponent(" OR ")) + ); break; case "audit": @@ -41,10 +75,6 @@ export const cloudLogFetcher = ( ); break; - case "functions": - logQuery.push(`resource.labels.function_name = "R-${tablePath}"`); - break; - default: break; } diff --git a/src/components/TableModals/ExtensionsModal/ExtensionList.tsx b/src/components/TableModals/ExtensionsModal/ExtensionList.tsx index dbd63a9e..7ed8e6c6 100644 --- a/src/components/TableModals/ExtensionsModal/ExtensionList.tsx +++ b/src/components/TableModals/ExtensionsModal/ExtensionList.tsx @@ -14,6 +14,7 @@ import { import { Extension as ExtensionIcon, Copy as DuplicateIcon, + CloudLogs as LogsIcon, } from "@src/assets/icons"; import EditIcon from "@mui/icons-material/EditOutlined"; import DeleteIcon from "@mui/icons-material/DeleteOutlined"; @@ -21,6 +22,12 @@ import DeleteIcon from "@mui/icons-material/DeleteOutlined"; import EmptyState from "@src/components/EmptyState"; import { extensionNames, IExtension } from "./utils"; import { DATE_TIME_FORMAT } from "@src/constants/dates"; +import { useSetAtom } from "jotai"; +import { + cloudLogFiltersAtom, + tableModalAtom, + tableScope, +} from "@src/atoms/tableScope"; export interface IExtensionListProps { extensions: IExtension[]; @@ -37,6 +44,9 @@ export default function ExtensionList({ handleEdit, handleDelete, }: IExtensionListProps) { + const setModal = useSetAtom(tableModalAtom, tableScope); + const setCloudLogFilters = useSetAtom(cloudLogFiltersAtom, tableScope); + if (extensions.length === 0) return ( + + { + setModal("cloudLogs"); + setCloudLogFilters({ + type: "rowy", + functionType: ["extension"], + timeRange: { type: "days", value: 7 }, + extension: [extensionObject.name], + }); + }} + > + + + { setModal("cloudLogs"); setCloudLogFilters({ - type: "webhook", + type: "rowy", + functionType: ["hooks"], timeRange: { type: "days", value: 7 }, webhook: [webhook.endpoint], }); From 072686bb66f3fb1e7cd9cd70b08555b862e1e175 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Wed, 28 Dec 2022 17:01:48 +0930 Subject: [PATCH 09/14] expand rowy logging into tabs: extension, webhook, column(derivative/action/default value/connector) --- src/atoms/tableScope/ui.ts | 2 +- src/components/ColumnMenu/ColumnMenu.tsx | 45 +- .../CloudLogsModal/CloudLogsModal.tsx | 590 ++++++++---------- .../CloudLogsModal/TimeRangeSelect.tsx | 4 +- .../TableModals/CloudLogsModal/utils.ts | 83 +-- .../ExtensionsModal/ExtensionList.tsx | 3 +- .../TableModals/WebhooksModal/WebhookList.tsx | 3 +- 7 files changed, 314 insertions(+), 416 deletions(-) diff --git a/src/atoms/tableScope/ui.ts b/src/atoms/tableScope/ui.ts index 44afee10..177ae9b2 100644 --- a/src/atoms/tableScope/ui.ts +++ b/src/atoms/tableScope/ui.ts @@ -142,7 +142,7 @@ export const selectedCellAtom = atom(null); export const contextMenuTargetAtom = atom(null); export type CloudLogFilters = { - type: "rowy" | "audit" | "build"; + type: "extension" | "webhook" | "column" | "audit" | "build"; timeRange: | { type: "seconds" | "minutes" | "hours" | "days"; value: number } | { type: "range"; start: Date; end: Date }; diff --git a/src/components/ColumnMenu/ColumnMenu.tsx b/src/components/ColumnMenu/ColumnMenu.tsx index a5f76a67..99b168aa 100644 --- a/src/components/ColumnMenu/ColumnMenu.tsx +++ b/src/components/ColumnMenu/ColumnMenu.tsx @@ -25,7 +25,6 @@ import { import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward"; import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward"; import EditIcon from "@mui/icons-material/EditOutlined"; -// import ReorderIcon from "@mui/icons-material/Reorder"; import SettingsIcon from "@mui/icons-material/SettingsOutlined"; import EvalIcon from "@mui/icons-material/PlayCircleOutline"; @@ -319,24 +318,19 @@ export default function ColumnMenu({ }, disabled: !isConfigurable, }, - // { - // label: "Re-order", - // icon: , - // onClick: () => alert("REORDER"), - // }, - - // { - // label: "Hide for everyone", - // activeLabel: "Show", - // icon: , - // activeIcon: , - // onClick: () => { - // actions.update(column.key, { hidden: !column.hidden }); - // handleClose(); - // }, - // active: column.hidden, - // color: "error" as "error", - // }, + { + key: "logs", + label: altPress ? "Logs" : "Logs…", + icon: , + onClick: () => { + setModal("cloudLogs"); + setCloudLogFilters({ + type: "column", + timeRange: { type: "days", value: 7 }, + column: [column.key], + }); + }, + }, ]; // TODO: Generalize @@ -388,19 +382,6 @@ export default function ColumnMenu({ confirm: "Evaluate", }), }, - { - key: "logs", - label: altPress ? "Logs" : "Logs…", - icon: , - onClick: () => { - setModal("cloudLogs"); - setCloudLogFilters({ - type: "rowy", - timeRange: { type: "days", value: 7 }, - column: [column.key], - }); - }, - }, ]; const columnActions: IMenuContentsProps["menuItems"] = [ diff --git a/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx b/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx index 95af37f1..93c2a8af 100644 --- a/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx +++ b/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx @@ -13,6 +13,7 @@ import { InputAdornment, Button, Box, + CircularProgress, } from "@mui/material"; import RefreshIcon from "@mui/icons-material/Refresh"; import { CloudLogs as LogsIcon } from "@src/assets/icons"; @@ -96,7 +97,7 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { "&, & .MuiTab-root": { minHeight: { md: "var(--dialog-title-height)" }, }, - ml: { md: 18 }, + ml: { md: 20 }, mr: { md: 40 / 8 + 3 }, minHeight: 32, @@ -114,15 +115,17 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { + onChange={(_, v) => { setCloudLogFilters((c) => ({ type: v, timeRange: c.timeRange, - })) - } + })); + }} aria-label="Filter by log type" > - Rowy Logging + Extension + Webhook + Column Audit Build @@ -142,154 +145,18 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { )} - {cloudLogFilters.type === "rowy" && <>} - {cloudLogFilters.type === "audit" && ( - - setCloudLogFilters((prev) => ({ - ...prev, - auditRowId: e.target.value, - })) - } - InputProps={{ - startAdornment: ( - - {tableSettings.collection}/ - - ), - }} - className="labelHorizontal" - sx={{ - "& .MuiInputBase-root, & .MuiInputBase-input": { - typography: "body2", - fontFamily: "mono", - }, - "& .MuiInputAdornment-positionStart": { - m: "0 !important", - pointerEvents: "none", - }, - "& .MuiInputBase-input": { pl: 0 }, - }} - /> - )} -
{cloudLogFilters.type !== "build" && ( <> - {!isValidating && Array.isArray(data) && ( - - {data.length} entries - - )} - - {cloudLogFilters.type !== "rowy" && ( - - setCloudLogFilters((prev) => ({ ...prev, severity })) - } - TextFieldProps={{ - style: { width: 130 }, - placeholder: "Severity", - SelectProps: { - renderValue: () => { - if ( - !Array.isArray(cloudLogFilters.severity) || - cloudLogFilters.severity.length === 0 - ) - return `Severity`; - - if (cloudLogFilters.severity.length === 1) - return ( - <> - Severity{" "} - - - ); - - return `Severity (${cloudLogFilters.severity.length})`; - }, - }, - }} - itemRenderer={(option) => ( - <> - - {startCase(option.value.toLowerCase())} - - )} - /> - )} - - setCloudLogFilters((c) => ({ ...c, timeRange: value })) - } - /> - mutate()} - title="Refresh" - icon={} - disabled={isValidating} - /> - - )} - - - {isValidating && ( - - )} - - } - > - {cloudLogFilters.type === "build" ? ( - - ) : ( - - - {cloudLogFilters.type === "rowy" ? ( - + + {isValidating ? "Loading" : `${data?.length ?? 0} entries`} + - { - setCloudLogFilters((prev) => ({ - ...prev, - functionType: v, - })); - }} - TextFieldProps={{ - id: "functionType", - className: "labelHorizontal", - sx: { "& .MuiInputBase-root": { width: 200 } }, - fullWidth: false, - SelectProps: { - renderValue: () => { - if (cloudLogFilters?.functionType?.length === 1) { - return `Type (${cloudLogFilters.functionType[0]})`; - } else if (cloudLogFilters?.functionType?.length) { - return `Type (${cloudLogFilters.functionType.length})`; - } else { - return `Type`; - } - }, - }, - }} - itemRenderer={(option) => <>{upperCase(option.value)}} + + mutate()} + title="Refresh" + icon={ + isValidating ? ( + + ) : ( + + ) + } + disabled={isValidating} /> - { - setCloudLogFilters((prev) => ({ - ...prev, - loggingSource: v, - })); - }} - TextFieldProps={{ - id: "loggingSource", - className: "labelHorizontal", - sx: { "& .MuiInputBase-root": { width: 200 } }, - fullWidth: false, - SelectProps: { - renderValue: () => { - if (cloudLogFilters?.loggingSource?.length === 1) { - return `Source (${cloudLogFilters.loggingSource[0]})`; - } else if (cloudLogFilters?.loggingSource?.length) { - return `Source (${cloudLogFilters.loggingSource.length})`; - } else { - return `Source`; - } + + )} + + + } + > + {cloudLogFilters.type === "build" ? ( + + ) : ( + + {["extension", "webhook", "column", "audit"].includes( + cloudLogFilters.type + ) ? ( + + {cloudLogFilters.type === "extension" ? ( + <> + ({ + label: x.name, + value: x.name, + type: x.type, + })) + : [] + } + value={cloudLogFilters.extension ?? []} + onChange={(v) => + setCloudLogFilters((prev) => ({ ...prev, extension: v })) + } + TextFieldProps={{ + id: "extension", + className: "labelHorizontal", + sx: { + width: "100%", + "& .MuiInputBase-root": { width: "100%" }, }, - }, - }} - itemRenderer={(option) => <>{upperCase(option.value)}} - /> + fullWidth: false, + placeholder: "Extension", + SelectProps: { + renderValue: () => { + if (cloudLogFilters?.extension?.length === 1) { + return `Extension (${cloudLogFilters.extension[0]})`; + } else if (cloudLogFilters?.extension?.length) { + return `Extension (${cloudLogFilters.extension.length})`; + } else { + return `Extension`; + } + }, + }, + }} + itemRenderer={(option) => ( + <> + {option.label} {option.type} + + )} + /> + + ) : null} + {cloudLogFilters.type === "webhook" ? ( { @@ -412,133 +306,145 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { )} /> - ({ - label: x.name, - value: x.name, - type: x.type, - })) - : [] - } - value={cloudLogFilters.extension ?? []} - onChange={(v) => - setCloudLogFilters((prev) => ({ ...prev, extension: v })) - } - TextFieldProps={{ - id: "extension", - className: "labelHorizontal", - sx: { "& .MuiInputBase-root": { width: 180 } }, - fullWidth: false, - placeholder: "Extension", - SelectProps: { - renderValue: () => { - if (cloudLogFilters?.extension?.length === 1) { - return `Extension (${cloudLogFilters.extension[0]})`; - } else if (cloudLogFilters?.extension?.length) { - return `Extension (${cloudLogFilters.extension.length})`; - } else { - return `Extension`; - } + ) : null} + {cloudLogFilters.type === "column" ? ( + <> + ({ + label: config.name, + value: key, + type: config.type, + }) + )} + value={cloudLogFilters.column ?? []} + onChange={(v) => + setCloudLogFilters((prev) => ({ ...prev, column: v })) + } + TextFieldProps={{ + id: "column", + className: "labelHorizontal", + sx: { + width: "100%", + "& .MuiInputBase-root": { width: "100%" }, }, - }, - }} - itemRenderer={(option) => ( - <> - {option.label} {option.type} - - )} - /> - ({ - label: config.name, - value: key, - type: config.type, - }) - )} - value={cloudLogFilters.column ?? []} - onChange={(v) => - setCloudLogFilters((prev) => ({ ...prev, column: v })) - } - TextFieldProps={{ - id: "column", - className: "labelHorizontal", - sx: { "& .MuiInputBase-root": { width: 200 } }, - fullWidth: false, - placeholder: "Column", - SelectProps: { - renderValue: () => { - if (cloudLogFilters?.column?.length === 1) { - return `Column (${cloudLogFilters.column[0]})`; - } else if (cloudLogFilters?.column?.length) { - return `Column (${cloudLogFilters.column.length})`; - } else { - return `Column`; - } + fullWidth: false, + placeholder: "Column", + SelectProps: { + renderValue: () => { + if (cloudLogFilters?.column?.length === 1) { + return `Column (${cloudLogFilters.column[0]})`; + } else if (cloudLogFilters?.column?.length) { + return `Column (${cloudLogFilters.column.length})`; + } else { + return `Column`; + } + }, }, - }, - }} - itemRenderer={(option) => ( - <> - {option.label} {option.value}  - {option.type} - - )} - /> - - setCloudLogFilters((prev) => ({ ...prev, severity })) - } - TextFieldProps={{ - style: { width: 130 }, - placeholder: "Severity", - SelectProps: { - renderValue: () => { - if ( - !Array.isArray(cloudLogFilters.severity) || - cloudLogFilters.severity.length === 0 - ) - return `Severity`; + }} + itemRenderer={(option) => ( + <> + {option.label} {option.value}  + {option.type} + + )} + /> + + ) : null} + {cloudLogFilters.type === "audit" ? ( + <> + + setCloudLogFilters((prev) => ({ + ...prev, + auditRowId: e.target.value, + })) + } + InputProps={{ + startAdornment: ( + + {tableSettings.collection}/ + + ), + }} + className="labelHorizontal" + sx={{ + width: "100%", + "& .MuiInputBase-root, & .MuiInputBase-input": { + width: "100%", + typography: "body2", + fontFamily: "mono", + }, + "& .MuiInputAdornment-positionStart": { + m: "0 !important", + pointerEvents: "none", + }, + "& .MuiInputBase-input": { pl: 0 }, + "& .MuiFormLabel-root": { + whiteSpace: "nowrap", + }, + }} + /> + + ) : null} + + setCloudLogFilters((prev) => ({ ...prev, severity })) + } + TextFieldProps={{ + style: { width: 200 }, + placeholder: "Severity", + SelectProps: { + renderValue: () => { + if ( + !Array.isArray(cloudLogFilters.severity) || + cloudLogFilters.severity.length === 0 + ) + return `Severity`; - if (cloudLogFilters.severity.length === 1) - return ( - <> - Severity{" "} - - - ); + if (cloudLogFilters.severity.length === 1) + return ( + <> + Severity{" "} + + + ); - return `Severity (${cloudLogFilters.severity.length})`; - }, + return `Severity (${cloudLogFilters.severity.length})`; }, - }} - itemRenderer={(option) => ( - <> - - {startCase(option.value.toLowerCase())} - - )} - /> - - ) : null} - + }, + }} + itemRenderer={(option) => ( + <> + + {startCase(option.value.toLowerCase())} + + )} + /> + + setCloudLogFilters((c) => ({ ...c, timeRange: value })) + } + /> + + ) : null} +
{value && value.type !== "range" && ( { + return `jsonPayload.loggingSource = "${loggingSource}"`; + }) + .join(encodeURIComponent(" OR ")) + ); + } + switch (cloudLogFilters.type) { - case "rowy": + case "extension": logQuery.push(`logName = "projects/${projectId}/logs/rowy-logging"`); - if (cloudLogFilters?.functionType?.length) - logQuery.push( - cloudLogFilters.functionType - .map((functionType) => { - return `jsonPayload.functionType = "${functionType}"`; - }) - .join(encodeURIComponent(" OR ")) - ); - if (cloudLogFilters?.loggingSource?.length) { - logQuery.push( - cloudLogFilters.loggingSource - .map((loggingSource) => { - return `jsonPayload.loggingSource = "${loggingSource}"`; - }) - .join(encodeURIComponent(" OR ")) - ); - } else { - // mandatory filter to remove unwanted gcp diagnostic logs - logQuery.push( - ["backend-scripts", "backend-function", "hooks"] - .map((loggingSource) => { - return `jsonPayload.loggingSource = "${loggingSource}"`; - }) - .join(encodeURIComponent(" OR ")) - ); - } - if (cloudLogFilters?.webhook?.length) { - logQuery.push( - cloudLogFilters.webhook - .map((id) => `jsonPayload.url : "${id}"`) - .join(encodeURIComponent(" OR ")) - ); - } - if (cloudLogFilters?.extension?.length) + if (cloudLogFilters?.extension?.length) { logQuery.push( cloudLogFilters.extension .map((extensionName) => { @@ -56,7 +34,25 @@ export const cloudLogFetcher = ( }) .join(encodeURIComponent(" OR ")) ); - if (cloudLogFilters?.column?.length) + } else { + logQuery.push(`jsonPayload.functionType = "extension"`); + } + break; + + case "webhook": + if (cloudLogFilters?.webhook?.length) { + logQuery.push( + cloudLogFilters.webhook + .map((id) => `jsonPayload.url : "${id}"`) + .join(encodeURIComponent(" OR ")) + ); + } else { + logQuery.push(`jsonPayload.functionType = "hooks"`); + } + break; + + case "column": + if (cloudLogFilters?.column?.length) { logQuery.push( cloudLogFilters.column .map((column) => { @@ -64,6 +60,21 @@ export const cloudLogFetcher = ( }) .join(encodeURIComponent(" OR ")) ); + } else { + logQuery.push( + [ + "connector", + "derivative-script", + "action", + "derivative-function", + "defaultValue", + ] + .map((functionType) => { + return `jsonPayload.functionType = "${functionType}"`; + }) + .join(encodeURIComponent(" OR ")) + ); + } break; case "audit": diff --git a/src/components/TableModals/ExtensionsModal/ExtensionList.tsx b/src/components/TableModals/ExtensionsModal/ExtensionList.tsx index 7ed8e6c6..a0d5b82f 100644 --- a/src/components/TableModals/ExtensionsModal/ExtensionList.tsx +++ b/src/components/TableModals/ExtensionsModal/ExtensionList.tsx @@ -107,8 +107,7 @@ export default function ExtensionList({ onClick={() => { setModal("cloudLogs"); setCloudLogFilters({ - type: "rowy", - functionType: ["extension"], + type: "extension", timeRange: { type: "days", value: 7 }, extension: [extensionObject.name], }); diff --git a/src/components/TableModals/WebhooksModal/WebhookList.tsx b/src/components/TableModals/WebhooksModal/WebhookList.tsx index 01b67d07..d2f6b670 100644 --- a/src/components/TableModals/WebhooksModal/WebhookList.tsx +++ b/src/components/TableModals/WebhooksModal/WebhookList.tsx @@ -126,8 +126,7 @@ export default function WebhookList({ onClick={() => { setModal("cloudLogs"); setCloudLogFilters({ - type: "rowy", - functionType: ["hooks"], + type: "webhook", timeRange: { type: "days", value: 7 }, webhook: [webhook.endpoint], }); From 28f6ea519f22589965def134db46794b13ae28bf Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Thu, 29 Dec 2022 20:57:18 +0930 Subject: [PATCH 10/14] column logs: only allow logging view for connector/action/default value/derivative --- src/components/ColumnMenu/ColumnMenu.tsx | 14 +++++++++++--- .../CloudLogsModal/CloudLogsModal.tsx | 17 +++++++++++++---- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/components/ColumnMenu/ColumnMenu.tsx b/src/components/ColumnMenu/ColumnMenu.tsx index 99b168aa..7dff465e 100644 --- a/src/components/ColumnMenu/ColumnMenu.tsx +++ b/src/components/ColumnMenu/ColumnMenu.tsx @@ -318,7 +318,15 @@ export default function ColumnMenu({ }, disabled: !isConfigurable, }, - { + ]; + + if ( + column?.config?.defaultValue?.type === "dynamic" || + [FieldType.action, FieldType.derivative, FieldType.connector].includes( + column.type + ) + ) { + configActions.push({ key: "logs", label: altPress ? "Logs" : "Logs…", icon: , @@ -330,8 +338,8 @@ export default function ColumnMenu({ column: [column.key], }); }, - }, - ]; + }); + } // TODO: Generalize const handleEvaluateAll = async () => { diff --git a/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx b/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx index 93c2a8af..2b835e3a 100644 --- a/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx +++ b/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx @@ -43,6 +43,7 @@ import { cloudLogFiltersAtom, } from "@src/atoms/tableScope"; import { cloudLogFetcher } from "./utils"; +import { FieldType } from "@src/constants/fields"; export default function CloudLogsModal({ onClose }: ITableModalProps) { const [projectId] = useAtom(projectIdAtom, projectScope); @@ -312,13 +313,21 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { ({ + options={Object.entries(tableSchema.columns ?? {}) + .filter( + ([key, config]) => + config?.config?.defaultValue?.type === "dynamic" || + [ + FieldType.action, + FieldType.derivative, + FieldType.connector, + ].includes(config.type) + ) + .map(([key, config]) => ({ label: config.name, value: key, type: config.type, - }) - )} + }))} value={cloudLogFilters.column ?? []} onChange={(v) => setCloudLogFilters((prev) => ({ ...prev, column: v })) From 503dae79d8dba7537b0444280136c8e1a5428598 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Thu, 29 Dec 2022 21:41:06 +0930 Subject: [PATCH 11/14] auto refresh when switching log tabs --- .../TableModals/CloudLogsModal/CloudLogsModal.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx b/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx index 2b835e3a..2e20a475 100644 --- a/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx +++ b/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx @@ -116,11 +116,20 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { { + onChange={(_, newType) => { setCloudLogFilters((c) => ({ - type: v, + type: newType, timeRange: c.timeRange, })); + if ( + ["extension", "webhook", "column", "audit"].includes( + newType + ) + ) { + setTimeout(() => { + mutate(); + }, 0); + } }} aria-label="Filter by log type" > @@ -169,6 +178,7 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { severity: undefined, })); }} + disabled={isValidating} > Reset From 295974145acd0dafe4c7faf86ec4172c554ff25e Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Thu, 29 Dec 2022 21:58:36 +0930 Subject: [PATCH 12/14] add back old functions logging --- src/atoms/tableScope/ui.ts | 2 +- .../CloudLogsModal/CloudLogsModal.tsx | 32 ++++++++++++------- .../TableModals/CloudLogsModal/utils.ts | 4 +++ 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/atoms/tableScope/ui.ts b/src/atoms/tableScope/ui.ts index 177ae9b2..c1de1780 100644 --- a/src/atoms/tableScope/ui.ts +++ b/src/atoms/tableScope/ui.ts @@ -142,7 +142,7 @@ export const selectedCellAtom = atom(null); export const contextMenuTargetAtom = atom(null); export type CloudLogFilters = { - type: "extension" | "webhook" | "column" | "audit" | "build"; + type: "extension" | "webhook" | "column" | "audit" | "build" | "functions"; timeRange: | { type: "seconds" | "minutes" | "hours" | "days"; value: number } | { type: "range"; start: Date; end: Date }; diff --git a/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx b/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx index 2e20a475..b211dec2 100644 --- a/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx +++ b/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx @@ -17,6 +17,7 @@ import { } from "@mui/material"; import RefreshIcon from "@mui/icons-material/Refresh"; import { CloudLogs as LogsIcon } from "@src/assets/icons"; +import ClearIcon from "@mui/icons-material/Clear"; import Modal from "@src/components/Modal"; import TableToolbarButton from "@src/components/TableToolbar/TableToolbarButton"; @@ -122,9 +123,13 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { timeRange: c.timeRange, })); if ( - ["extension", "webhook", "column", "audit"].includes( - newType - ) + [ + "extension", + "webhook", + "column", + "audit", + "functions", + ].includes(newType) ) { setTimeout(() => { mutate(); @@ -138,6 +143,9 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { Column Audit Build + + Functions (legacy) + ) : ( - {isValidating ? "Loading" : `${data?.length ?? 0} entries`} + {isValidating ? "" : `${data?.length ?? 0} entries`} - - + /> mutate()} title="Refresh" @@ -212,7 +219,7 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { overflowY: "visible", }} > - {["extension", "webhook", "column", "audit"].includes( + {["extension", "webhook", "column", "audit", "functions"].includes( cloudLogFilters.type ) ? ( + {cloudLogFilters.type === "functions" ? ( + + ) : null} {cloudLogFilters.type === "extension" ? ( <> Date: Thu, 29 Dec 2022 22:03:12 +0930 Subject: [PATCH 13/14] fix load more not working --- .../TableModals/CloudLogsModal/CloudLogsModal.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx b/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx index b211dec2..76cfe719 100644 --- a/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx +++ b/src/components/TableModals/CloudLogsModal/CloudLogsModal.tsx @@ -489,15 +489,18 @@ export default function CloudLogsModal({ onClose }: ITableModalProps) { marginRight: "auto", display: "flex", }} - onClick={() => + onClick={() => { setCloudLogFilters((c) => ({ ...c, timeRange: { ...c.timeRange, value: (c.timeRange as any).value * 2, }, - })) - } + })); + setTimeout(() => { + mutate(); + }, 0); + }} > Load more (last {cloudLogFilters.timeRange.value * 2}{" "} {cloudLogFilters.timeRange.type}) From 305d47d1a139617ea319d010bb2d718042eb7114 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Fri, 30 Dec 2022 15:29:30 +0930 Subject: [PATCH 14/14] reuse Rowy rowy loggin types --- src/components/CodeEditor/extensions.d.ts | 6 +----- src/components/CodeEditor/rowy.d.ts | 5 +++++ .../ColumnModals/ColumnConfigModal/defaultValue.d.ts | 6 +----- .../TableModals/WebhooksModal/Schemas/basic.tsx | 12 ++---------- src/components/TableModals/WebhooksModal/utils.tsx | 12 ++---------- .../TableModals/WebhooksModal/webhooks.d.ts | 12 ++---------- src/components/fields/Action/action.d.ts | 6 +----- src/components/fields/Connector/connector.d.ts | 6 +----- src/components/fields/Derivative/derivative.d.ts | 6 +----- src/components/fields/types.ts | 6 ------ 10 files changed, 16 insertions(+), 61 deletions(-) diff --git a/src/components/CodeEditor/extensions.d.ts b/src/components/CodeEditor/extensions.d.ts index 3da39ae9..22af5756 100644 --- a/src/components/CodeEditor/extensions.d.ts +++ b/src/components/CodeEditor/extensions.d.ts @@ -26,11 +26,7 @@ type ExtensionContext = { extensionBody: any; }; RULES_UTILS: any; - logging: { - log: (payload: any) => void; - warn: (payload: any) => void; - error: (payload: any) => void; - }; + logging: RowyLogging; }; // extension body definition diff --git a/src/components/CodeEditor/rowy.d.ts b/src/components/CodeEditor/rowy.d.ts index f6852cce..42582dd0 100644 --- a/src/components/CodeEditor/rowy.d.ts +++ b/src/components/CodeEditor/rowy.d.ts @@ -17,6 +17,11 @@ type uploadOptions = { folderPath?: string; fileName?: string; }; +type RowyLogging = { + log: (payload: any) => void; + warn: (payload: any) => void; + error: (payload: any) => void; +}; interface Rowy { metadata: { /** diff --git a/src/components/ColumnModals/ColumnConfigModal/defaultValue.d.ts b/src/components/ColumnModals/ColumnConfigModal/defaultValue.d.ts index e3b90e13..779bd9be 100644 --- a/src/components/ColumnModals/ColumnConfigModal/defaultValue.d.ts +++ b/src/components/ColumnModals/ColumnConfigModal/defaultValue.d.ts @@ -4,10 +4,6 @@ type DefaultValueContext = { storage: firebasestorage.Storage; db: FirebaseFirestore.Firestore; auth: firebaseauth.BaseAuth; - logging: { - log: (payload: any) => void; - warn: (payload: any) => void; - error: (payload: any) => void; - }; + logging: RowyLogging; }; type DefaultValue = (context: DefaultValueContext) => "PLACEHOLDER_OUTPUT_TYPE"; diff --git a/src/components/TableModals/WebhooksModal/Schemas/basic.tsx b/src/components/TableModals/WebhooksModal/Schemas/basic.tsx index 54075d43..9d8e7b8c 100644 --- a/src/components/TableModals/WebhooksModal/Schemas/basic.tsx +++ b/src/components/TableModals/WebhooksModal/Schemas/basic.tsx @@ -30,11 +30,7 @@ export const parserExtraLibs = [ send: (v:any)=>void; sendStatus: (status:number)=>void }; - logging: { - log: (payload: any) => void; - warn: (payload: any) => void; - error: (payload: any) => void; - }; + logging: RowyLogging; } ) => Promise;`, ]; @@ -49,11 +45,7 @@ export const conditionExtraLibs = [ send: (v:any)=>void; sendStatus: (status:number)=>void; }; - logging: { - log: (payload: any) => void; - warn: (payload: any) => void; - error: (payload: any) => void; - }; + logging: RowyLogging; } ) => Promise;`, ]; diff --git a/src/components/TableModals/WebhooksModal/utils.tsx b/src/components/TableModals/WebhooksModal/utils.tsx index b1ba8601..c7a992ef 100644 --- a/src/components/TableModals/WebhooksModal/utils.tsx +++ b/src/components/TableModals/WebhooksModal/utils.tsx @@ -35,11 +35,7 @@ export const parserExtraLibs = [ send: (v:any)=>void; sendStatus: (status:number)=>void }; - logging: { - log: (payload: any) => void; - warn: (payload: any) => void; - error: (payload: any) => void; - }; + logging: RowyLogging; } ) => Promise;`, ]; @@ -54,11 +50,7 @@ export const conditionExtraLibs = [ send: (v:any)=>void sendStatus: (status:number)=>void }; - logging: { - log: (payload: any) => void; - warn: (payload: any) => void; - error: (payload: any) => void; - }; + logging: RowyLogging; } ) => Promise;`, ]; diff --git a/src/components/TableModals/WebhooksModal/webhooks.d.ts b/src/components/TableModals/WebhooksModal/webhooks.d.ts index fa98341f..65df0530 100644 --- a/src/components/TableModals/WebhooksModal/webhooks.d.ts +++ b/src/components/TableModals/WebhooksModal/webhooks.d.ts @@ -3,20 +3,12 @@ type Condition = (args: { db: FirebaseFirestore.Firestore; ref: FirebaseFirestore.CollectionReference; res: Response; - logging: { - log: (payload: any) => void; - warn: (payload: any) => void; - error: (payload: any) => void; - }; + logging: RowyLogging; }) => Promise; type Parser = (args: { req: WebHookRequest; db: FirebaseFirestore.Firestore; ref: FirebaseFirestore.CollectionReference; - logging: { - log: (payload: any) => void; - warn: (payload: any) => void; - error: (payload: any) => void; - }; + logging: RowyLogging; }) => Promise; diff --git a/src/components/fields/Action/action.d.ts b/src/components/fields/Action/action.d.ts index 33fc7489..1daab613 100644 --- a/src/components/fields/Action/action.d.ts +++ b/src/components/fields/Action/action.d.ts @@ -15,11 +15,7 @@ type ActionContext = { auth: firebaseauth.BaseAuth; actionParams: actionParams; user: ActionUser; - logging: { - log: (payload: any) => void; - warn: (payload: any) => void; - error: (payload: any) => void; - }; + logging: RowyLogging; }; type ActionResult = { diff --git a/src/components/fields/Connector/connector.d.ts b/src/components/fields/Connector/connector.d.ts index d12041d4..c16585ae 100644 --- a/src/components/fields/Connector/connector.d.ts +++ b/src/components/fields/Connector/connector.d.ts @@ -15,11 +15,7 @@ type ConnectorContext = { auth: firebaseauth.BaseAuth; query: string; user: ConnectorUser; - logging: { - log: (payload: any) => void; - warn: (payload: any) => void; - error: (payload: any) => void; - }; + logging: RowyLogging; }; type ConnectorResult = any[]; type Connector = ( diff --git a/src/components/fields/Derivative/derivative.d.ts b/src/components/fields/Derivative/derivative.d.ts index 9d01f97c..a56afeba 100644 --- a/src/components/fields/Derivative/derivative.d.ts +++ b/src/components/fields/Derivative/derivative.d.ts @@ -5,11 +5,7 @@ type DerivativeContext = { db: FirebaseFirestore.Firestore; auth: firebaseauth.BaseAuth; change: any; - logging: { - log: (payload: any) => void; - warn: (payload: any) => void; - error: (payload: any) => void; - }; + logging: RowyLogging; }; type Derivative = (context: DerivativeContext) => "PLACEHOLDER_OUTPUT_TYPE"; diff --git a/src/components/fields/types.ts b/src/components/fields/types.ts index 299336f2..63374d81 100644 --- a/src/components/fields/types.ts +++ b/src/components/fields/types.ts @@ -113,9 +113,3 @@ export interface IFilterCustomInputProps { operator: TableFilter["operator"]; [key: string]: any; } - -export interface RowyLogging { - log: (payload: any) => void; - warn: (payload: any) => void; - error: (payload: any) => void; -}