Merge pull request #1070 from rowyio/feature/code-templates-comments-update

ROWY-879: code templates update
This commit is contained in:
Shams
2023-01-11 11:40:55 +01:00
committed by GitHub
16 changed files with 376 additions and 343 deletions

View File

@@ -9,6 +9,9 @@ import { projectScope, projectIdAtom } from "@src/atoms/projectScope";
export interface ICodeEditorHelperProps {
docLink: string;
disableDefaultVariables?: boolean;
disableSecretManagerLink?: boolean;
disableCloudManagerLink?: boolean;
additionalVariables?: {
key: string;
description: string;
@@ -17,32 +20,37 @@ export interface ICodeEditorHelperProps {
export default function CodeEditorHelper({
docLink,
disableDefaultVariables,
disableSecretManagerLink,
disableCloudManagerLink,
additionalVariables,
}: ICodeEditorHelperProps) {
const [projectId] = useAtom(projectIdAtom, projectScope);
const availableVariables = [
{
key: "db",
description: `db object provides access to firestore database instance of this project. giving you access to any collection or document in this firestore instance`,
},
{
key: "auth",
description: `auth provides access to a firebase auth instance, can be used to manage auth users or generate tokens.`,
},
{
key: "storage",
description: `firebase Storage can be accessed through this, storage.bucket() returns default storage bucket of the firebase project.`,
},
{
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`,
},
];
const availableVariables = disableDefaultVariables
? []
: [
{
key: "db",
description: `db object provides access to firestore database instance of this project. giving you access to any collection or document in this firestore instance`,
},
{
key: "auth",
description: `auth provides access to a firebase auth instance, can be used to manage auth users or generate tokens.`,
},
{
key: "storage",
description: `firebase Storage can be accessed through this, storage.bucket() returns default storage bucket of the firebase project.`,
},
{
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 (
<Stack
@@ -77,29 +85,33 @@ export default function CodeEditorHelper({
spacing={1}
style={{ marginTop: -4 }}
>
<Tooltip title="Secret Manager&nbsp;↗">
<IconButton
size="small"
color="primary"
target="_blank"
rel="noopener noreferrer"
href={`https://console.cloud.google.com/security/secret-manager?project=${projectId}`}
>
<SecretsIcon fontSize="small" />
</IconButton>
</Tooltip>
{!disableSecretManagerLink && (
<Tooltip title="Secret Manager&nbsp;↗">
<IconButton
size="small"
color="primary"
target="_blank"
rel="noopener noreferrer"
href={`https://console.cloud.google.com/security/secret-manager?project=${projectId}`}
>
<SecretsIcon fontSize="small" />
</IconButton>
</Tooltip>
)}
<Tooltip title="Configure Cloud Function&nbsp;↗">
<IconButton
size="small"
color="primary"
target="_blank"
rel="noopener noreferrer"
href={`https://console.cloud.google.com/functions/list?project=${projectId}`}
>
<FunctionsIcon fontSize="small" />
</IconButton>
</Tooltip>
{!disableCloudManagerLink && (
<Tooltip title="Configure Cloud Function&nbsp;↗">
<IconButton
size="small"
color="primary"
target="_blank"
rel="noopener noreferrer"
href={`https://console.cloud.google.com/functions/list?project=${projectId}`}
>
<FunctionsIcon fontSize="small" />
</IconButton>
</Tooltip>
)}
<Tooltip title="Examples & documentation&nbsp;↗">
<IconButton

View File

@@ -53,17 +53,20 @@ function CodeEditor({ type, column, handleChange }: ICodeEditorProps) {
dynamicValueFn = column.config?.defaultValue?.dynamicValueFn;
} else if (column.config?.defaultValue?.script) {
dynamicValueFn = `const dynamicValueFn : DefaultValue = async ({row,ref,db,storage,auth,logging})=>{
${column.config?.defaultValue.script}
}`;
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
${column.config?.defaultValue.script}
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`;
} else {
dynamicValueFn = `const dynamicValueFn : DefaultValue = async ({row,ref,db,storage,auth,logging})=>{
// Write your default value code here
// for example:
// generate random hex color
// const color = "#" + Math.floor(Math.random() * 16777215).toString(16);
// return color;
// checkout the documentation for more info: https://docs.rowy.io/how-to/default-values#dynamic
}`;
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
// Example: generate random hex color
// const color = "#" + Math.floor(Math.random() * 16777215).toString(16);
// return color;
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`;
}
return (

View File

@@ -62,50 +62,53 @@ export const triggerTypes: ExtensionTrigger[] = ["create", "update", "delete"];
const extensionBodyTemplate = {
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.
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
// example:
// we can post notification to different discord channels based on row data
// Task Extension is very flexible, you can do anything.
// From updating other documents in your database, to making an api request to 3rd party service.
// Example: post notification to different discord channels based on row data
/*
const topic = row.topic;
const channel = await db.collection('discordChannels').doc(topic).get();
const channelUrl = await channel.get("channelUrl");
const content = "Hello discord channel";
return fetch("https://discord.com/api/webhooks/"+channelUrl, {
{
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
content
})
}).then(async resp => {
const result = await resp.json()
if (resp.ok) console.info(result)
else console.error(result)
return fetch("https://discord.com/api/webhooks/"+channelUrl, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
content
})
}).then(async resp => {
const result = await resp.json()
if (resp.ok) console.info(result)
else console.error(result)
})
*/
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
docSync: `const extensionBody: DocSyncBody = async({row, db, change, ref, logging}) => {
// feel free to add your own code logic here
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
return ({
fieldsToSync: [], // a list of string of column names
row: row, // object of data to sync, usually the row itself
targetPath: "", // fill in the path here
})
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
historySnapshot: `const extensionBody: HistorySnapshotBody = async({row, db, change, ref, logging}) => {
// feel free to add your own code logic here
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
return ({
trackedFields: [], // a list of string of column names
collectionId: "historySnapshots", // optionally change the sub-collection id of where the history snapshots are stored
})
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
algoliaIndex: `const extensionBody: AlgoliaIndexBody = async({row, db, change, ref, logging}) => {
// feel free to add your own code logic here
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
return ({
fieldsToSync: [], // a list of string of column names
@@ -113,9 +116,10 @@ const extensionBodyTemplate = {
index: "", // algolia index to sync to
objectID: ref.id, // algolia object ID, ref.id is one possible choice
})
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
meiliIndex: `const extensionBody: MeiliIndexBody = async({row, db, change, ref, logging}) => {
// feel free to add your own code logic here
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
return({
fieldsToSync: [], // a list of string of column names
@@ -123,9 +127,10 @@ const extensionBodyTemplate = {
index: "", // algolia index to sync to
objectID: ref.id, // algolia object ID, ref.id is one possible choice
})
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
bigqueryIndex: `const extensionBody: BigqueryIndexBody = async({row, db, change, ref, logging}) => {
// feel free to add your own code logic here
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
return ({
fieldsToSync: [], // a list of string of column names
@@ -133,9 +138,10 @@ const extensionBodyTemplate = {
index: "", // algolia index to sync to
objectID: ref.id, // algolia object ID, ref.id is one possible choice
})
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
slackMessage: `const extensionBody: SlackMessageBody = async({row, db, change, ref, logging}) => {
// feel free to add your own code logic here
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
return ({
channels: [], // a list of slack channel IDs in string
@@ -143,18 +149,19 @@ const extensionBodyTemplate = {
text: "", // the text parameter to pass in to slack api
attachments: [], // the attachments parameter to pass in to slack api
})
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
sendgridEmail: `const extensionBody: SendgridEmailBody = async({row, db, change, ref, logging}) => {
// feel free to add your own code logic here
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
return ({
from: "Name<example@domain.com>", // send from field
personalizations: [
{
to: [{ name: "", email: "" }], // recipient
dynamic_template_data: {
}, // template parameters
},
{
to: [{ name: "", email: "" }], // recipient
dynamic_template_data: {
}, // template parameters
},
],
template_id: "", // sendgrid template ID
categories: [], // helper info to categorise sendgrid emails
@@ -163,9 +170,10 @@ const extensionBodyTemplate = {
// add any other custom args you want to pass to sendgrid events here
},
})
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
apiCall: `const extensionBody: ApiCallBody = async({row, db, change, ref, logging}) => {
// feel free to add your own code logic here
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
return ({
body: "",
@@ -173,56 +181,56 @@ const extensionBodyTemplate = {
method: "",
callback: ()=>{},
})
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
twilioMessage: `const extensionBody: TwilioMessageBody = async({row, db, change, ref, logging}) => {
/**
*
* Setup twilio secret key: https://docs.rowy.io/extensions/twilio-message#secret-manager-setup
*
* You can add any code logic here to be able to customize your message
* or dynamically get the from or to numbers
*
**/
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
// Setup twilio secret key: https://docs.rowy.io/extensions/twilio-message#secret-manager-setup
// Add any code here to customize your message or dynamically get the from/to numbers
return ({
from: "", // from phone number registered on twilio
to: "", // recipient phone number - eg: row.<fieldname>
body: "Hi there!" // message text
})
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
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
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
// You can use FCM token from the row or from the user document in the database
// const FCMtoken = row.FCMtoken
// or push through topic
// Or push through topic
const topicName = 'industry-tech';
// you can return single or array of notification payloads
return [{
notification: {
title: 'Hello!',
},
android: {
// You can return single or array of notification payloads
return [{
notification: {
imageUrl: 'https://thiscatdoesnotexist.com/'
}
},
apns: {
payload: {
aps: {
'mutable-content': 1
title: 'Hello!',
},
android: {
notification: {
imageUrl: 'https://thiscatdoesnotexist.com/'
}
},
fcm_options: {
image: 'https://thiscatdoesnotexist.com/'
}
},
webpush: {
headers: {
image: 'https://thiscatdoesnotexist.com/'
}
},
// topic: topicName, // add topic send to subscribers
// token: FCMtoken // add FCM token to send to specific user
}]
apns: {
payload: {
aps: {
'mutable-content': 1
}
},
fcm_options: {
image: 'https://thiscatdoesnotexist.com/'
}
},
webpush: {
headers: {
image: 'https://thiscatdoesnotexist.com/'
}
},
// topic: topicName, // add topic send to subscribers
// token: FCMtoken // add FCM token to send to specific user
}]
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
};
@@ -239,8 +247,10 @@ export function emptyExtensionObject(
requiredFields: [],
trackedFields: [],
conditions: `const condition: Condition = async({row, change, logging}) => {
// feel free to add your own code logic here
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
return true;
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
lastEditor: user,
};

View File

@@ -48,7 +48,7 @@ export default function AddWebhookButton({
}}
{...props}
>
Add webhook
Add Webhook
</Button>
<Menu

View File

@@ -65,29 +65,24 @@ export const webhookBasic = {
template: (
table: TableSettings
) => `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;
`
}
}`,
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
// Optionally return an object to be added as a new row to the table
// Example: add the webhook body as row
const {body} = req;
${
table.audit !== false
? `const ${
table.auditFieldCreatedBy ?? "_createdBy"
} = await rowy.metadata.serviceAccountUser()
return {
...body,
${table.auditFieldCreatedBy ?? "_createdBy"}
}`
: `return body;`
}
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
},
condition: {
additionalVariables,
@@ -95,9 +90,11 @@ export const webhookBasic = {
template: (
table: TableSettings
) => `const condition: Condition = async({ref, req, db, logging}) => {
// feel free to add your own code logic here
return true;
}`,
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
return true;
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
},
auth: (
webhookObject: IWebhook,

View File

@@ -14,21 +14,25 @@ export const webhookSendgrid = {
template: (
table: TableSettings
) => `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
// List of events & docs : https://docs.sendgrid.com/for-developers/tracking-events/event#events
const { event, docPath } = sgEvent
// event param is provided by default
// however docPath or other custom parameter needs be passed in the custom_args variable in Sengrid Extension
return db.doc(docPath).update({ sgStatus: event })
}
//
if (Array.isArray(body)) {
// when multiple events are passed in one call
await Promise.allSettled(body.map(eventHandler))
} else eventHandler(body)
};`,
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
const { body } = req
const eventHandler = async (sgEvent) => {
// Event handlers can be modiefed to preform different actions based on the sendgrid event
// List of events & docs : https://docs.sendgrid.com/for-developers/tracking-events/event#events
const { event, docPath } = sgEvent
// Event param is provided by default
// However docPath or other custom parameter needs be passed in the custom_args variable in Sengrid Extension
return db.doc(docPath).update({ sgStatus: event })
}
if (Array.isArray(body)) {
// Multiple events are passed in one call
await Promise.allSettled(body.map(eventHandler))
} else {
eventHandler(body)
}
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
};`,
},
condition: {
additionalVariables: null,
@@ -36,9 +40,11 @@ export const webhookSendgrid = {
template: (
table: TableSettings
) => `const condition: Condition = async({ref, req, db, logging}) => {
// feel free to add your own code logic here
return true;
}`,
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
return true;
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
},
auth: (
webhookObject: IWebhook,

View File

@@ -18,15 +18,18 @@ export const webhookStripe = {
template: (
table: TableSettings
) => `const sendgridParser: Parser = async ({ req, db, ref, logging }) => {
const event = req.body
switch (event.type) {
case "payment_intent.succeeded":
break;
case "payment_intent.payment_failed":
break;
default:
// all other types
}
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
const event = req.body
switch (event.type) {
case "payment_intent.succeeded":
break;
case "payment_intent.payment_failed":
break;
default:
// All other types
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}
};`,
},
condition: {
@@ -35,8 +38,10 @@ export const webhookStripe = {
template: (
table: TableSettings
) => `const condition: Condition = async({ref, req, db, logging}) => {
// feel free to add your own code logic here
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
return true;
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
},
auth: (

View File

@@ -14,59 +14,57 @@ export const webhookTypeform = {
template: (
table: TableSettings
) => `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
// set the ref value to field key you would like to sync to
// docs: https://help.typeform.com/hc/en-us/articles/360050447552-Block-reference-format-restrictions
const {submitted_at,hidden,answers} = req.body.form_response
const submission = ({
_createdAt: submitted_at,
...hidden,
...answers.reduce((accRow, currAnswer) => {
switch (currAnswer.type) {
case "date":
return {
...accRow,
[currAnswer.field.ref]: new Date(currAnswer[currAnswer.type]),
};
case "choice":
return {
...accRow,
[currAnswer.field.ref]: currAnswer[currAnswer.type].label,
};
case "choices":
return {
...accRow,
[currAnswer.field.ref]: currAnswer[currAnswer.type].labels,
};
case "file_url":
default:
return {
...accRow,
[currAnswer.field.ref]: currAnswer[currAnswer.type],
};
}
}, {}),
})
${
table.audit !== false
? `
// auditField
const ${
table.auditFieldCreatedBy ?? "_createdBy"
} = await rowy.metadata.serviceAccountUser()
return {
...submission,
${table.auditFieldCreatedBy ?? "_createdBy"}
}
`
: `
return submission
`
}
};`,
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
// This reduces the form submission into a single object of key value pairs
// Example: {name: "John", age: 20}
// ⚠️ Ensure that you have assigned ref values of the fields
// Set the ref value to field key you would like to sync to
// Docs: https://help.typeform.com/hc/en-us/articles/360050447552-Block-reference-format-restrictions
const {submitted_at,hidden,answers} = req.body.form_response
const submission = ({
_createdAt: submitted_at,
...hidden,
...answers.reduce((accRow, currAnswer) => {
switch (currAnswer.type) {
case "date":
return {
...accRow,
[currAnswer.field.ref]: new Date(currAnswer[currAnswer.type]),
};
case "choice":
return {
...accRow,
[currAnswer.field.ref]: currAnswer[currAnswer.type].label,
};
case "choices":
return {
...accRow,
[currAnswer.field.ref]: currAnswer[currAnswer.type].labels,
};
case "file_url":
default:
return {
...accRow,
[currAnswer.field.ref]: currAnswer[currAnswer.type],
};
}
}, {}),
})
${
table.audit !== false
? `const ${
table.auditFieldCreatedBy ?? "_createdBy"
} = await rowy.metadata.serviceAccountUser()
return {
...submission,
${table.auditFieldCreatedBy ?? "_createdBy"}
}`
: `return submission;`
}
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
};`,
},
condition: {
additionalVariables: null,
@@ -74,9 +72,11 @@ export const webhookTypeform = {
template: (
table: TableSettings
) => `const condition: Condition = async({ref, req, db, logging}) => {
// feel free to add your own code logic here
return true;
}`,
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
return true;
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
},
auth: (
webhookObject: IWebhook,

View File

@@ -15,30 +15,24 @@ export const webhook = {
template: (
table: TableSettings
) => `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
// 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;
`
}
}`,
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
// Optionally return an object to be added as a new row to the table
// Example: add the webhook body as row
const {body} = req;
${
table.audit !== false
? `const ${
table.auditFieldCreatedBy ?? "_createdBy"
} = await rowy.metadata.serviceAccountUser()
return {
...body,
${table.auditFieldCreatedBy ?? "_createdBy"}
}`
: `return body;`
}
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
},
condition: {
additionalVariables: null,
@@ -46,9 +40,11 @@ export const webhook = {
template: (
table: TableSettings
) => `const condition: Condition = async({ref, req, db, logging}) => {
// feel free to add your own code logic here
return true;
}`,
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
return true;
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`,
},
auth: (
webhookObject: IWebhook,

View File

@@ -86,7 +86,7 @@ export default function WebhookModal({
disableBackdropClick
disableEscapeKeyDown
fullWidth
title={`${mode === "add" ? "Add" : "Update"} webhook: ${
title={`${mode === "add" ? "Add" : "Update"} Webhook: ${
webhookNames[webhookObject.type]
}`}
sx={{

View File

@@ -72,7 +72,7 @@ export const webhookNames: Record<WebhookType, string> = {
// twitter: "Twitter",
stripe: "Stripe",
basic: "Basic",
webform: "Web form",
webform: "Web Form",
};
export interface IWebhookEditor {

View File

@@ -1,54 +1,59 @@
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")
// try {
// const resp = await fetch('https://example.com/api/v1/users/'+ref.id,{
// method: 'PUT',
// headers: {
// 'Content-Type': 'application/json',
// 'Authorization': authToken
// },
// body: JSON.stringify(row)
// })
//
// return {
// success: true,
// message: 'User updated successfully on example service',
// status: "upto date"
// }
// } catch (error) {
// return {
// success: false,
// message: 'User update failed on example service',
// }
// }
// checkout the documentation for more info: https://docs.rowy.io/field-types/action#script
}`;
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
// Example:
/*
const authToken = await rowy.secrets.get("service")
try {
const resp = await fetch('https://example.com/api/v1/users/'+ref.id,{
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': authToken
},
body: JSON.stringify(row)
})
return {
success: true,
message: 'User updated successfully on example service',
status: "upto date"
}
} catch (error) {
return {
success: false,
message: 'User update failed on example service',
}
}
*/
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`;
export const 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")
// try {
// const resp = await fetch('https://example.com/api/v1/users/'+ref.id,{
// method: 'DELETE',
// headers: {
// 'Content-Type': 'application/json',
// 'Authorization': authToken
// },
// body: JSON.stringify(row)
// })
//
// return {
// success: true,
// message: 'User deleted successfully on example service',
// status: null
// }
// } catch (error) {
// return {
// success: false,
// message: 'User delete failed on example service',
// }
// }
}`;
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
// Example:
/*
const authToken = await rowy.secrets.get("service")
try {
const resp = await fetch('https://example.com/api/v1/users/'+ref.id,{
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Authorization': authToken
},
body: JSON.stringify(row)
})
return {
success: true,
message: 'User deleted successfully on example service',
status: null
}
} catch (error) {
return {
success: false,
message: 'User delete failed on example service',
}
}
*/
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`;

View File

@@ -12,8 +12,10 @@ export const replacer = (data: any) => (m: string, key: string) => {
};
export const baseFunction = `const connectorFn: Connector = async ({query, row, user, logging}) => {
// TODO: Implement your service function here
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
return [];
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
};`;
export const getLabel = (config: any, row: TableRow) => {

View File

@@ -66,15 +66,19 @@ export default function Settings({
? config.derivativeFn
: config?.script
? `const derivative:Derivative = async ({row,ref,db,storage,auth,logging})=>{
${config.script.replace(/utilFns.getSecret/g, "rowy.secrets.get")}
}`
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
${config.script.replace(/utilFns.getSecret/g, "rowy.secrets.get")}
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`
: `const derivative:Derivative = async ({row,ref,db,storage,auth,logging})=>{
// Write your derivative code here
// for example:
// const sum = row.a + row.b;
// return sum;
// checkout the documentation for more info: https://docs.rowy.io/field-types/derivative
}`;
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
// Example:
// const sum = row.a + row.b;
// return sum;
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}`;
return (
<>

View File

@@ -22,6 +22,8 @@ import { getFieldProp } from "..";
/* eslint-disable import/no-webpack-loader-syntax */
import formulaDefs from "!!raw-loader!./formula.d.ts";
import { WIKI_LINKS } from "@src/constants/externalLinks";
import CodeEditorHelper from "@src/components/CodeEditor/CodeEditorHelper";
const CodeEditor = lazy(
() =>
@@ -97,28 +99,18 @@ export default function Settings({
<InputLabel>Formula script</InputLabel>
<div>
<Stack
direction="row"
alignItems="flex-start"
justifyItems="space-between"
justifyContent="space-between"
marginBottom={1}
>
<Typography variant="body2" color="textSecondary">
Available:
</Typography>
<Grid
container
spacing={1}
style={{ flexGrow: 1, marginTop: -8, marginLeft: 0 }}
>
<Grid item>
<Tooltip title="Current row's data">
<code>row</code>
</Tooltip>
</Grid>
</Grid>
</Stack>
<CodeEditorHelper
disableDefaultVariables
disableSecretManagerLink
disableCloudManagerLink
docLink={WIKI_LINKS.fieldTypesFormula}
additionalVariables={[
{
key: "row",
description: `Current row's data`,
},
]}
/>
<Suspense fallback={<FieldSkeleton height={200} />}>
<CodeEditor
diagnosticsOptions={diagnosticsOptions}

View File

@@ -66,10 +66,11 @@ export const outputFieldTypes = Object.values(FieldType).filter(
);
export const defaultFn = `const formula:Formula = async ({ row })=> {
// Write your formula code here
// for example:
// WRITE YOUR CODE ONLY BELOW THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
// Example:
// return row.a + row.b;
// checkout the documentation for more info: https://docs.rowy.io/field-types/formula
// WRITE YOUR CODE ONLY ABOVE THIS LINE. DO NOT WRITE CODE/COMMENTS OUTSIDE THE FUNCTION BODY
}
`;