Просмотр исходного кода

Jobs will not run on every deploy anymore (#3254)

Feroze Mohideen 2 лет назад
Родитель
Сommit
fdc8e4da2b

+ 5 - 5
cli/cmd/stack/apply.go

@@ -59,7 +59,7 @@ func CreateV1BuildResources(client *api.Client, raw []byte, stackName string, pr
 
 	v1File.Resources = append(v1File.Resources, bi, pi)
 
-	release, cmd, err := createReleaseResource(client,
+	preDeploy, cmd, err := createPreDeployResource(client,
 		stackConf.parsed.Release,
 		stackConf.stackName,
 		bi.Name,
@@ -72,11 +72,11 @@ func CreateV1BuildResources(client *api.Client, raw []byte, stackName string, pr
 		return nil, "", err
 	}
 
-	if release != nil {
-		color.New(color.FgYellow).Printf("Found release command to run before deploying apps: %s \n", cmd)
-		v1File.Resources = append(v1File.Resources, release)
+	if preDeploy != nil {
+		color.New(color.FgYellow).Printf("Found pre-deploy command to run before deploying apps: %s \n", cmd)
+		v1File.Resources = append(v1File.Resources, preDeploy)
 	} else {
-		color.New(color.FgYellow).Printf("No release command found in porter.yaml or helm. \n")
+		color.New(color.FgYellow).Printf("No pre-deploy command found in porter.yaml or helm. \n")
 	}
 
 	return v1File, builder, nil

+ 3 - 3
cli/cmd/stack/release.go → cli/cmd/stack/preDeploy.go

@@ -12,12 +12,12 @@ import (
 	switchboardTypes "github.com/porter-dev/switchboard/pkg/types"
 )
 
-func createReleaseResource(client *api.Client, release *App, stackName, buildResourceName, pushResourceName string, projectID, clusterID uint, env map[string]string) (*switchboardTypes.Resource, string, error) {
+func createPreDeployResource(client *api.Client, release *App, stackName, buildResourceName, pushResourceName string, projectID, clusterID uint, env map[string]string) (*switchboardTypes.Resource, string, error) {
 	var finalCmd string
 	if release != nil && release.Run != nil {
 		finalCmd = *release.Run
 	} else {
-		finalCmd = getReleaseCommandFromRelease(client, stackName, projectID, clusterID)
+		finalCmd = getPredeployStartCommandFromRelease(client, stackName, projectID, clusterID)
 		if finalCmd == "" {
 			return nil, "", nil
 		}
@@ -64,7 +64,7 @@ func createReleaseResource(client *api.Client, release *App, stackName, buildRes
 	}, finalCmd, nil
 }
 
-func getReleaseCommandFromRelease(client *api.Client, stackName string, projectID uint, clusterID uint) string {
+func getPredeployStartCommandFromRelease(client *api.Client, stackName string, projectID uint, clusterID uint) string {
 	namespace := fmt.Sprintf("porter-stack-%s", stackName)
 	releaseName := fmt.Sprintf("%s-r", stackName)
 	release, err := client.GetRelease(

+ 39 - 22
dashboard/package-lock.json

@@ -37,7 +37,6 @@
         "core-js": "^3.16.1",
         "cron-parser": "^4.3.0",
         "cron-validator": "^1.3.1",
-        "cronstrue": "^2.2.0",
         "d3-array": "^2.11.0",
         "d3-time-format": "^3.0.0",
         "dayjs": "^1.11.5",
@@ -117,6 +116,7 @@
         "babel-loader": "^8.2.2",
         "babel-plugin-lodash": "^3.3.4",
         "babel-plugin-styled-components": "^1.13.3",
+        "cronstrue": "^2.28.0",
         "css-loader": "^5.2.6",
         "file-loader": "^6.1.0",
         "html-webpack-plugin": "^4.5.0",
@@ -5636,9 +5636,10 @@
       "integrity": "sha512-C1HsxuPCY/5opR55G5/WNzyEGDWFVG+6GLrA+fW/sCTcP6A6NTjUP2AK7B8n2PyFs90kDG2qzwm8LMheADku6A=="
     },
     "node_modules/cronstrue": {
-      "version": "2.23.0",
-      "resolved": "https://registry.npmjs.org/cronstrue/-/cronstrue-2.23.0.tgz",
-      "integrity": "sha512-iPoWUQbCwUmrBf1w9W+9YQs8FowWp/teC2XGz3zAmt0Aja+HWGjyjUkWASWcsdzxSuL0EIIdvlfGEVBljvTbSQ==",
+      "version": "2.28.0",
+      "resolved": "https://registry.npmjs.org/cronstrue/-/cronstrue-2.28.0.tgz",
+      "integrity": "sha512-yByAR5on9i/p26djiSve4l29/AJkjCFDgopq+3gUVrQh2xgb3KKScofwkpf5XcRhuWAX0u0EuEK2nltB5hV1jQ==",
+      "dev": true,
       "bin": {
         "cronstrue": "bin/cli.js"
       }
@@ -16425,7 +16426,8 @@
     "@icons/material": {
       "version": "0.2.4",
       "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz",
-      "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw=="
+      "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==",
+      "requires": {}
     },
     "@ironplans/api": {
       "version": "0.4.1",
@@ -16605,7 +16607,8 @@
     "@material-ui/types": {
       "version": "5.1.0",
       "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz",
-      "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A=="
+      "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==",
+      "requires": {}
     },
     "@material-ui/utils": {
       "version": "4.11.3",
@@ -16920,7 +16923,8 @@
       "version": "7.2.1",
       "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-7.2.1.tgz",
       "integrity": "sha512-oZ0Ib5I4Z2pUEcoo95cT1cr6slco9WY7yiPpG+RGNkj8YcYgJnM7pXmYmorNOReh8MIGcKSqXyeGjxnr8YiZbA==",
-      "dev": true
+      "dev": true,
+      "requires": {}
     },
     "@types/body-parser": {
       "version": "1.19.2",
@@ -18137,13 +18141,15 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
       "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==",
-      "dev": true
+      "dev": true,
+      "requires": {}
     },
     "ajv-keywords": {
       "version": "3.5.2",
       "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
       "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
-      "dev": true
+      "dev": true,
+      "requires": {}
     },
     "anser": {
       "version": "2.1.1",
@@ -19439,9 +19445,10 @@
       "integrity": "sha512-C1HsxuPCY/5opR55G5/WNzyEGDWFVG+6GLrA+fW/sCTcP6A6NTjUP2AK7B8n2PyFs90kDG2qzwm8LMheADku6A=="
     },
     "cronstrue": {
-      "version": "2.23.0",
-      "resolved": "https://registry.npmjs.org/cronstrue/-/cronstrue-2.23.0.tgz",
-      "integrity": "sha512-iPoWUQbCwUmrBf1w9W+9YQs8FowWp/teC2XGz3zAmt0Aja+HWGjyjUkWASWcsdzxSuL0EIIdvlfGEVBljvTbSQ=="
+      "version": "2.28.0",
+      "resolved": "https://registry.npmjs.org/cronstrue/-/cronstrue-2.28.0.tgz",
+      "integrity": "sha512-yByAR5on9i/p26djiSve4l29/AJkjCFDgopq+3gUVrQh2xgb3KKScofwkpf5XcRhuWAX0u0EuEK2nltB5hV1jQ==",
+      "dev": true
     },
     "cross-spawn": {
       "version": "6.0.5",
@@ -21079,7 +21086,8 @@
     "goober": {
       "version": "2.1.12",
       "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.12.tgz",
-      "integrity": "sha512-yXHAvO08FU1JgTXX6Zn6sYCUFfB/OJSX8HHjDSgerZHZmFKAb08cykp5LBw5QnmyMcZyPRMqkdyHUSSzge788Q=="
+      "integrity": "sha512-yXHAvO08FU1JgTXX6Zn6sYCUFfB/OJSX8HHjDSgerZHZmFKAb08cykp5LBw5QnmyMcZyPRMqkdyHUSSzge788Q==",
+      "requires": {}
     },
     "good-listener": {
       "version": "1.2.2",
@@ -21465,7 +21473,8 @@
       "version": "5.1.0",
       "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
       "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
-      "dev": true
+      "dev": true,
+      "requires": {}
     },
     "ieee754": {
       "version": "1.2.1",
@@ -22342,7 +22351,8 @@
     "markdown-to-jsx": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.2.0.tgz",
-      "integrity": "sha512-3l4/Bigjm4bEqjCR6Xr+d4DtM1X6vvtGsMGSjJYyep8RjjIvcWtrXBS8Wbfe1/P+atKNMccpsraESIaWVplzVg=="
+      "integrity": "sha512-3l4/Bigjm4bEqjCR6Xr+d4DtM1X6vvtGsMGSjJYyep8RjjIvcWtrXBS8Wbfe1/P+atKNMccpsraESIaWVplzVg==",
+      "requires": {}
     },
     "material-colors": {
       "version": "1.2.6",
@@ -23260,7 +23270,8 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
       "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
-      "dev": true
+      "dev": true,
+      "requires": {}
     },
     "postcss-modules-local-by-default": {
       "version": "4.0.0",
@@ -23557,7 +23568,8 @@
     "react-animate-height": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/react-animate-height/-/react-animate-height-3.1.1.tgz",
-      "integrity": "sha512-UkC6+V3ZlCneBRaSM7aUctDJ+PRP6ztcGtxvU7MTeoMMWPhz8BQNaX7QWaZrkzp1ih1G8uZZ+DI9nfLvtD6OdQ=="
+      "integrity": "sha512-UkC6+V3ZlCneBRaSM7aUctDJ+PRP6ztcGtxvU7MTeoMMWPhz8BQNaX7QWaZrkzp1ih1G8uZZ+DI9nfLvtD6OdQ==",
+      "requires": {}
     },
     "react-beautiful-dnd": {
       "version": "13.1.1",
@@ -23676,7 +23688,8 @@
     "react-onclickoutside": {
       "version": "6.12.2",
       "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.12.2.tgz",
-      "integrity": "sha512-NMXGa223OnsrGVp5dJHkuKxQ4czdLmXSp5jSV9OqiCky9LOpPATn3vLldc+q5fK3gKbEHvr7J1u0yhBh/xYkpA=="
+      "integrity": "sha512-NMXGa223OnsrGVp5dJHkuKxQ4czdLmXSp5jSV9OqiCky9LOpPATn3vLldc+q5fK3gKbEHvr7J1u0yhBh/xYkpA==",
+      "requires": {}
     },
     "react-popper": {
       "version": "2.3.0",
@@ -23748,7 +23761,8 @@
     "react-table": {
       "version": "7.8.0",
       "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz",
-      "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA=="
+      "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==",
+      "requires": {}
     },
     "react-transition-group": {
       "version": "4.4.5",
@@ -25530,12 +25544,14 @@
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz",
       "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==",
-      "dev": true
+      "dev": true,
+      "requires": {}
     },
     "use-sync-external-store": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
-      "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA=="
+      "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
+      "requires": {}
     },
     "util": {
       "version": "0.11.1",
@@ -26829,7 +26845,8 @@
       "version": "7.5.9",
       "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
       "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
-      "dev": true
+      "dev": true,
+      "requires": {}
     },
     "xtend": {
       "version": "4.0.2",

+ 1 - 1
dashboard/package.json

@@ -32,7 +32,6 @@
     "core-js": "^3.16.1",
     "cron-parser": "^4.3.0",
     "cron-validator": "^1.3.1",
-    "cronstrue": "^2.2.0",
     "d3-array": "^2.11.0",
     "d3-time-format": "^3.0.0",
     "dayjs": "^1.11.5",
@@ -118,6 +117,7 @@
     "babel-loader": "^8.2.2",
     "babel-plugin-lodash": "^3.3.4",
     "babel-plugin-styled-components": "^1.13.3",
+    "cronstrue": "^2.28.0",
     "css-loader": "^5.2.6",
     "file-loader": "^6.1.0",
     "html-webpack-plugin": "^4.5.0",

+ 1 - 1
dashboard/src/components/CloudFormationForm.tsx

@@ -178,7 +178,7 @@ const CloudFormationForm: React.FC<Props> = ({
                       <i
                         className="material-icons"
                         onClick={() => {
-                          window.open("https://console.aws.amazon.com/billing/home?region=us-east-1#/account", "_blank")
+                          window.open("https://docs.aws.amazon.com/IAM/latest/UserGuide/FindingYourAWSId.html", "_blank")
                         }}
                       >
                         help_outline

+ 2 - 1
dashboard/src/main/home/app-dashboard/expanded-app/ExpandedApp.tsx

@@ -492,6 +492,7 @@ const ExpandedApp: React.FC<Props> = ({ ...props }) => {
         setPorterApp(tempPorterApp);
         setButtonStatus("success");
         setShowUnsavedChangesBanner(false);
+        getPorterApp({ revision: 0 });
       } else {
         setButtonStatus(<Error message="Unable to update app" />);
       }
@@ -666,7 +667,7 @@ const ExpandedApp: React.FC<Props> = ({ ...props }) => {
   };
 
   const setRevision = (chart: ChartType, isCurrent?: boolean) => {
-    getPorterApp({ revision: chart.version });
+    getPorterApp({ revision: isCurrent ? 0 : chart.version });
   };
 
   const getReadableDate = (s: string) => {

+ 3 - 2
dashboard/src/main/home/app-dashboard/expanded-app/logs/utils.ts

@@ -297,7 +297,6 @@ export const useLogs = (
     setLoading(true);
     setLogs([]);
     flushLogsBuffer(true);
-    const websocketKey = `${currentPod}-${namespace}-websocket`;
     const endDate = timeRange?.endTime != null ? timeRange.endTime : dayjs(setDate);
     const oneDayAgo = timeRange?.startTime != null ? timeRange.startTime : endDate.subtract(1, "day");
 
@@ -320,7 +319,9 @@ export const useLogs = (
       );
     }
 
-    closeWebsocket(websocketKey);
+    closeAllWebsockets();
+    const suffix = Math.random().toString(36).substring(2, 15);
+    const websocketKey = `${currentPod}-${namespace}-websocket-${suffix}`;
 
     setLoading(false);
 

+ 10 - 3
dashboard/src/main/home/app-dashboard/expanded-app/status/ControllerTab.tsx

@@ -89,6 +89,10 @@ const ControllerTabFC: React.FunctionComponent<Props> = ({
     () => closeAllWebsockets();
   }, [currentSelectors, controller, currentCluster, currentProject]);
 
+  useEffect(() => {
+    return () => closeAllWebsockets();
+  }, [])
+
   const updatePods = async () => {
     try {
       const res = await api.getMatchingPods(
@@ -322,9 +326,12 @@ const ControllerTabFC: React.FunctionComponent<Props> = ({
       }
 
       if (event.Kind != "pod") {
-        let [available, total] = getAvailability(object.metadata.kind, object);
-        setAvailable(available);
-        setTotal(total);
+        const availability = getAvailability(object.metadata.kind, object);
+        if (availability != null) {
+          let [available, total] = availability;
+          setAvailable(available);
+          setTotal(total);
+        }
         return;
       }
       updatePods();

+ 23 - 2
dashboard/src/main/home/app-dashboard/new-app-flow/JobTabs.tsx

@@ -6,6 +6,8 @@ import TabSelector from "components/TabSelector";
 import Checkbox from "components/porter/Checkbox";
 import { JobService } from "./serviceTypes";
 import { Height } from "react-animate-height";
+import cronstrue from 'cronstrue';
+import Link from "components/porter/Link";
 
 interface Props {
   service: JobService;
@@ -20,6 +22,23 @@ const JobTabs: React.FC<Props> = ({
 }) => {
   const [currentTab, setCurrentTab] = React.useState<string>('main');
 
+  const getScheduleDescription = () => {
+    try {
+      return <Text color="helper">This job runs: {cronstrue.toString(service.cronSchedule.value)}</Text>;
+    } catch (err) {
+      return <Text color="helper">
+        Invalid cron schedule.{" "}
+        <Link
+          to={"https://crontab.cronhub.io/"}
+          hasunderline
+          target="_blank"
+        >
+          Need help?
+        </Link>
+      </Text>;
+    }
+  }
+
   const renderMain = () => {
     return (
       <>
@@ -35,7 +54,7 @@ const JobTabs: React.FC<Props> = ({
         />
         <Spacer y={1} />
         <Input
-          label="Cron schedule (leave blank to run manually)"
+          label="Cron schedule"
           placeholder="ex: */5 * * * *"
           value={service.cronSchedule.value}
           disabled={service.cronSchedule.readOnly}
@@ -43,6 +62,8 @@ const JobTabs: React.FC<Props> = ({
           setValue={(e) => { editService({ ...service, cronSchedule: { readOnly: false, value: e } }) }}
           disabledTooltip={"You may only edit this field in your porter.yaml."}
         />
+        <Spacer y={0.5} />
+        {getScheduleDescription()}
       </>
     )
   };
@@ -101,7 +122,7 @@ const JobTabs: React.FC<Props> = ({
         currentTab={currentTab}
         setCurrentTab={(value: string) => {
           if (value === 'main') {
-            setHeight(244);
+            setHeight(276);
           } else if (value === 'resources') {
             setHeight(244);
           } else if (value === 'advanced') {

+ 12 - 9
dashboard/src/main/home/app-dashboard/new-app-flow/NewAppFlow.tsx

@@ -167,6 +167,7 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
 
   useEffect(() => {
     setFormState({ ...formState, serviceList: [] });
+    setDetected(undefined);
   }, [porterApp.git_branch]);
 
   const handleSetAccessData = (data: GithubAppAccessData) => {
@@ -321,16 +322,10 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
 
       const yamlString = yaml.dump(finalPorterYaml);
       const base64Encoded = btoa(yamlString);
-      let imageInfo = {
+      const imageInfo = {
         repository: "",
         tag: "",
       };
-      if (porterApp.image_repo_uri && imageTag) {
-        imageInfo = {
-          repository: porterApp.image_repo_uri,
-          tag: imageTag,
-        };
-      }
 
       const porterAppRequest = {
         porter_yaml: base64Encoded,
@@ -348,7 +343,15 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
         env_groups: syncedEnvGroups?.map((env: PopulatedEnvGroup) => env.name),
         user_update: true,
       }
-      if (buildView === "docker") {
+      if (porterApp.image_repo_uri && imageTag) {
+        porterAppRequest.image_info = {
+          repository: porterApp.image_repo_uri,
+          tag: imageTag,
+        };
+        porterAppRequest.repo_name = "";
+        porterAppRequest.git_branch = "";
+        porterAppRequest.git_repo_id = 0;
+      } else if (buildView === "docker") {
         porterAppRequest.dockerfile = porterApp.dockerfile;
       } else {
         porterAppRequest.builder = porterApp.builder;
@@ -365,7 +368,7 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
         }
       );
 
-      if (porterApp.repo_name === "") {
+      if (porterAppRequest.repo_name === "") {
         props.history.push(`/apps/${porterApp.name}`);
       }
 

+ 1 - 1
dashboard/src/main/home/app-dashboard/new-app-flow/Services.tsx

@@ -135,7 +135,7 @@ const Services: React.FC<ServicesProps> = ({
               options={[
                 { label: "Web", value: "web" },
                 { label: "Worker", value: "worker" },
-                { label: "Job", value: "job" },
+                { label: "Cron Job", value: "job" },
               ]}
             />
           </Container>

+ 6 - 8
dashboard/src/main/home/app-dashboard/new-app-flow/serviceTypes.ts

@@ -300,16 +300,10 @@ const JobService = {
         startCommand: ServiceField.string('', porterJson?.apps?.[name]?.run),
         type: 'job',
         jobsExecuteConcurrently: ServiceField.boolean(false, porterJson?.apps?.[name]?.config?.allowConcurrent),
-        cronSchedule: ServiceField.string('', porterJson?.apps?.[name]?.config?.schedule?.value),
+        cronSchedule: ServiceField.string('*/10 * * * *', porterJson?.apps?.[name]?.config?.schedule?.value),
         canDelete: porterJson?.apps?.[name] == null,
     }),
     serialize: (service: JobService) => {
-        const schedule = service.cronSchedule.value ? {
-            schedule: {
-                enabled: true,
-                value: service.cronSchedule.value,
-            }
-        } : {};
         return {
             allowConcurrent: service.jobsExecuteConcurrently.value,
             container: {
@@ -321,7 +315,11 @@ const JobService = {
                     memory: service.ram.value + 'Mi',
                 }
             },
-            ...schedule,
+            schedule: {
+                enabled: service.cronSchedule.value ? true : false,
+                value: service.cronSchedule.value,
+            },
+            paused: true,
         }
     },
     deserialize: (name: string, values: any, porterJson?: PorterJson): JobService => {

+ 2 - 2
dashboard/src/main/home/cluster-dashboard/expanded-chart/RevisionSection.tsx

@@ -90,7 +90,7 @@ class RevisionSection extends Component<PropsType, StateType> {
     const ws = new WebSocket(`${url}${apiPath}`);
 
     ws.onopen = () => {
-      // console.log("connected to chart live updates websocket");
+      console.log("connected to chart live updates websocket");
     };
 
     ws.onmessage = (evt: MessageEvent) => {
@@ -119,7 +119,7 @@ class RevisionSection extends Component<PropsType, StateType> {
               return { ...prevState, revisions: [object, ...prevRevisions] };
             }
 
-            return { ...prevState, revisions: prevRevisions };
+            return { ...prevState, revisions: prevRevisions, maxVersion: Math.max(...prevRevisions.map(rev => rev.version)) };
           },
           () => {
             this.props.setRevision(this.state.revisions[0], true);