|
|
@@ -1,8 +1,9 @@
|
|
|
-import React, { useEffect, useState, useContext } from "react";
|
|
|
+import React, { useEffect, useState, useContext, useCallback } from "react";
|
|
|
import { RouteComponentProps, withRouter } from "react-router";
|
|
|
import styled from "styled-components";
|
|
|
import { DeviconsNameList } from "assets/devicons-name-list";
|
|
|
-
|
|
|
+import useAuth from "shared/auth/useAuth";
|
|
|
+import yaml from "js-yaml";
|
|
|
import api from "shared/api";
|
|
|
import { Context } from "shared/Context";
|
|
|
|
|
|
@@ -21,17 +22,37 @@ import TitleSectionStacks from "components/TitleSectionStacks";
|
|
|
import DeploymentTypeStacks from "main/home/cluster-dashboard/expanded-chart/DeploymentTypeStacks";
|
|
|
import DeployStatusSection from "main/home/cluster-dashboard/expanded-chart/deploy-status-section/DeployStatusSection";
|
|
|
import { integrationList } from "shared/common";
|
|
|
+import { ChartType, ResourceType } from "shared/types";
|
|
|
+import RevisionSection from "main/home/cluster-dashboard/expanded-chart/RevisionSection";
|
|
|
|
|
|
type Props = RouteComponentProps & {};
|
|
|
|
|
|
const ExpandedApp: React.FC<Props> = ({ ...props }) => {
|
|
|
- const { currentCluster, currentProject } = useContext(Context);
|
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
const [appData, setAppData] = useState(null);
|
|
|
const [error, setError] = useState(null);
|
|
|
+ const [isAuthorized] = useAuth();
|
|
|
+ const [forceRefreshRevisions, setForceRefreshRevisions] = useState<boolean>(
|
|
|
+ false
|
|
|
+ );
|
|
|
+ const [isLoadingChartData, setIsLoadingChartData] = useState<boolean>(true);
|
|
|
+ const [imageIsPlaceholder, setImageIsPlaceholer] = useState<boolean>(false);
|
|
|
+
|
|
|
const [tab, setTab] = useState("events");
|
|
|
- const [isExpanded, setIsExpanded] = useState(false);
|
|
|
+ const [saveValuesStatus, setSaveValueStatus] = useState<string>(null);
|
|
|
+ const [loading, setLoading] = useState<boolean>(false);
|
|
|
+ const [components, setComponents] = useState<ResourceType[]>([]);
|
|
|
|
|
|
+ const [isExpanded, setIsExpanded] = useState(false);
|
|
|
+ const [isAgentInstalled, setIsAgentInstalled] = useState<boolean>(false);
|
|
|
+ const [showRevisions, setShowRevisions] = useState<boolean>(false);
|
|
|
+ const [newestImage, setNewestImage] = useState<string>(null);
|
|
|
+ const {
|
|
|
+ currentCluster,
|
|
|
+ currentProject,
|
|
|
+ setCurrentError,
|
|
|
+ setCurrentOverlay,
|
|
|
+ } = useContext(Context);
|
|
|
const getPorterApp = async () => {
|
|
|
setIsLoading(true);
|
|
|
const { appName } = props.match.params as any;
|
|
|
@@ -86,7 +107,187 @@ const ExpandedApp: React.FC<Props> = ({ ...props }) => {
|
|
|
// });
|
|
|
return "";
|
|
|
};
|
|
|
+ const updateComponents = async (currentChart: ChartType) => {
|
|
|
+ setLoading(true);
|
|
|
+ try {
|
|
|
+ const res = await api.getChartComponents(
|
|
|
+ "<token>",
|
|
|
+ {},
|
|
|
+ {
|
|
|
+ id: currentProject.id,
|
|
|
+ name: currentChart.name,
|
|
|
+ namespace: currentChart.namespace,
|
|
|
+ cluster_id: currentCluster.id,
|
|
|
+ revision: currentChart.version,
|
|
|
+ }
|
|
|
+ );
|
|
|
+ setComponents(res.data.Objects);
|
|
|
+ setLoading(false);
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error);
|
|
|
+ setLoading(false);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const getChartData = async (chart: ChartType) => {
|
|
|
+ setIsLoadingChartData(true);
|
|
|
+ const res = await api.getChart(
|
|
|
+ "<token>",
|
|
|
+ {},
|
|
|
+ {
|
|
|
+ name: chart.name,
|
|
|
+ namespace: chart.namespace,
|
|
|
+ cluster_id: currentCluster.id,
|
|
|
+ revision: chart.version,
|
|
|
+ id: currentProject.id,
|
|
|
+ }
|
|
|
+ );
|
|
|
+ const image = res.data?.config?.image?.repository;
|
|
|
+ const tag = res.data?.config?.image?.tag?.toString();
|
|
|
+ const newNewestImage = tag ? image + ":" + tag : image;
|
|
|
+ let imageIsPlaceholder = false;
|
|
|
+ if (
|
|
|
+ (image === "porterdev/hello-porter" ||
|
|
|
+ image === "public.ecr.aws/o1j4x7p4/hello-porter") &&
|
|
|
+ !newestImage
|
|
|
+ ) {
|
|
|
+ imageIsPlaceholder = true;
|
|
|
+ }
|
|
|
+ setImageIsPlaceholer(imageIsPlaceholder);
|
|
|
+ setNewestImage(newNewestImage);
|
|
|
+
|
|
|
+ const updatedChart = res.data;
|
|
|
+
|
|
|
+ setAppData({ chart: updatedChart });
|
|
|
+
|
|
|
+ updateComponents(updatedChart).finally(() => setIsLoadingChartData(false));
|
|
|
+ };
|
|
|
+
|
|
|
+ const setRevision = (chart: ChartType, isCurrent?: boolean) => {
|
|
|
+ // // if we've set the revision, we also override the revision in log data
|
|
|
+ // let newLogData = logData;
|
|
|
+
|
|
|
+ // newLogData.revision = `${chart.version}`;
|
|
|
+
|
|
|
+ // setLogData(newLogData);
|
|
|
+
|
|
|
+ // setIsPreview(!isCurrent);
|
|
|
+ getChartData(chart);
|
|
|
+ };
|
|
|
+ const appUpgradeVersion = useCallback(
|
|
|
+ async (version: string, cb: () => void) => {
|
|
|
+ // convert current values to yaml
|
|
|
+ const values = appData.chart.config;
|
|
|
+
|
|
|
+ const valuesYaml = yaml.dump({
|
|
|
+ ...values,
|
|
|
+ });
|
|
|
+
|
|
|
+ setSaveValueStatus("loading");
|
|
|
+ getChartData(appData.chart);
|
|
|
+
|
|
|
+ try {
|
|
|
+ await api.upgradeChartValues(
|
|
|
+ "<token>",
|
|
|
+ {
|
|
|
+ values: valuesYaml,
|
|
|
+ version: version,
|
|
|
+ latest_revision: appData.chart.version,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: currentProject.id,
|
|
|
+ namespace: appData.chart.namespace,
|
|
|
+ name: appData.chart.name,
|
|
|
+ cluster_id: currentCluster.id,
|
|
|
+ }
|
|
|
+ );
|
|
|
+ setSaveValueStatus("successful");
|
|
|
+ setForceRefreshRevisions(true);
|
|
|
+
|
|
|
+ window.analytics?.track("Chart Upgraded", {
|
|
|
+ chart: appData.chart.name,
|
|
|
+ values: valuesYaml,
|
|
|
+ });
|
|
|
+
|
|
|
+ cb && cb();
|
|
|
+ } catch (err) {
|
|
|
+ const parsedErr = err?.response?.data?.error;
|
|
|
+
|
|
|
+ if (parsedErr) {
|
|
|
+ err = parsedErr;
|
|
|
+ }
|
|
|
|
|
|
+ setSaveValueStatus(err);
|
|
|
+ setCurrentError(parsedErr);
|
|
|
+
|
|
|
+ window.analytics?.track("Failed to Upgrade Chart", {
|
|
|
+ chart: appData.chart.name,
|
|
|
+ values: valuesYaml,
|
|
|
+ error: err,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ [appData?.chart]
|
|
|
+ );
|
|
|
+
|
|
|
+ // const updateTabs = () => {
|
|
|
+ // // Collate non-form tabs
|
|
|
+ // let rightTabOptions = [] as any[];
|
|
|
+ // let leftTabOptions = [] as any[];
|
|
|
+ // if (
|
|
|
+ // appData.chart.chart.metadata.home === "https://getporter.dev/" &&
|
|
|
+ // (appData.chart.chart.metadata.name === "web" ||
|
|
|
+ // appData.chart.chart.metadata.name === "worker" ||
|
|
|
+ // appData.chart.chart.metadata.name === "job") &&
|
|
|
+ // currentCluster.agent_integration_enabled
|
|
|
+ // ) {
|
|
|
+ // leftTabOptions.push({ label: "Events", value: "events" });
|
|
|
+
|
|
|
+ // if (isAgentInstalled) {
|
|
|
+ // leftTabOptions.push({ label: "Logs", value: "logs" });
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // leftTabOptions.push({ label: "Status", value: "status" });
|
|
|
+ // leftTabOptions.push({ label: "Metrics", value: "metrics" });
|
|
|
+ // // if (props.isMetricsInstalled) {
|
|
|
+ // // leftTabOptions.push({ label: "Metrics", value: "metrics" });
|
|
|
+ // // }
|
|
|
+
|
|
|
+ // rightTabOptions.push({ label: "Chart Overview", value: "graph" });
|
|
|
+
|
|
|
+ // // if (devOpsMode) {
|
|
|
+ // // rightTabOptions.push(
|
|
|
+ // // { label: "Manifests", value: "list" },
|
|
|
+ // // { label: "Helm Values", value: "values" }
|
|
|
+ // // );
|
|
|
+ // // }
|
|
|
+
|
|
|
+ // if (appData.chart?.git_action_config?.git_repo) {
|
|
|
+ // rightTabOptions.push({
|
|
|
+ // label: "Build Settings",
|
|
|
+ // value: "build-settings",
|
|
|
+ // });
|
|
|
+ // }
|
|
|
+
|
|
|
+ // // Settings tab is always last
|
|
|
+ // if (isAuthorized("application", "", ["get", "delete"])) {
|
|
|
+ // rightTabOptions.push({ label: "Settings", value: "settings" });
|
|
|
+ // }
|
|
|
+
|
|
|
+ // // Filter tabs if previewing an old revision or updating the chart version
|
|
|
+ // if (isPreview) {
|
|
|
+ // const liveTabs = ["status", "events", "settings", "deploy", "metrics"];
|
|
|
+ // rightTabOptions = rightTabOptions.filter(
|
|
|
+ // (tab: any) => !liveTabs.includes(tab.value)
|
|
|
+ // );
|
|
|
+ // leftTabOptions = leftTabOptions.filter(
|
|
|
+ // (tab: any) => !liveTabs.includes(tab.value)
|
|
|
+ // );
|
|
|
+ // }
|
|
|
+
|
|
|
+ // setLeftTabOptions(leftTabOptions);
|
|
|
+ // setRightTabOptions(rightTabOptions);
|
|
|
+ // };
|
|
|
useEffect(() => {
|
|
|
const { appName } = props.match.params as any;
|
|
|
if (currentCluster && appName && currentProject) {
|
|
|
@@ -181,6 +382,24 @@ const ExpandedApp: React.FC<Props> = ({ ...props }) => {
|
|
|
</LastDeployed>
|
|
|
</InfoWrapper>
|
|
|
</HeaderWrapper>
|
|
|
+ <RevisionSection
|
|
|
+ showRevisions={showRevisions}
|
|
|
+ toggleShowRevisions={() => {
|
|
|
+ setShowRevisions(!showRevisions);
|
|
|
+ }}
|
|
|
+ chart={appData.chart}
|
|
|
+ refreshChart={() => getChartData(appData.chart)}
|
|
|
+ setRevision={setRevision}
|
|
|
+ forceRefreshRevisions={forceRefreshRevisions}
|
|
|
+ refreshRevisionsOff={() => setForceRefreshRevisions(false)}
|
|
|
+ shouldUpdate={
|
|
|
+ appData.chart.latest_version &&
|
|
|
+ appData.chart.latest_version !==
|
|
|
+ appData.chart.chart.metadata.version
|
|
|
+ }
|
|
|
+ latestVersion={appData.chart.latest_version}
|
|
|
+ upgradeVersion={appUpgradeVersion}
|
|
|
+ />
|
|
|
<Spacer y={1} />
|
|
|
<TabSelector
|
|
|
options={[
|