}
+ icon={
}
color="default"
disabled={disabled || index === 0}
size="small"
@@ -257,7 +257,7 @@ const AccessFormSSHConfig = ({ form: formInst, formName, disabled, initialValues
}}
/>
}
+ icon={
}
color="default"
disabled={disabled || index === fields.length - 1}
size="small"
@@ -268,7 +268,7 @@ const AccessFormSSHConfig = ({ form: formInst, formName, disabled, initialValues
}}
/>
}
+ icon={
}
color="default"
disabled={disabled}
size="small"
@@ -285,7 +285,7 @@ const AccessFormSSHConfig = ({ form: formInst, formName, disabled, initialValues
})}
/>
) : null}
-
} onClick={() => add(initFormModel())}>
+
} onClick={() => add(initFormModel())}>
{t("access.form.ssh_jump_servers.add")}
diff --git a/ui/src/components/workflow/WorkflowRunDetail.tsx b/ui/src/components/workflow/WorkflowRunDetail.tsx
index 17e122fd7..86244c3a7 100644
--- a/ui/src/components/workflow/WorkflowRunDetail.tsx
+++ b/ui/src/components/workflow/WorkflowRunDetail.tsx
@@ -89,45 +89,31 @@ const WorkflowRunLogs = ({ runId, runStatus }: { runId: string; runStatus: strin
const [showWhitespace, setShowWhitespace] = useState(true);
const renderBadge = () => {
+ let color: string | undefined;
+
switch (runStatus) {
case WORKFLOW_RUN_STATUSES.PENDING:
- return (
-
-
- {t("workflow_run.props.status.pending")}
-
- );
+ break;
case WORKFLOW_RUN_STATUSES.RUNNING:
- return (
-
-
- {t("workflow_run.props.status.running")}
-
- );
+ color = themeToken.colorInfo;
+ break;
case WORKFLOW_RUN_STATUSES.SUCCEEDED:
- return (
-
-
- {t("workflow_run.props.status.succeeded")}
-
- );
+ color = themeToken.colorSuccess;
+ break;
case WORKFLOW_RUN_STATUSES.FAILED:
- return (
-
-
- {t("workflow_run.props.status.failed")}
-
- );
+ color = themeToken.colorError;
+ break;
case WORKFLOW_RUN_STATUSES.CANCELED:
- return (
-
-
- {t("workflow_run.props.status.canceled")}
-
- );
+ color = themeToken.colorWarning;
+ break;
}
- return <>>;
+ return (
+
+
+ {t(`workflow_run.props.status.${runStatus}`)}
+
+ );
};
const renderRecord = (record: Log) => {
@@ -294,12 +280,13 @@ const WorkflowRunArtifacts = ({ runId }: { runId: string }) => {
{
key: "name",
title: t("workflow_run_artifact.props.name"),
- ellipsis: true,
render: (_, record) => {
return (
-
- {record.subjectAltNames}
-
+
+
+ {record.subjectAltNames}
+
+
);
},
},
diff --git a/ui/src/components/workflow/WorkflowRuns.tsx b/ui/src/components/workflow/WorkflowRuns.tsx
index e9689a290..3cf335ce9 100644
--- a/ui/src/components/workflow/WorkflowRuns.tsx
+++ b/ui/src/components/workflow/WorkflowRuns.tsx
@@ -45,13 +45,11 @@ const WorkflowRuns = ({ className, style, workflowId }: WorkflowRunsProps) => {
{
key: "id",
title: t("workflow_run.props.id"),
- ellipsis: true,
render: (_, record) =>
{record.id},
},
{
key: "status",
title: t("workflow_run.props.status"),
- ellipsis: true,
render: (_, record) => {
return
;
},
@@ -243,7 +241,7 @@ const WorkflowRuns = ({ className, style, workflowId }: WorkflowRunsProps) => {
/>
),
icon: (
-
+
),
@@ -273,7 +271,11 @@ const WorkflowRuns = ({ className, style, workflowId }: WorkflowRunsProps) => {
dataSource={tableData}
loading={loading}
locale={{
- emptyText: loading ? : } />,
+ emptyText: loading ? (
+
+ ) : (
+ } />
+ ),
}}
pagination={{
current: page,
diff --git a/ui/src/components/workflow/WorkflowStatusIcon.tsx b/ui/src/components/workflow/WorkflowStatusIcon.tsx
index caf807b1c..4ab965e5d 100644
--- a/ui/src/components/workflow/WorkflowStatusIcon.tsx
+++ b/ui/src/components/workflow/WorkflowStatusIcon.tsx
@@ -1,10 +1,4 @@
-import {
- CheckCircleOutlined as CheckCircleOutlinedIcon,
- ClockCircleOutlined as ClockCircleOutlinedIcon,
- CloseCircleOutlined as CloseCircleOutlinedIcon,
- StopOutlined as StopOutlinedIcon,
- SyncOutlined as SyncOutlinedIcon,
-} from "@ant-design/icons";
+import { IconCircleCheck, IconCircleDashed, IconCircleOff, IconCircleX, IconClock, IconLoader3 } from "@tabler/icons-react";
import { theme } from "antd";
import { WORKFLOW_RUN_STATUSES } from "@/domain/workflowRun";
@@ -18,7 +12,9 @@ export type WorkflowStatusIconProps = {
status: string;
};
-const WorkflowStatusIcon = ({ className, style, color, size, status }: WorkflowStatusIconProps) => {
+const WorkflowStatusIcon = ({ className, style, color, status, ...props }: WorkflowStatusIconProps) => {
+ const { size = "1em" } = props;
+
const { token: themeToken } = theme.useToken();
switch (status) {
@@ -27,74 +23,55 @@ const WorkflowStatusIcon = ({ className, style, color, size, status }: WorkflowS
color = themeToken.colorTextSecondary;
}
return (
-
+
+
+
);
case WORKFLOW_RUN_STATUSES.RUNNING:
if (color === true) {
color = themeToken.colorInfo;
}
return (
-
+
+
+
);
case WORKFLOW_RUN_STATUSES.SUCCEEDED:
if (color === true) {
color = themeToken.colorSuccess;
- console.log(color);
}
return (
-
+
+
+
);
case WORKFLOW_RUN_STATUSES.FAILED:
if (color === true) {
color = themeToken.colorError;
}
return (
-
+
+
+
);
case WORKFLOW_RUN_STATUSES.CANCELED:
if (color === true) {
color = themeToken.colorWarning;
}
return (
-
+
+
+
);
default:
- return <>>;
+ if (color === true) {
+ color = themeToken.colorTextSecondary;
+ }
+ return (
+
+
+
+ );
}
};
diff --git a/ui/src/components/workflow/node/AddNode.tsx b/ui/src/components/workflow/node/AddNode.tsx
index 1ef2f2a67..c9fe64968 100644
--- a/ui/src/components/workflow/node/AddNode.tsx
+++ b/ui/src/components/workflow/node/AddNode.tsx
@@ -1,14 +1,6 @@
import { memo, useMemo } from "react";
import { useTranslation } from "react-i18next";
-import {
- CloudUploadOutlined as CloudUploadOutlinedIcon,
- DeploymentUnitOutlined as DeploymentUnitOutlinedIcon,
- MonitorOutlined as MonitorOutlinedIcon,
- SendOutlined as SendOutlinedIcon,
- SisternodeOutlined as SisternodeOutlinedIcon,
- SolutionOutlined as SolutionOutlinedIcon,
-} from "@ant-design/icons";
-import { IconPlus } from "@tabler/icons-react";
+import { IconCloudUpload, IconContract, IconDeviceDesktopSearch, IconPackage, IconPlus, IconSend, IconSitemap } from "@tabler/icons-react";
import { Dropdown } from "antd";
import { WorkflowNodeType, newNode } from "@/domain/workflow";
@@ -25,15 +17,17 @@ const AddNode = ({ node, disabled }: AddNodeProps) => {
const { addNode } = useWorkflowStore(useZustandShallowSelector(["addNode"]));
const dropdownMenus = useMemo(() => {
- return [
- [WorkflowNodeType.Apply, "workflow_node.apply.label", ],
- [WorkflowNodeType.Upload, "workflow_node.upload.label", ],
- [WorkflowNodeType.Monitor, "workflow_node.monitor.label", ],
- [WorkflowNodeType.Deploy, "workflow_node.deploy.label", ],
- [WorkflowNodeType.Notify, "workflow_node.notify.label", ],
- [WorkflowNodeType.Branch, "workflow_node.branch.label", ],
- [WorkflowNodeType.ExecuteResultBranch, "workflow_node.execute_result_branch.label", ],
- ]
+ return (
+ [
+ [WorkflowNodeType.Apply, "workflow_node.apply.label", ],
+ [WorkflowNodeType.Upload, "workflow_node.upload.label", ],
+ [WorkflowNodeType.Monitor, "workflow_node.monitor.label", ],
+ [WorkflowNodeType.Deploy, "workflow_node.deploy.label", ],
+ [WorkflowNodeType.Notify, "workflow_node.notify.label", ],
+ [WorkflowNodeType.Branch, "workflow_node.branch.label", ],
+ [WorkflowNodeType.ExecuteResultBranch, "workflow_node.execute_result_branch.label", ],
+ ] satisfies Array<[WorkflowNodeType, string, React.ReactNode]>
+ )
.filter(([type]) => {
const hasExecuteResult = [
WorkflowNodeType.Apply,
@@ -50,17 +44,21 @@ const AddNode = ({ node, disabled }: AddNodeProps) => {
})
.map(([type, label, icon]) => {
return {
- key: type as string,
+ key: type,
disabled: disabled,
- label: t(label as string),
- icon: icon,
+ label: t(label),
+ icon: (
+
+ {icon}
+
+ ),
onClick: () => {
- const nextNode = newNode(type as WorkflowNodeType);
+ const nextNode = newNode(type);
addNode(nextNode, node.id);
},
};
});
- }, [node.id, disabled, node.type]);
+ }, [node.id, node.type, disabled]);
return (
diff --git a/ui/src/components/workflow/node/ApplyNodeConfigForm.tsx b/ui/src/components/workflow/node/ApplyNodeConfigForm.tsx
index ab05a5264..19ffb0f22 100644
--- a/ui/src/components/workflow/node/ApplyNodeConfigForm.tsx
+++ b/ui/src/components/workflow/node/ApplyNodeConfigForm.tsx
@@ -1,7 +1,7 @@
import { forwardRef, memo, useEffect, useImperativeHandle, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router";
-import { IconChevronRight, IconHelp, IconPlus, IconX } from "@tabler/icons-react";
+import { IconChevronRight, IconCircleMinus, IconHelp, IconPlus } from "@tabler/icons-react";
import { useControllableValue } from "ahooks";
import { AutoComplete, Button, Divider, Flex, Form, type FormInstance, Input, InputNumber, Select, Switch, Tooltip, Typography } from "antd";
import { createSchemaFieldRule } from "antd-zod";
@@ -607,7 +607,7 @@ const EmailInput = memo(
}
+ icon={}
size="small"
type="text"
onClick={(e) => {
diff --git a/ui/src/components/workflow/node/ConditionNodeConfigFormExpressionEditor.tsx b/ui/src/components/workflow/node/ConditionNodeConfigFormExpressionEditor.tsx
index 1a7c7dd0c..2a8075a1e 100644
--- a/ui/src/components/workflow/node/ConditionNodeConfigFormExpressionEditor.tsx
+++ b/ui/src/components/workflow/node/ConditionNodeConfigFormExpressionEditor.tsx
@@ -1,6 +1,6 @@
import { forwardRef, useEffect, useImperativeHandle, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
-import { IconPlus, IconX } from "@tabler/icons-react";
+import { IconCircleMinus, IconCirclePlus } from "@tabler/icons-react";
import { useControllableValue } from "ahooks";
import { Button, Form, Input, Radio, Select, theme } from "antd";
@@ -368,20 +368,12 @@ const ConditionNodeConfigFormExpressionEditor = forwardRef
- }
- size="small"
- type="text"
- onClick={() => remove(index)}
- />
+ } type="text" onClick={() => remove(index)} />
))}
- } onClick={() => add({})}>
+ } onClick={() => add({})}>
{t("workflow_node.condition.form.expression.add_condition.button")}
diff --git a/ui/src/components/workflow/node/_SharedNode.tsx b/ui/src/components/workflow/node/_SharedNode.tsx
index 0935708ad..cced54a3c 100644
--- a/ui/src/components/workflow/node/_SharedNode.tsx
+++ b/ui/src/components/workflow/node/_SharedNode.tsx
@@ -145,7 +145,7 @@ const SharedNodeMenu = ({ menus, trigger, node, disabled, branchId, branchIndex,
disabled: disabled,
label: isNodeBranchLike(node) ? t("workflow_node.action.rename_branch") : t("workflow_node.action.rename_node"),
icon: (
-
+
),
@@ -180,7 +180,7 @@ const SharedNodeMenu = ({ menus, trigger, node, disabled, branchId, branchIndex,
disabled: disabled || isNodeUnduplicatable(node),
label: isNodeBranchLike(node) ? t("workflow_node.action.duplicate_branch") : t("workflow_node.action.duplicate_node"),
icon: (
-
+
),
@@ -194,7 +194,7 @@ const SharedNodeMenu = ({ menus, trigger, node, disabled, branchId, branchIndex,
disabled: disabled || isNodeUnremovable(node),
label: isNodeBranchLike(node) ? t("workflow_node.action.remove_branch") : t("workflow_node.action.remove_node"),
icon: (
-
+
),
diff --git a/ui/src/pages/ConsoleLayout.tsx b/ui/src/pages/ConsoleLayout.tsx
index 7700ade05..ceff2e665 100644
--- a/ui/src/pages/ConsoleLayout.tsx
+++ b/ui/src/pages/ConsoleLayout.tsx
@@ -79,7 +79,7 @@ const ConsoleLayout = () => {
{
key: "theme",
icon: (
-
+
),
@@ -89,7 +89,7 @@ const ConsoleLayout = () => {
{
key: "locale",
icon: (
-
+
),
@@ -99,7 +99,7 @@ const ConsoleLayout = () => {
{
key: "document",
icon: (
-
+
),
@@ -110,7 +110,7 @@ const ConsoleLayout = () => {
key: "logout",
danger: true,
icon: (
-
+
),
@@ -166,20 +166,26 @@ const SiderMenu = memo(({ onSelect }: { onSelect?: (key: string) => void }) => {
const MENU_KEY_CERTIFICATES = "/certificates";
const MENU_KEY_ACCESSES = "/accesses";
const MENU_KEY_SETTINGS = "/settings";
- const menuItems: Required["items"] = [
- [MENU_KEY_HOME, , t("dashboard.page.title")],
- [MENU_KEY_WORKFLOWS, , t("workflow.page.title")],
- [MENU_KEY_CERTIFICATES, , t("certificate.page.title")],
- [MENU_KEY_ACCESSES, , t("access.page.title")],
- [MENU_KEY_SETTINGS, , t("settings.page.title")],
- ].map(([key, icon, label]) => {
+ const menuItems: Required["items"] = (
+ [
+ [MENU_KEY_HOME, "dashboard.page.title", ],
+ [MENU_KEY_WORKFLOWS, "workflow.page.title", ],
+ [MENU_KEY_CERTIFICATES, "certificate.page.title", ],
+ [MENU_KEY_ACCESSES, "access.page.title", ],
+ [MENU_KEY_SETTINGS, "settings.page.title", ],
+ ] satisfies Array<[string, string, React.ReactNode]>
+ ).map(([key, label, icon]) => {
return {
- key: key as string,
- icon: {icon},
- label: label,
+ key: key,
+ icon: (
+
+ {icon}
+
+ ),
+ label: t(label),
onClick: () => {
- navigate(key as string);
- onSelect?.(key as string);
+ navigate(key);
+ onSelect?.(key);
},
};
});
diff --git a/ui/src/pages/accesses/AccessList.tsx b/ui/src/pages/accesses/AccessList.tsx
index 2e760ccb7..22329a407 100644
--- a/ui/src/pages/accesses/AccessList.tsx
+++ b/ui/src/pages/accesses/AccessList.tsx
@@ -48,12 +48,11 @@ const AccessList = () => {
{
key: "name",
title: t("access.props.name"),
- ellipsis: true,
render: (_, record) => {
return (
-
+
-
+
{record.name || "\u00A0"}
{t(accessProvidersMap.get(record.provider)?.name ?? "") || "\u00A0"}
@@ -204,7 +203,7 @@ const AccessList = () => {
title: {t("access.action.delete")},
content: ,
icon: (
-
+
),
diff --git a/ui/src/pages/certificates/CertificateList.tsx b/ui/src/pages/certificates/CertificateList.tsx
index 49c0b4a3b..567770ffc 100644
--- a/ui/src/pages/certificates/CertificateList.tsx
+++ b/ui/src/pages/certificates/CertificateList.tsx
@@ -49,36 +49,41 @@ const CertificateList = () => {
{
key: "expiry",
title: t("certificate.props.validity"),
- ellipsis: true,
sorter: true,
sortOrder: sorter.columnKey === "expiry" ? sorter.order : undefined,
render: (_, record) => {
const total = dayjs(record.expireAt).diff(dayjs(record.created), "d") + 1;
- const expired = dayjs().isAfter(dayjs(record.expireAt));
- const leftDays = dayjs(record.expireAt).diff(dayjs(), "d");
+ const isExpired = dayjs().isAfter(dayjs(record.expireAt));
+ const leftHours = dayjs(record.expireAt).diff(dayjs(), "h");
+ const leftDays = Math.round(leftHours / 24);
return (
-
- {!expired ? (
- leftDays >= 1 ? (
-
-
+
+ {!isExpired ? (
+ leftDays >= 20 ? (
+
+
+ {t("certificate.props.validity.left_days", { left: leftDays, total })}
+
+ ) : leftDays >= 1 ? (
+
+
{t("certificate.props.validity.left_days", { left: leftDays, total })}
) : (
-
-
+
+
{t("certificate.props.validity.less_than_a_day")}
)
) : (
-
-
+
+
{t("certificate.props.validity.expired")}
)}
-
+
{t("certificate.props.validity.expiration", { date: dayjs(record.expireAt).format("YYYY-MM-DD") })}
@@ -89,24 +94,23 @@ const CertificateList = () => {
key: "brand",
title: t("certificate.props.brand"),
render: (_, record) => (
-
-
{record.issuerOrg || "\u00A0"}
-
{record.keyAlgorithm || "\u00A0"}
+
+ {record.issuerOrg || "\u00A0"}
+ {record.keyAlgorithm || "\u00A0"}
),
},
{
key: "source",
title: t("certificate.props.source"),
- ellipsis: true,
render: (_, record) => {
const workflowId = record.workflowId;
return (
-
-
{t(`certificate.props.source.${record.source}`)}
+
+
{t(`certificate.props.source.${record.source}`)}
{
e.stopPropagation();
if (workflowId) {
@@ -226,7 +230,7 @@ const CertificateList = () => {
title: {t("certificate.action.delete")},
content: ,
icon: (
-
+
),
diff --git a/ui/src/pages/dashboard/Dashboard.tsx b/ui/src/pages/dashboard/Dashboard.tsx
index 9f3a35e04..e3e232734 100644
--- a/ui/src/pages/dashboard/Dashboard.tsx
+++ b/ui/src/pages/dashboard/Dashboard.tsx
@@ -189,8 +189,12 @@ const StatisticCards = () => {
};
const WorkflowRunHistoryTable = () => {
+ const navigate = useNavigate();
+
const { t } = useTranslation();
+ const { notification } = App.useApp();
+
const tableColumns: TableProps["columns"] = [
{
key: "$index",
@@ -202,27 +206,27 @@ const WorkflowRunHistoryTable = () => {
{
key: "name",
title: t("workflow.props.name"),
- ellipsis: true,
render: (_, record) => {
const workflow = record.expand?.workflowId;
return (
- {
- if (workflow) {
- navigate(`/workflows/${workflow.id}`);
- }
- }}
- >
- {workflow?.name ?? {t(`#${record.workflowId}`)}}
-
+
+ {
+ if (workflow) {
+ navigate(`/workflows/${workflow.id}`);
+ }
+ }}
+ >
+ {workflow?.name ?? {t(`#${record.workflowId}`)}}
+
+
);
},
},
{
key: "status",
title: t("workflow_run.props.status"),
- ellipsis: true,
render: (_, record) => {
return ;
},
diff --git a/ui/src/pages/settings/Settings.tsx b/ui/src/pages/settings/Settings.tsx
index 05f7f186a..0c22af811 100644
--- a/ui/src/pages/settings/Settings.tsx
+++ b/ui/src/pages/settings/Settings.tsx
@@ -40,7 +40,11 @@ const Settings = () => {
items={menus.map(([key, label, icon]) => ({
key,
label: t(label),
- icon: {icon},
+ icon: (
+
+ {icon}
+
+ ),
}))}
onClick={({ key }) => {
setMenuValue(key);
@@ -58,7 +62,11 @@ const Settings = () => {
items={menus.map(([key, label, icon]) => ({
key,
label: t(label),
- icon: {icon},
+ icon: (
+
+ {icon}
+
+ ),
}))}
onClick={({ key }) => {
setMenuValue(key);
diff --git a/ui/src/pages/workflows/WorkflowDetail.tsx b/ui/src/pages/workflows/WorkflowDetail.tsx
index 531ef7e8d..380c87d77 100644
--- a/ui/src/pages/workflows/WorkflowDetail.tsx
+++ b/ui/src/pages/workflows/WorkflowDetail.tsx
@@ -93,7 +93,7 @@ const WorkflowDetail = () => {
title: {t("workflow.action.delete")},
content: ,
icon: (
-
+
),
@@ -246,7 +246,7 @@ const WorkflowDetail = () => {
key: "orchestration",
label: t("workflow.detail.orchestration.tab"),
icon: (
-
+
),
@@ -255,7 +255,7 @@ const WorkflowDetail = () => {
key: "runs",
label: t("workflow.detail.runs.tab"),
icon: (
-
+
),
diff --git a/ui/src/pages/workflows/WorkflowList.tsx b/ui/src/pages/workflows/WorkflowList.tsx
index 7e1e8e749..e4a3d6cc2 100644
--- a/ui/src/pages/workflows/WorkflowList.tsx
+++ b/ui/src/pages/workflows/WorkflowList.tsx
@@ -41,9 +41,8 @@ const WorkflowList = () => {
{
key: "name",
title: t("workflow.props.name"),
- ellipsis: true,
render: (_, record) => (
-
+
{record.name || "\u00A0"}
{record.description || "\u00A0"}
@@ -54,7 +53,6 @@ const WorkflowList = () => {
{
key: "trigger",
title: t("workflow.props.trigger"),
- ellipsis: true,
render: (_, record) => {
const trigger = record.trigger;
if (!trigger) {
@@ -99,7 +97,7 @@ const WorkflowList = () => {
render: (_, record) => {
return (
-
+
{record.lastRunTime ? dayjs(record.lastRunTime!).format("YYYY-MM-DD HH:mm:ss") : ""}
);
@@ -137,7 +135,7 @@ const WorkflowList = () => {
color="primary"
icon={}
variant="text"
- onClick={() => {
+ onClick={(e) => {
e.stopPropagation();
handleRecordDuplicateClick(record);
}}
@@ -276,7 +274,7 @@ const WorkflowList = () => {
title: {t("workflow.action.delete")},
content: ,
icon: (
-
+
),
diff --git a/ui/src/pages/workflows/WorkflowNew.tsx b/ui/src/pages/workflows/WorkflowNew.tsx
index 8fb846302..8c9d86360 100644
--- a/ui/src/pages/workflows/WorkflowNew.tsx
+++ b/ui/src/pages/workflows/WorkflowNew.tsx
@@ -25,7 +25,7 @@ const WorkflowNew = () => {
const templateGridSpans = {
xs: { flex: "100%" },
- md: { flex: "100%" },
+ md: { flex: "50%" },
lg: { flex: "50%" },
xl: { flex: "33.3333%" },
xxl: { flex: "33.3333%" },
@@ -112,102 +112,96 @@ const WorkflowNew = () => {
};
return (
-
-
-
-
-
{t("workflow.new.title")}
-
{t("workflow.new.subtitle")}
-
-
-
-
-
-
-
- {t("workflow.new.templates.title")}
-
-
-
-
- }
- hoverable
- onClick={() => handleTemplateClick(TEMPLATE_KEY_STANDARD)}
- >
-
-
-
-
-
-
-
-
- }
- hoverable
- onClick={() => handleTemplateClick(TEMPLATE_KEY_CERTTEST)}
- >
-
-
-
-
-
-
-
-
- }
- hoverable
- onClick={() => handleTemplateClick(TEMPLATE_KEY_EMPTY)}
- >
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
{t("workflow.new.title")}
+
{t("workflow.new.subtitle")}
+
+
+
+ {t("workflow.new.templates.title")}
+
+
+
+
+ }
+ hoverable
+ onClick={() => handleTemplateClick(TEMPLATE_KEY_STANDARD)}
+ >
+
+
+
+
+
+
+
+
+ }
+ hoverable
+ onClick={() => handleTemplateClick(TEMPLATE_KEY_CERTTEST)}
+ >
+
+
+
+
+
+
+
+
+ }
+ hoverable
+ onClick={() => handleTemplateClick(TEMPLATE_KEY_EMPTY)}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
};