2
0
Эх сурвалжийг харах

always show job footers for jobs in the proto (#4120)

Feroze Mohideen 2 жил өмнө
parent
commit
d359996b7a

+ 5 - 2
dashboard/src/lib/hooks/useAppStatus.ts

@@ -3,6 +3,8 @@ import _ from "lodash";
 import pluralize from "pluralize";
 import z from "zod";
 
+import { type ClientService } from "lib/porter-apps/services";
+
 import api from "shared/api";
 import {
   useWebsockets,
@@ -43,14 +45,14 @@ type SerializedServiceStatus = z.infer<typeof serviceStatusValidator>;
 export const useAppStatus = ({
   projectId,
   clusterId,
-  serviceNames,
+  services,
   deploymentTargetId,
   appName,
   kind = "pod",
 }: {
   projectId: number;
   clusterId: number;
-  serviceNames: string[];
+  services: ClientService[];
   deploymentTargetId: string;
   appName: string;
   kind?: string;
@@ -116,6 +118,7 @@ export const useAppStatus = ({
   };
 
   useEffect(() => {
+    const serviceNames = services.map((s) => s.name.value);
     void Promise.all(serviceNames.map(updatePods));
     for (const serviceName of serviceNames) {
       setupWebsocket(serviceName);

+ 19 - 0
dashboard/src/lib/porter-apps/services.ts

@@ -39,6 +39,25 @@ export type DetectedServices = {
 };
 type ClientServiceType = "web" | "worker" | "job" | "predeploy";
 
+type ClientWebService = ClientService & { config: ClientWebConfig };
+export const isClientWebService = (
+  service: ClientService
+): service is ClientWebService => {
+  return service.config.type === "web";
+};
+type ClientWorkerService = ClientService & { config: ClientWorkerConfig };
+export const isClientWorkerService = (
+  service: ClientService
+): service is ClientWorkerService => {
+  return service.config.type === "worker";
+};
+type ClientJobService = ClientService & { config: ClientJobConfig };
+export const isClientJobService = (
+  service: ClientService
+): service is ClientJobService => {
+  return service.config.type === "job";
+};
+
 const webConfigValidator = z.object({
   type: z.literal("web"),
   autoscaling: autoscalingValidator.optional(),

+ 6 - 1
dashboard/src/main/home/app-dashboard/app-view/tabs/Overview.tsx

@@ -9,6 +9,8 @@ import { type PorterAppFormData } from "lib/porter-apps";
 import {
   defaultSerialized,
   deserializeService,
+  isClientWebService,
+  isClientWorkerService,
 } from "lib/porter-apps/services";
 
 import { useClusterResources } from "shared/ClusterResourcesContext";
@@ -33,12 +35,15 @@ const Overview: React.FC<Props> = ({ buttonStatus }) => {
     projectId,
     clusterId,
     deploymentTarget,
+    latestClientServices,
   } = useLatestRevision();
 
   const { serviceVersionStatus } = useAppStatus({
     projectId,
     clusterId,
-    serviceNames: latestProto.serviceList.map((s) => s.name),
+    services: latestClientServices.filter(
+      (s) => isClientWebService(s) || isClientWorkerService(s) // we only care about the pod status of web and workers
+    ),
     deploymentTargetId: deploymentTarget.id,
     appName: latestProto.name,
   });

+ 15 - 8
dashboard/src/main/home/app-dashboard/validate-apply/services-settings/ServiceContainer.tsx

@@ -8,14 +8,18 @@ import { match } from "ts-pattern";
 import Spacer from "components/porter/Spacer";
 import { type ClientServiceStatus } from "lib/hooks/useAppStatus";
 import { type PorterAppFormData } from "lib/porter-apps";
-import { type ClientService } from "lib/porter-apps/services";
+import {
+  isClientJobService,
+  type ClientService,
+} from "lib/porter-apps/services";
 
 import chip from "assets/computer-chip.svg";
 import job from "assets/job.png";
 import web from "assets/web.png";
 import worker from "assets/worker.png";
 
-import ServiceStatusFooter from "./ServiceStatusFooter";
+import JobFooter from "./footers/JobFooter";
+import ServiceStatusFooter from "./footers/ServiceStatusFooter";
 import JobTabs from "./tabs/JobTabs";
 import WebTabs from "./tabs/WebTabs";
 import WorkerTabs from "./tabs/WorkerTabs";
@@ -38,6 +42,7 @@ type ServiceProps = {
   };
   clusterIngressIp: string;
   showDisableTls: boolean;
+  existingServiceNames: string[];
 };
 
 const ServiceContainer: React.FC<ServiceProps> = ({
@@ -52,6 +57,7 @@ const ServiceContainer: React.FC<ServiceProps> = ({
   internalNetworkingDetails,
   clusterIngressIp,
   showDisableTls,
+  existingServiceNames,
 }) => {
   const renderTabs = (service: ClientService): JSX.Element => {
     return match(service)
@@ -186,13 +192,14 @@ const ServiceContainer: React.FC<ServiceProps> = ({
           </StyledSourceBox>
         )}
       </AnimatePresence>
-      {status && (
-        <ServiceStatusFooter
-          serviceName={service.name.value}
-          isJob={service.config.type === "job"}
-          status={status}
-        />
+      {!isClientJobService(service) && status && (
+        <ServiceStatusFooter status={status} />
       )}
+      {isClientJobService(service) &&
+        // make sure that this service is in a created revision before showing the job footer - cannot view history / run jobs that are not deployed
+        existingServiceNames.includes(service.name.value) && (
+          <JobFooter jobName={service.name.value} />
+        )}
       <Spacer y={0.5} />
     </>
   );

+ 1 - 0
dashboard/src/main/home/app-dashboard/validate-apply/services-settings/ServiceList.tsx

@@ -238,6 +238,7 @@ const ServiceList: React.FC<ServiceListProps> = ({
                 internalNetworkingDetails={internalNetworkingDetails}
                 clusterIngressIp={clusterIngressIp}
                 showDisableTls={loadBalancerType === "ALB"}
+                existingServiceNames={existingServiceNames}
               />
             ) : null;
           })}

+ 76 - 0
dashboard/src/main/home/app-dashboard/validate-apply/services-settings/footers/JobFooter.tsx

@@ -0,0 +1,76 @@
+import React from "react";
+import _ from "lodash";
+import styled from "styled-components";
+
+import Button from "components/porter/Button";
+import Container from "components/porter/Container";
+import Link from "components/porter/Link";
+import Spacer from "components/porter/Spacer";
+
+import { useLatestRevision } from "../../../app-view/LatestRevisionContext";
+import TriggerJobButton from "../../jobs/TriggerJobButton";
+
+type JobFooterProps = {
+  jobName: string;
+};
+const ServiceStatusFooter: React.FC<JobFooterProps> = ({ jobName }) => {
+  const { latestProto, projectId, clusterId, deploymentTarget, appName } =
+    useLatestRevision();
+
+  return (
+    <StyledStatusFooter>
+      <Container row>
+        <Link to={`/apps/${latestProto.name}/job-history?service=${jobName}`}>
+          <Button
+            onClick={() => {}}
+            height="30px"
+            width="87px"
+            color="#ffffff11"
+            withBorder
+          >
+            <I className="material-icons">open_in_new</I>
+            History
+          </Button>
+        </Link>
+        <Spacer inline x={1} />
+        <TriggerJobButton
+          projectId={projectId}
+          clusterId={clusterId}
+          appName={appName}
+          jobName={jobName}
+          deploymentTargetId={deploymentTarget.id}
+        />
+      </Container>
+    </StyledStatusFooter>
+  );
+};
+
+export default ServiceStatusFooter;
+
+const I = styled.i`
+  font-size: 14px;
+  margin-right: 5px;
+`;
+
+const StyledStatusFooter = styled.div`
+  width: 100%;
+  padding: 10px 15px;
+  background: ${(props) => props.theme.fg2};
+  border-bottom-left-radius: 5px;
+  border-bottom-right-radius: 5px;
+  border: 1px solid #494b4f;
+  border-top: 0;
+  overflow: hidden;
+  display: flex;
+  align-items: stretch;
+  flex-direction: row;
+  animation: fadeIn 0.5s;
+  @keyframes fadeIn {
+    from {
+      opacity: 0;
+    }
+    to {
+      opacity: 1;
+    }
+  }
+`;

+ 2 - 47
dashboard/src/main/home/app-dashboard/validate-apply/services-settings/ServiceStatusFooter.tsx → dashboard/src/main/home/app-dashboard/validate-apply/services-settings/footers/ServiceStatusFooter.tsx

@@ -7,7 +7,6 @@ import { match } from "ts-pattern";
 import Button from "components/porter/Button";
 import Container from "components/porter/Container";
 import Link from "components/porter/Link";
-import Spacer from "components/porter/Spacer";
 import Tag from "components/porter/Tag";
 import Text from "components/porter/Text";
 import { type ClientServiceStatus } from "lib/hooks/useAppStatus";
@@ -15,62 +14,18 @@ import { isClientServiceNotification } from "lib/porter-apps/notification";
 
 import alert from "assets/alert-warning.svg";
 
-import { useLatestRevision } from "../../app-view/LatestRevisionContext";
-import TriggerJobButton from "../jobs/TriggerJobButton";
+import { useLatestRevision } from "../../../app-view/LatestRevisionContext";
 
 type ServiceStatusFooterProps = {
-  serviceName: string;
   status: ClientServiceStatus[];
-  isJob: boolean;
 };
 const ServiceStatusFooter: React.FC<ServiceStatusFooterProps> = ({
-  serviceName,
   status,
-  isJob,
 }) => {
   const [expanded, setExpanded] = useState<boolean>(false);
-  const {
-    latestProto,
-    projectId,
-    clusterId,
-    deploymentTarget,
-    appName,
-    latestClientNotifications,
-    tabUrlGenerator,
-  } = useLatestRevision();
+  const { latestClientNotifications, tabUrlGenerator } = useLatestRevision();
   const [height, setHeight] = useState<Height>(0);
 
-  if (isJob) {
-    return (
-      <StyledStatusFooter>
-        <Container row>
-          <Link
-            to={`/apps/${latestProto.name}/job-history?service=${serviceName}`}
-          >
-            <Button
-              onClick={() => {}}
-              height="30px"
-              width="87px"
-              color="#ffffff11"
-              withBorder
-            >
-              <I className="material-icons">open_in_new</I>
-              History
-            </Button>
-          </Link>
-          <Spacer inline x={1} />
-          <TriggerJobButton
-            projectId={projectId}
-            clusterId={clusterId}
-            appName={appName}
-            jobName={serviceName}
-            deploymentTargetId={deploymentTarget.id}
-          />
-        </Container>
-      </StyledStatusFooter>
-    );
-  }
-
   return (
     <>
       {status.map((versionStatus, i) => {