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

broken: Implementing useChart deep functions for RUD operations

jnfrati 4 лет назад
Родитель
Сommit
8ecc08c950

+ 326 - 9
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedJobChart.tsx

@@ -31,13 +31,14 @@ import ValuesYaml from "./ValuesYaml";
 import DeploymentType from "./DeploymentType";
 import Modal from "main/home/modals/Modal";
 import UpgradeChartModal from "main/home/modals/UpgradeChartModal";
-import { pushFiltered } from "../../../../shared/routing";
+import { pushFiltered, useRouting } from "../../../../shared/routing";
 import { RouteComponentProps, useRouteMatch, withRouter } from "react-router";
 import KeyValueArray from "components/form-components/KeyValueArray";
 import RevisionSection from "./RevisionSection";
 import { onlyInLeft } from "shared/array_utils";
 import Loading from "components/Loading";
 import { NewWebsocketOptions, useWebsockets } from "shared/hooks/useWebsockets";
+import JobList from "./jobs/JobList";
 
 type PropsType = WithAuthProps &
   RouteComponentProps & {
@@ -619,7 +620,7 @@ class ExpandedJobChart extends Component<PropsType, StateType> {
   //   return chartStatus;
   // };
 
-  renderTabContents = (currentTab: string, submitValues?: any) => {
+  renderTabContents = (currentTab: string) => {
     switch (currentTab) {
       case "jobs":
         if (this.state.imageIsPlaceholder) {
@@ -1105,26 +1106,253 @@ ExpandedJobChart.contextType = Context;
 
 export default withRouter(withAuth(ExpandedJobChart));
 
-const ExpandedJobChartFC = () => {
-  const { chart, loading: isLoadingChart } = useChart();
+const ExpandedJobChartFC: React.FC<PropsType> = ({
+  currentChart: oldChart,
+  closeChart,
+  isAuthorized,
+  currentCluster,
+}) => {
+  const { setCurrentOverlay } = useContext(Context);
+  const {
+    chart,
+    loading: isLoadingChart,
+    refreshChart,
+    deleteChart,
+    updateChart,
+    upgradeChart,
+  } = useChart(oldChart);
   const { jobs, hasPorterImageTemplate } = useJobs(chart);
+  const [devOpsMode, setDevOpsMode] = useState(
+    () => localStorage.getItem("devOpsMode") === "true"
+  );
 
   if (isLoadingChart) {
     return <Loading />;
   }
 
-  useEffect(() => {}, []);
+  const formData = chart.form;
+
+  const readableDate = (s: string) => {
+    let ts = new Date(s);
+    let date = ts.toLocaleDateString();
+    let time = ts.toLocaleTimeString([], {
+      hour: "numeric",
+      minute: "2-digit",
+    });
+    return `${time} on ${date}`;
+  };
+
+  let rightTabOptions = [] as any[];
+
+  if (devOpsMode) {
+    rightTabOptions.push({ label: "Helm Values", value: "values" });
+  }
+
+  if (isAuthorized("job", "", ["get", "delete"])) {
+    rightTabOptions.push({ label: "Settings", value: "settings" });
+  }
+
+  const leftTabOptions = [{ label: "Jobs", value: "jobs" }];
 
-  return null;
+  const renderTabContents = (currentTab: string) => {
+    switch (currentTab) {
+      case "jobs":
+        if (hasPorterImageTemplate) {
+          return (
+            <Placeholder>
+              <TextWrap>
+                <Header>
+                  <Spinner src={loading} /> This job is currently being deployed
+                </Header>
+                Navigate to the
+                <A
+                  href={`https://github.com/${this.props.currentChart?.git_action_config?.git_repo}/actions`}
+                  target={"_blank"}
+                >
+                  Actions tab
+                </A>{" "}
+                of your GitHub repo to view live build logs.
+              </TextWrap>
+            </Placeholder>
+          );
+        }
+        return (
+          <TabWrapper>
+            {/* <TempJobList
+              handleSaveValues={this.handleSaveValues}
+              jobs={this.state.jobs}
+              setJobs={(jobs: any) => this.setState({ jobs })}
+              isAuthorized={this.props.isAuthorized}
+              saveValuesStatus={this.state.saveValuesStatus}
+              expandJob={(job: any) => this.setJobRun(job)}
+              isDeployedFromGithub={
+                !!this.state.currentChart?.git_action_config?.git_repo
+              }
+              repositoryUrl={
+                this.state.currentChart?.git_action_config?.git_repo
+              }
+              currentChartVersion={Number(this.state.currentChart.version)}
+              latestChartVersion={Number(
+                this.state.currentChart.latest_version
+              )}
+            /> */}
+            <JobList 
+              jobs={jobs}
+|             isAuthorized={isAuthorized}
+              saveValuesStatus={saveValuesStatus}
+              expandJob={(job: any) => this.setJobRun(job)}
+              isDeployedFromGithub={
+                !!this.state.currentChart?.git_action_config?.git_repo
+              }
+              repositoryUrl={
+                this.state.currentChart?.git_action_config?.git_repo
+              }
+              currentChartVersion={Number(this.state.currentChart.version)}
+              latestChartVersion={Number(
+                this.state.currentChart.latest_version
+              )}
+            />
+          </TabWrapper>
+        );
+      case "values":
+        return (
+          <ValuesYaml
+            currentChart={chart}
+            refreshChart={() => refreshChart()}
+            disabled={!isAuthorized("job", "", ["get", "update"])}
+          />
+        );
+      case "settings":
+        return (
+          isAuthorized("job", "", ["get", "delete"]) && (
+            <SettingsSection
+              currentChart={chart}
+              refreshChart={() => refreshChart()}
+              setShowDeleteOverlay={(showOverlay: boolean) => {
+                if (showOverlay) {
+                  setCurrentOverlay({
+                    message: `Are you sure you want to delete ${chart.name}?`,
+                    onYes: deleteChart,
+                    onNo: () => setCurrentOverlay(null),
+                  });
+                } else {
+                  setCurrentOverlay(null);
+                }
+              }}
+              saveButtonText="Save Config"
+            />
+          )
+        );
+      default:
+    }
+  };
+
+  return (
+    <>
+      <StyledExpandedChart>
+        <HeaderWrapper>
+          <BackButton onClick={closeChart}>
+            <BackButtonImg src={backArrow} />
+          </BackButton>
+          <TitleSection icon={chart.chart.metadata.icon} iconWidth="33px">
+            {chart.name}
+            <DeploymentType currentChart={chart} />
+            <TagWrapper>
+              Namespace <NamespaceTag>{chart.namespace}</NamespaceTag>
+            </TagWrapper>
+          </TitleSection>
+
+          <InfoWrapper>
+            <LastDeployed>
+              Run {jobs?.length} times <Dot>•</Dot>Last template update at
+              {" " + readableDate(chart.info.last_deployed)}
+            </LastDeployed>
+          </InfoWrapper>
+          <RevisionSection
+            chart={chart}
+            refreshChart={() => refreshChart()}
+            setRevision={() => {}}
+            forceRefreshRevisions={false}
+            refreshRevisionsOff={() => {}}
+            status={""}
+            shouldUpdate={
+              chart.latest_version &&
+              chart.latest_version !== chart.chart.metadata.version
+            }
+            latestVersion={chart.latest_version}
+            upgradeVersion={() => {
+              // this.handleUpgradeVersion(this.state.upgradeVersion, () => {
+              //   this.setState({ loading: false });
+              // });
+              // this.setState({ upgradeVersion: "", loading: true });
+            }}
+          />
+        </HeaderWrapper>
+
+        {isChartDeleting ? (
+          <>
+            <LineBreak />
+            <Placeholder>
+              <TextWrap>
+                <Header>
+                  <Spinner src={loading} /> Deleting "{chart.name}"
+                </Header>
+                You will be automatically redirected after deletion is complete.
+              </TextWrap>
+            </Placeholder>
+          </>
+        ) : (
+          <BodyWrapper>
+            {(leftTabOptions?.length > 0 ||
+              formData.tabs?.length > 0 ||
+              rightTabOptions?.length > 0) && (
+              <PorterFormWrapper
+                formData={formData}
+                valuesToOverride={{
+                  namespace: chart.namespace,
+                  clusterId: currentCluster?.id,
+                }}
+                renderTabContents={renderTabContents}
+                isReadOnly={
+                  hasPorterImageTemplate ||
+                  !isAuthorized("job", "", ["get", "update"])
+                }
+                onSubmit={(formValues) => updateChart(formValues, false)}
+                leftTabOptions={leftTabOptions}
+                rightTabOptions={rightTabOptions}
+                saveValuesStatus={"saveValuesStatus"}
+                saveButtonText="Save Config"
+                includeHiddenFields
+                addendum={
+                  <TabButton
+                    onClick={() =>
+                      setDevOpsMode((prev) => {
+                        localStorage.setItem("devOpsMode", prev.toString());
+                        return !prev;
+                      })
+                    }
+                    devOpsMode={devOpsMode}
+                  >
+                    <i className="material-icons">offline_bolt</i> DevOps Mode
+                  </TabButton>
+                }
+              />
+            )}
+          </BodyWrapper>
+        )}
+      </StyledExpandedChart>
+    </>
+  );
 };
 
-const useChart = () => {
+const useChart = (oldChart: ChartType) => {
   const { currentProject, currentCluster } = useContext(Context);
   const [chart, setChart] = useState<ChartTypeWithExtendedConfig>(null);
-  const { params } = useRouteMatch<{
+  const { params, url: matchUrl } = useRouteMatch<{
     namespace: string;
     chartName: string;
   }>();
+  const { pushFiltered } = useRouting();
 
   const loading = useMemo(() => {
     return chart === null;
@@ -1150,11 +1378,100 @@ const useChart = () => {
           setChart(res.data);
         }
       });
-  }, [params]);
+  }, [params, currentCluster, currentProject]);
+
+  /**
+   * Upgrade chart version
+   */
+  const upgradeChart = async () => {};
+
+  /**
+   * Delete/Uninstall chart
+   */
+  const deleteChart = async () => {
+    try {
+      await api.uninstallTemplate(
+        "<token>",
+        {},
+        {
+          namespace: chart.namespace,
+          name: chart.name,
+          id: currentProject.id,
+          cluster_id: currentCluster.id,
+        }
+      );
+
+      return;
+    } catch (error) {
+      console.log(error);
+      throw new Error("Couldn't uninstall the chart");
+    }
+  };
+
+  /**
+   * Update chart values
+   */
+  const updateChart = async (values: string) => {
+    api
+      .upgradeChartValues(
+        "<token>",
+        {
+          values,
+        },
+        {
+          id: currentProject.id,
+          name: chart.name,
+          namespace: chart.namespace,
+          cluster_id: currentCluster.id,
+        }
+      )
+      .then((res) => {
+        refreshChart();
+      })
+      .catch((err) => {
+        let parsedErr = err?.response?.data?.error;
+
+        if (parsedErr) {
+          err = parsedErr;
+        }
+        throw new Error(parsedErr);
+      });
+  };
+
+  /**
+   * Refresh the chart data
+   */
+  const refreshChart = async () => {
+    try {
+      const newChart = await api
+        .getChart(
+          "<token>",
+          {},
+          {
+            name: chart.name,
+            revision: 0,
+            namespace: chart.namespace,
+            cluster_id: currentCluster.id,
+            id: currentProject.id,
+          }
+        )
+        .then((res) => res.data);
+
+      pushFiltered(matchUrl, ["project_id", "job"], {
+        chart_revision: newChart.version,
+      });
+
+      setChart(newChart);
+    } catch (error) {}
+  };
 
   return {
     chart,
     loading,
+    upgradeChart,
+    deleteChart,
+    updateChart,
+    refreshChart,
   };
 };