From a305793c654e673cbd0352b7b3d06129279df3a6 Mon Sep 17 00:00:00 2001 From: d-g-town <66391417+d-g-town@users.noreply.github.com> Date: Fri, 29 Sep 2023 15:52:27 -0400 Subject: [PATCH] support allowConcurrency, suspendCron, and timeoutSeconds (#3686) Co-authored-by: David Townley --- dashboard/package-lock.json | 14 ++++----- dashboard/package.json | 2 +- dashboard/src/lib/porter-apps/services.ts | 31 ++++++++++++++----- .../services-settings/ServiceContainer.tsx | 2 +- .../services-settings/tabs/JobTabs.tsx | 15 ++++++++- .../services-settings/tabs/Main.tsx | 25 +++++++++++++-- go.mod | 2 +- go.sum | 4 +-- 8 files changed, 73 insertions(+), 22 deletions(-) diff --git a/dashboard/package-lock.json b/dashboard/package-lock.json index a48137de57..d6848b0c5d 100644 --- a/dashboard/package-lock.json +++ b/dashboard/package-lock.json @@ -13,7 +13,7 @@ "@loadable/component": "^5.15.2", "@material-ui/core": "^4.11.3", "@material-ui/lab": "^4.0.0-alpha.61", - "@porter-dev/api-contracts": "^0.2.1", + "@porter-dev/api-contracts": "^0.2.6", "@react-spring/web": "^9.6.1", "@sentry/react": "^6.13.2", "@sentry/tracing": "^6.13.2", @@ -2455,9 +2455,9 @@ } }, "node_modules/@porter-dev/api-contracts": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@porter-dev/api-contracts/-/api-contracts-0.2.1.tgz", - "integrity": "sha512-YNXlmHwoLOft1q3FEKoAOCa73t8wz0sG9DYMs7+lModWK/kljts1COculJEVs9e/CzkCs4rxTXSX4lH2BnDX2w==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@porter-dev/api-contracts/-/api-contracts-0.2.6.tgz", + "integrity": "sha512-IxwcsqQOZs8EfP3K9wzTArhR5y2vZUBEh6YRiXZD/73ORObN4bWI3eRQz39J0TQt5p/D00J8Dqo01nN9QY8rcA==", "dependencies": { "@bufbuild/protobuf": "^1.1.0" } @@ -16956,9 +16956,9 @@ "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" }, "@porter-dev/api-contracts": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@porter-dev/api-contracts/-/api-contracts-0.2.1.tgz", - "integrity": "sha512-YNXlmHwoLOft1q3FEKoAOCa73t8wz0sG9DYMs7+lModWK/kljts1COculJEVs9e/CzkCs4rxTXSX4lH2BnDX2w==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@porter-dev/api-contracts/-/api-contracts-0.2.6.tgz", + "integrity": "sha512-IxwcsqQOZs8EfP3K9wzTArhR5y2vZUBEh6YRiXZD/73ORObN4bWI3eRQz39J0TQt5p/D00J8Dqo01nN9QY8rcA==", "requires": { "@bufbuild/protobuf": "^1.1.0" } diff --git a/dashboard/package.json b/dashboard/package.json index d6df94755c..625621bbdc 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -8,7 +8,7 @@ "@loadable/component": "^5.15.2", "@material-ui/core": "^4.11.3", "@material-ui/lab": "^4.0.0-alpha.61", - "@porter-dev/api-contracts": "^0.2.1", + "@porter-dev/api-contracts": "^0.2.6", "@react-spring/web": "^9.6.1", "@sentry/react": "^6.13.2", "@sentry/tracing": "^6.13.2", diff --git a/dashboard/src/lib/porter-apps/services.ts b/dashboard/src/lib/porter-apps/services.ts index 845e19fb2e..2e1729dd62 100644 --- a/dashboard/src/lib/porter-apps/services.ts +++ b/dashboard/src/lib/porter-apps/services.ts @@ -50,8 +50,10 @@ export const serviceValidator = z.object({ }), z.object({ type: z.literal("job"), - allowConcurrent: serviceBooleanValidator, + allowConcurrent: serviceBooleanValidator.optional(), cron: serviceStringValidator, + suspendCron: serviceBooleanValidator.optional(), + timeoutSeconds: serviceNumberValidator }), z.object({ type: z.literal("predeploy"), @@ -86,8 +88,10 @@ export type SerializedService = { } | { type: "job"; - allowConcurrent: boolean; + allowConcurrent?: boolean; cron: string; + suspendCron?: boolean; + timeoutSeconds: number; } | { type: "predeploy"; @@ -158,6 +162,8 @@ export function defaultSerialized({ type: "job" as const, allowConcurrent: false, cron: "", + suspendCron: false, + timeoutSeconds: 3600, }, })) .with("predeploy", () => ({ @@ -221,8 +227,10 @@ export function serializeService(service: ClientService): SerializedService { ramMegabytes: service.ramMegabytes.value, config: { type: "job" as const, - allowConcurrent: config.allowConcurrent.value, + allowConcurrent: config.allowConcurrent?.value, cron: config.cron.value, + suspendCron: config.suspendCron?.value, + timeoutSeconds: config.timeoutSeconds.value, }, }) ) @@ -326,11 +334,18 @@ export function deserializeService({ ...baseService, config: { type: "job" as const, - allowConcurrent: ServiceField.boolean( - config.allowConcurrent, - overrideJobConfig?.allowConcurrent - ), + allowConcurrent: + typeof config.allowConcurrent === "boolean" || + typeof overrideJobConfig?.allowConcurrent === "boolean" + ? ServiceField.boolean(config.allowConcurrent, overrideJobConfig?.allowConcurrent) + : ServiceField.boolean(false, undefined), cron: ServiceField.string(config.cron, overrideJobConfig?.cron), + suspendCron: + typeof config.suspendCron === "boolean" || + typeof overrideJobConfig?.suspendCron === "boolean" + ? ServiceField.boolean(config.suspendCron, overrideJobConfig?.suspendCron) + : ServiceField.boolean(false, undefined), + timeoutSeconds: config.timeoutSeconds == 0 ? ServiceField.number(3600, overrideJobConfig?.timeoutSeconds) : ServiceField.number(config.timeoutSeconds, overrideJobConfig?.timeoutSeconds), }, }; }) @@ -394,6 +409,7 @@ export function serviceProto(service: SerializedService): Service { config: { value: { ...config, + allowConcurrentOptional: config.allowConcurrent, }, case: "jobConfig", }, @@ -456,6 +472,7 @@ export function serializedServiceFromProto({ config: { type: isPredeploy ? ("predeploy" as const) : ("job" as const), ...value, + allowConcurrent: value.allowConcurrentOptional }, })) .exhaustive(); diff --git a/dashboard/src/main/home/app-dashboard/validate-apply/services-settings/ServiceContainer.tsx b/dashboard/src/main/home/app-dashboard/validate-apply/services-settings/ServiceContainer.tsx index 22ac76a3dc..03d7be22f3 100644 --- a/dashboard/src/main/home/app-dashboard/validate-apply/services-settings/ServiceContainer.tsx +++ b/dashboard/src/main/home/app-dashboard/validate-apply/services-settings/ServiceContainer.tsx @@ -114,7 +114,7 @@ const ServiceContainer: React.FC = ({ if (data) { let largestInstanceType = { vCPUs: 2, - RAM: 4294, + RAM: 4, }; data.forEach((node: any) => { diff --git a/dashboard/src/main/home/app-dashboard/validate-apply/services-settings/tabs/JobTabs.tsx b/dashboard/src/main/home/app-dashboard/validate-apply/services-settings/tabs/JobTabs.tsx index 11d8969f59..9ff74d51d8 100644 --- a/dashboard/src/main/home/app-dashboard/validate-apply/services-settings/tabs/JobTabs.tsx +++ b/dashboard/src/main/home/app-dashboard/validate-apply/services-settings/tabs/JobTabs.tsx @@ -11,6 +11,7 @@ import MainTab from "./Main"; import Resources from "./Resources"; import { Controller, useFormContext } from "react-hook-form"; import { PorterAppFormData } from "lib/porter-apps"; +import {ControlledInput} from "../../../../../../components/porter/ControlledInput"; interface Props { index: number; @@ -32,7 +33,7 @@ const JobTabs: React.FC = ({ maxCPU, isPredeploy, }) => { - const { control } = useFormContext(); + const { control, register } = useFormContext(); const [currentTab, setCurrentTab] = React.useState< "main" | "resources" | "advanced" >("main"); @@ -90,6 +91,18 @@ const JobTabs: React.FC = ({ )} /> + + )) .exhaustive()} diff --git a/dashboard/src/main/home/app-dashboard/validate-apply/services-settings/tabs/Main.tsx b/dashboard/src/main/home/app-dashboard/validate-apply/services-settings/tabs/Main.tsx index 64d86d7fdb..43c2f24738 100644 --- a/dashboard/src/main/home/app-dashboard/validate-apply/services-settings/tabs/Main.tsx +++ b/dashboard/src/main/home/app-dashboard/validate-apply/services-settings/tabs/Main.tsx @@ -1,6 +1,6 @@ import React, { useCallback } from "react"; import cronstrue from "cronstrue"; -import { useFormContext } from "react-hook-form"; +import {Controller, useFormContext} from "react-hook-form"; import { ControlledInput } from "components/porter/ControlledInput"; import Spacer from "components/porter/Spacer"; @@ -8,6 +8,7 @@ import { PorterAppFormData } from "lib/porter-apps"; import { ClientService } from "lib/porter-apps/services"; import Text from "components/porter/Text"; import Link from "components/porter/Link"; +import Checkbox from "components/porter/Checkbox"; type MainTabProps = { index: number; @@ -16,7 +17,7 @@ type MainTabProps = { }; const MainTab: React.FC = ({ index, service, isPredeploy = false }) => { - const { register, watch } = useFormContext(); + const { register, control, watch } = useFormContext(); const cron = watch(`app.services.${index}.config.cron.value`); const getScheduleDescription = useCallback((cron: string) => { @@ -62,8 +63,28 @@ const MainTab: React.FC = ({ index, service, isPredeploy = false } } {...register(`app.services.${index}.config.cron.value`)} /> + {getScheduleDescription(cron)} + + ( + { + onChange(!value); + }} + disabledTooltip={ + "You may only edit this field in your porter.yaml." + } + > + Suspend cron job + + )} + /> )} diff --git a/go.mod b/go.mod index 53d11417c0..b6e43cb59b 100644 --- a/go.mod +++ b/go.mod @@ -82,7 +82,7 @@ require ( github.com/matryer/is v1.4.0 github.com/nats-io/nats.go v1.24.0 github.com/open-policy-agent/opa v0.44.0 - github.com/porter-dev/api-contracts v0.2.5 + github.com/porter-dev/api-contracts v0.2.6 github.com/riandyrn/otelchi v0.5.1 github.com/santhosh-tekuri/jsonschema/v5 v5.0.1 github.com/stefanmcshane/helm v0.0.0-20221213002717-88a4a2c6e77d diff --git a/go.sum b/go.sum index 21fe513e17..b5ea2a2421 100644 --- a/go.sum +++ b/go.sum @@ -1516,8 +1516,8 @@ github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/polyfloyd/go-errorlint v0.0.0-20210722154253-910bb7978349/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw= -github.com/porter-dev/api-contracts v0.2.5 h1:2ZSnjnDLKtGPrjk1rfP7KajxCJtEiTpbmAMgs6z+NhM= -github.com/porter-dev/api-contracts v0.2.5/go.mod h1:fX6JmP5QuzxDLvqP3evFOTXjI4dHxsG0+VKNTjImZU8= +github.com/porter-dev/api-contracts v0.2.6 h1:5Z/Qr1Qv6iAM4rCUfpa9+HougO8K2HFjGOeSLDZFfDw= +github.com/porter-dev/api-contracts v0.2.6/go.mod h1:fX6JmP5QuzxDLvqP3evFOTXjI4dHxsG0+VKNTjImZU8= github.com/porter-dev/switchboard v0.0.3 h1:dBuYkiVLa5Ce7059d6qTe9a1C2XEORFEanhbtV92R+M= github.com/porter-dev/switchboard v0.0.3/go.mod h1:xSPzqSFMQ6OSbp42fhCi4AbGbQbsm6nRvOkrblFeXU4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=