|
|
@@ -1,4 +1,4 @@
|
|
|
-import React, { useContext, useState } from "react";
|
|
|
+import React, { useContext, useMemo, useState } from "react";
|
|
|
import styled from "styled-components";
|
|
|
|
|
|
import api from "shared/api";
|
|
|
@@ -7,6 +7,9 @@ import JobResource from "./JobResource";
|
|
|
import useAuth from "shared/auth/useAuth";
|
|
|
import usePagination from "shared/hooks/usePagination";
|
|
|
import Selector from "components/Selector";
|
|
|
+import DisplaySwitch from "components/DisplaySwitch";
|
|
|
+import { CellProps, Column } from "react-table";
|
|
|
+import { dateFormatter, JobRun, runnedFor } from "../../chart/JobRunTable";
|
|
|
|
|
|
type PropsType = {
|
|
|
jobs: any[];
|
|
|
@@ -28,6 +31,7 @@ const JobListFC = (props: PropsType): JSX.Element => {
|
|
|
} = useContext(Context);
|
|
|
const [deletionCandidate, setDeletionCandidate] = useState(null);
|
|
|
const [deletionJob, setDeletionJob] = useState(null);
|
|
|
+ const [view, setView] = useState<"table" | "list">("list");
|
|
|
|
|
|
const {
|
|
|
firstContentIndex,
|
|
|
@@ -85,6 +89,12 @@ const JobListFC = (props: PropsType): JSX.Element => {
|
|
|
|
|
|
return (
|
|
|
<>
|
|
|
+ <DisplaySwitch
|
|
|
+ onChange={(option) => {
|
|
|
+ setView(option);
|
|
|
+ }}
|
|
|
+ value={view}
|
|
|
+ />
|
|
|
<JobListWrapper>
|
|
|
{props.jobs
|
|
|
.slice(firstContentIndex, lastContentIndex)
|
|
|
@@ -161,6 +171,176 @@ const JobListFC = (props: PropsType): JSX.Element => {
|
|
|
|
|
|
export default JobListFC;
|
|
|
|
|
|
+type JobTableRendererType = {
|
|
|
+ jobs: JobRun[];
|
|
|
+ handleDelete: () => void;
|
|
|
+ deletionJob: JobRun;
|
|
|
+ currentChartVersion: number;
|
|
|
+ latestChartVersion: number;
|
|
|
+ isDeployedFromGithub: boolean;
|
|
|
+ repositoryUrl?: string;
|
|
|
+};
|
|
|
+
|
|
|
+const JobTableRenderer = (props: JobTableRendererType): JSX.Element => {
|
|
|
+ const { currentProject, currentCluster } = useContext(Context);
|
|
|
+
|
|
|
+ const columns = useMemo<Column<JobRun>[]>(
|
|
|
+ () => [
|
|
|
+ {
|
|
|
+ Header: "Namespace / Name",
|
|
|
+ accessor: (originalRow) => {
|
|
|
+ const owners = originalRow.metadata.ownerReferences;
|
|
|
+ let name = "N/A";
|
|
|
+ if (Array.isArray(owners)) {
|
|
|
+ name = owners[0]?.name;
|
|
|
+ }
|
|
|
+ if (originalRow?.metadata?.labels["meta.helm.sh/release-name"]) {
|
|
|
+ name = originalRow.metadata.labels["meta.helm.sh/release-name"];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (name !== "N/A") {
|
|
|
+ return originalRow.metadata?.namespace + "/" + name;
|
|
|
+ }
|
|
|
+
|
|
|
+ return name;
|
|
|
+ },
|
|
|
+ width: "max-content",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ Header: "Run at",
|
|
|
+ accessor: (originalRow) => dateFormatter(originalRow.status.startTime),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ Header: "Run for",
|
|
|
+ accessor: (originalRow) => {
|
|
|
+ if (originalRow.status?.completionTime) {
|
|
|
+ return originalRow.status?.completionTime;
|
|
|
+ } else if (
|
|
|
+ Array.isArray(originalRow.status?.conditions) &&
|
|
|
+ originalRow.status?.conditions[0]?.lastTransitionTime
|
|
|
+ ) {
|
|
|
+ return originalRow.status?.conditions[0]?.lastTransitionTime;
|
|
|
+ } else {
|
|
|
+ return "Still running...";
|
|
|
+ }
|
|
|
+ },
|
|
|
+ Cell: ({ row }: CellProps<JobRun>) => {
|
|
|
+ if (row.original.status?.completionTime) {
|
|
|
+ return runnedFor(
|
|
|
+ row.original.status?.startTime,
|
|
|
+ row.original.status?.completionTime
|
|
|
+ );
|
|
|
+ } else if (
|
|
|
+ Array.isArray(row.original.status?.conditions) &&
|
|
|
+ row.original.status?.conditions[0]?.lastTransitionTime
|
|
|
+ ) {
|
|
|
+ return runnedFor(
|
|
|
+ row.original.status?.startTime,
|
|
|
+ row.original.status?.conditions[0]?.lastTransitionTime
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ return "Still running...";
|
|
|
+ }
|
|
|
+ },
|
|
|
+ styles: {
|
|
|
+ padding: "10px",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ Header: "Status",
|
|
|
+ id: "status",
|
|
|
+ Cell: ({ row }: CellProps<JobRun>) => {
|
|
|
+ if (row.original.status?.succeeded >= 1) {
|
|
|
+ return <Status color="#38a88a">Succeeded</Status>;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (row.original.status?.failed >= 1) {
|
|
|
+ return <Status color="#cc3d42">Failed</Status>;
|
|
|
+ }
|
|
|
+
|
|
|
+ return <Status color="#ffffff11">Running</Status>;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ Header: "Commit/Image tag",
|
|
|
+ id: "commit_or_image_tag",
|
|
|
+ accessor: (originalRow) => {
|
|
|
+ const container = originalRow.spec?.template?.spec?.containers[0];
|
|
|
+ return container?.image?.split(":")[1] || "N/A";
|
|
|
+ },
|
|
|
+ Cell: ({ row }: CellProps<JobRun>) => {
|
|
|
+ const container = row.original.spec?.template?.spec?.containers[0];
|
|
|
+
|
|
|
+ const tag = container?.image?.split(":")[1];
|
|
|
+ return tag;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ Header: "Command",
|
|
|
+ id: "command",
|
|
|
+ accessor: (originalRow) => {
|
|
|
+ const container = originalRow.spec?.template?.spec?.containers[0];
|
|
|
+ return container?.command?.join(" ") || "N/A";
|
|
|
+ },
|
|
|
+ Cell: ({ row }: CellProps<JobRun>) => {
|
|
|
+ const container = row.original.spec?.template?.spec?.containers[0];
|
|
|
+
|
|
|
+ return (
|
|
|
+ <CommandString>
|
|
|
+ {container?.command?.join(" ") || "N/A"}
|
|
|
+ </CommandString>
|
|
|
+ );
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: "delete",
|
|
|
+ Cell: ({ row }: CellProps<JobRun>) => {
|
|
|
+ return (
|
|
|
+ <i
|
|
|
+ className="material-icons"
|
|
|
+ onClick={(e) => {
|
|
|
+ e.stopPropagation();
|
|
|
+ props.handleDelete();
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ delete
|
|
|
+ </i>
|
|
|
+ );
|
|
|
+ },
|
|
|
+ maxWidth: 40,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ []
|
|
|
+ );
|
|
|
+
|
|
|
+ const data = useMemo(() => {}, [props.jobs]);
|
|
|
+
|
|
|
+ return <></>;
|
|
|
+};
|
|
|
+
|
|
|
+const CommandString = styled.div`
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ max-width: 300px;
|
|
|
+ color: #ffffff55;
|
|
|
+ margin-right: 27px;
|
|
|
+ font-family: monospace;
|
|
|
+`;
|
|
|
+
|
|
|
+const Status = styled.div<{ color: string }>`
|
|
|
+ padding: 5px 10px;
|
|
|
+ background: ${(props) => props.color};
|
|
|
+ font-size: 13px;
|
|
|
+ border-radius: 3px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: min-content;
|
|
|
+ height: 25px;
|
|
|
+ min-width: 90px;
|
|
|
+`;
|
|
|
+
|
|
|
const FlexEnd = styled.div`
|
|
|
display: flex;
|
|
|
justify-content: flex-end;
|