From e4da6bcb068474e9ccf96579fc91e6a502cac93a Mon Sep 17 00:00:00 2001 From: Han Tuerker <46192266+htuerker@users.noreply.github.com> Date: Thu, 27 Oct 2022 10:09:00 +0300 Subject: [PATCH] Feat: Runtime options (#898) * feat(runtime-options): add runtime options, update rowy run github link * Update src/components/TableModals/ExtensionsModal/ExtensionList.tsx * Update src/components/TableModals/ExtensionsModal/RuntimeOptions.tsx --- .../ExtensionsModal/ExtensionsModal.tsx | 77 +++++++++--- .../ExtensionsModal/RuntimeOptions.tsx | 117 ++++++++++++++++++ .../TableModals/ExtensionsModal/utils.ts | 6 + src/constants/externalLinks.ts | 4 +- src/types/table.d.ts | 6 +- 5 files changed, 188 insertions(+), 22 deletions(-) create mode 100644 src/components/TableModals/ExtensionsModal/RuntimeOptions.tsx diff --git a/src/components/TableModals/ExtensionsModal/ExtensionsModal.tsx b/src/components/TableModals/ExtensionsModal/ExtensionsModal.tsx index 57f6fbee..3ae3d20b 100644 --- a/src/components/TableModals/ExtensionsModal/ExtensionsModal.tsx +++ b/src/components/TableModals/ExtensionsModal/ExtensionsModal.tsx @@ -23,7 +23,6 @@ import { } from "@src/atoms/tableScope"; import { useSnackLogContext } from "@src/contexts/SnackLogContext"; -import { emptyExtensionObject, IExtension, ExtensionType } from "./utils"; import { runRoutes } from "@src/constants/runRoutes"; import { analytics, logEvent } from "@src/analytics"; import { @@ -31,6 +30,14 @@ import { getTableBuildFunctionPathname, } from "@src/utils/table"; +import { + emptyExtensionObject, + IExtension, + ExtensionType, + IRuntimeOptions, +} from "./utils"; +import RuntimeOptions from "./RuntimeOptions"; + export default function ExtensionsModal({ onClose }: ITableModalProps) { const [currentUser] = useAtom(currentUserAtom, projectScope); const [rowyRun] = useAtom(rowyRunAtom, projectScope); @@ -39,12 +46,24 @@ export default function ExtensionsModal({ onClose }: ITableModalProps) { const [tableSchema] = useAtom(tableSchemaAtom, tableScope); const [updateTableSchema] = useAtom(updateTableSchemaAtom, tableScope); - const currentExtensionObjects = (tableSchema.extensionObjects ?? - []) as IExtension[]; const [localExtensionsObjects, setLocalExtensionsObjects] = useState( - currentExtensionObjects + tableSchema.extensionObjects ?? [] ); + const [localRuntimeOptions, setLocalRuntimeOptions] = useState( + tableSchema.runtimeOptions ?? {} + ); + + const errors = { + runtimeOptions: { + timeoutSeconds: !( + !!localRuntimeOptions.timeoutSeconds && + localRuntimeOptions.timeoutSeconds > 0 && + localRuntimeOptions.timeoutSeconds <= 540 + ), + }, + }; + const [openMigrationGuide, setOpenMigrationGuide] = useState(false); useEffect(() => { if (tableSchema.sparks) setOpenMigrationGuide(true); @@ -57,7 +76,9 @@ export default function ExtensionsModal({ onClose }: ITableModalProps) { } | null>(null); const snackLogContext = useSnackLogContext(); - const edited = !isEqual(currentExtensionObjects, localExtensionsObjects); + const edited = + !isEqual(tableSchema.extensionObjects ?? [], localExtensionsObjects) || + !isEqual(tableSchema.runtimeOptions ?? {}, localRuntimeOptions); const handleClose = ( _setOpen: React.Dispatch> @@ -70,7 +91,8 @@ export default function ExtensionsModal({ onClose }: ITableModalProps) { cancel: "Keep", handleConfirm: () => { _setOpen(false); - setLocalExtensionsObjects(currentExtensionObjects); + setLocalExtensionsObjects(tableSchema.extensionObjects ?? []); + setLocalRuntimeOptions(tableSchema.runtimeOptions ?? {}); onClose(); }, }); @@ -79,15 +101,18 @@ export default function ExtensionsModal({ onClose }: ITableModalProps) { } }; - const handleSaveExtensions = async (callback?: Function) => { + const handleSave = async (callback?: Function) => { if (updateTableSchema) - await updateTableSchema({ extensionObjects: localExtensionsObjects }); + await updateTableSchema({ + extensionObjects: localExtensionsObjects, + runtimeOptions: localRuntimeOptions, + }); if (callback) callback(); onClose(); }; const handleSaveDeploy = async () => { - handleSaveExtensions(() => { + handleSave(() => { try { snackLogContext.requestSnackLog(); rowyRun({ @@ -132,6 +157,13 @@ export default function ExtensionsModal({ onClose }: ITableModalProps) { setExtensionModal(null); }; + const handleUpdateRuntimeOptions = (update: IRuntimeOptions) => { + setLocalRuntimeOptions((runtimeOptions) => ({ + ...runtimeOptions, + ...update, + })); + }; + const handleUpdateActive = (index: number, active: boolean) => { setLocalExtensionsObjects( localExtensionsObjects.map((extensionObject, i) => { @@ -217,24 +249,31 @@ export default function ExtensionsModal({ onClose }: ITableModalProps) { /> } children={ - + <> + + + } actions={{ primary: { children: "Save & Deploy", onClick: handleSaveDeploy, - disabled: !edited, + disabled: !edited || errors.runtimeOptions.timeoutSeconds, }, secondary: { children: "Save", - onClick: () => handleSaveExtensions(), - disabled: !edited, + onClick: () => handleSave(), + disabled: !edited || errors.runtimeOptions.timeoutSeconds, }, }} /> diff --git a/src/components/TableModals/ExtensionsModal/RuntimeOptions.tsx b/src/components/TableModals/ExtensionsModal/RuntimeOptions.tsx new file mode 100644 index 00000000..90ca584c --- /dev/null +++ b/src/components/TableModals/ExtensionsModal/RuntimeOptions.tsx @@ -0,0 +1,117 @@ +import { useState } from "react"; +import { useAtom, useSetAtom } from "jotai"; + +import { + Accordion, + AccordionDetails, + AccordionSummary, + Button, + Grid, + InputAdornment, + TextField, + Typography, +} from "@mui/material"; +import { ChevronDown } from "@src/assets/icons"; +import MultiSelect from "@rowy/multiselect"; + +import { + compatibleRowyRunVersionAtom, + projectScope, + rowyRunModalAtom, +} from "@src/atoms/projectScope"; + +import { IRuntimeOptions } from "./utils"; + +export default function RuntimeOptions({ + runtimeOptions, + handleUpdate, + errors, +}: { + runtimeOptions: IRuntimeOptions; + handleUpdate: (runtimeOptions: IRuntimeOptions) => void; + errors: { timeoutSeconds: boolean }; +}) { + const [compatibleRowyRunVersion] = useAtom( + compatibleRowyRunVersionAtom, + projectScope + ); + const openRowyRunModal = useSetAtom(rowyRunModalAtom, projectScope); + + const [expanded, setExpanded] = useState(false); + + const isCompatibleRowyRun = compatibleRowyRunVersion({ minVersion: "1.6.4" }); + + return ( + + + ) : ( + + ) + } + onClick={() => + isCompatibleRowyRun + ? setExpanded(!expanded) + : openRowyRunModal({ + version: "1.6.4", + feature: "Runtime options", + }) + } + > + Runtime options + + + + + handleUpdate({ memory: value ?? "256MB" })} + multiple={false} + options={["128MB", "256MB", "512MB", "1GB", "2GB", "4GB", "8GB"]} + /> + + + + seconds + ), + }} + onChange={(e) => + !isNaN(Number(e.target.value)) && + handleUpdate({ + timeoutSeconds: Number(e.target.value), + }) + } + inputProps={{ + inputMode: "numeric", + }} + error={errors.timeoutSeconds} + helperText={ + errors.timeoutSeconds + ? "Timeout must be an integer between 1 and 540" + : "The maximum timeout that can be specified is 9 mins (540 seconds)" + } + /> + + + + + ); +} diff --git a/src/components/TableModals/ExtensionsModal/utils.ts b/src/components/TableModals/ExtensionsModal/utils.ts index 117ef381..28d24fda 100644 --- a/src/components/TableModals/ExtensionsModal/utils.ts +++ b/src/components/TableModals/ExtensionsModal/utils.ts @@ -52,6 +52,12 @@ export interface IExtension { trackedFields?: string[]; } +// https://firebase.google.com/docs/functions/manage-functions#set_runtime_options +export interface IRuntimeOptions { + memory?: "128MB" | "256MB" | "512MB" | "1GB" | "2GB" | "4GB" | "8GB"; + timeoutSeconds?: number; +} + export const triggerTypes: ExtensionTrigger[] = ["create", "update", "delete"]; const extensionBodyTemplate = { diff --git a/src/constants/externalLinks.ts b/src/constants/externalLinks.ts index bf2f41ab..4625d6ba 100644 --- a/src/constants/externalLinks.ts +++ b/src/constants/externalLinks.ts @@ -15,8 +15,8 @@ export const EXTERNAL_LINKS = { twitter: "https://twitter.com/rowyio", productHunt: "https://www.producthunt.com/products/rowy-2", - rowyRun: meta.repository.url.replace(".git", "Run"), - rowyRunGitHub: meta.repository.url.replace(".git", "Run"), + rowyRun: meta.repository.url.replace("rowy.git", "backend"), + rowyRunGitHub: meta.repository.url.replace("rowy.git", "backend"), // prettier-ignore rowyRunDeploy: `https://deploy.cloud.run/?git_repo=${meta.repository.url.replace(".git", "Run")}.git`, diff --git a/src/types/table.d.ts b/src/types/table.d.ts index 376cd3ea..dadbf2ab 100644 --- a/src/types/table.d.ts +++ b/src/types/table.d.ts @@ -4,7 +4,10 @@ import type { DocumentData, DocumentReference, } from "firebase/firestore"; -import { IExtension } from "@src/components/TableModals/ExtensionsModal/utils"; +import { + IExtension, + IRuntimeOptions, +} from "@src/components/TableModals/ExtensionsModal/utils"; import { IWebhook } from "@src/components/TableModals/WebhooksModal/utils"; /** @@ -104,6 +107,7 @@ export type TableSchema = { extensionObjects?: IExtension[]; compiledExtension?: string; webhooks?: IWebhook[]; + runtimeOptions?: IRuntimeOptions; /** @deprecated Migrate to Extensions */ sparks?: string;