mirror of https://github.com/usual2970/certimate
multiple domain support
parent
f036eb1cf2
commit
71e2555391
|
@ -172,13 +172,7 @@ func apply(option *ApplyOption, provider challenge.Provider) (*Certificate, erro
|
||||||
}
|
}
|
||||||
myUser.Registration = reg
|
myUser.Registration = reg
|
||||||
|
|
||||||
domains := []string{option.Domain}
|
domains := strings.Split(option.Domain, ";")
|
||||||
|
|
||||||
// 如果是通配置符域名,把根域名也加入
|
|
||||||
if strings.HasPrefix(option.Domain, "*.") && len(strings.Split(option.Domain, ".")) == 3 {
|
|
||||||
rootDomain := strings.TrimPrefix(option.Domain, "*.")
|
|
||||||
domains = append(domains, rootDomain)
|
|
||||||
}
|
|
||||||
|
|
||||||
request := certificate.ObtainRequest{
|
request := certificate.ObtainRequest{
|
||||||
Domains: domains,
|
Domains: domains,
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -5,8 +5,8 @@
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Certimate - Your Trusted SSL Automation Partner</title>
|
<title>Certimate - Your Trusted SSL Automation Partner</title>
|
||||||
<script type="module" crossorigin src="/assets/index-Dn4jGLHB.js"></script>
|
<script type="module" crossorigin src="/assets/index-B6ZTaWIO.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-I--T0qY3.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-ClQTEWmX.css">
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-background">
|
<body class="bg-background">
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|
|
@ -0,0 +1,242 @@
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
import Show from "../Show";
|
||||||
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
|
import { FormControl, FormLabel } from "../ui/form";
|
||||||
|
import { Button } from "../ui/button";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "../ui/dialog";
|
||||||
|
import { Input } from "../ui/input";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Edit, Plus, Trash2 } from "lucide-react";
|
||||||
|
|
||||||
|
type StringListProps = {
|
||||||
|
className?: string;
|
||||||
|
value: string;
|
||||||
|
valueType?: "domain" | "ip";
|
||||||
|
onValueChange: (value: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const titles: Record<string, string> = {
|
||||||
|
domain: "domain",
|
||||||
|
ip: "IP",
|
||||||
|
};
|
||||||
|
|
||||||
|
const StringList = ({
|
||||||
|
value,
|
||||||
|
className,
|
||||||
|
onValueChange,
|
||||||
|
valueType = "domain",
|
||||||
|
}: StringListProps) => {
|
||||||
|
const [list, setList] = useState<string[]>([]);
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
useMemo(() => {
|
||||||
|
if (value) {
|
||||||
|
setList(value.split(";"));
|
||||||
|
}
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const changeList = () => {
|
||||||
|
onValueChange(list.join(";"));
|
||||||
|
};
|
||||||
|
changeList();
|
||||||
|
}, [list]);
|
||||||
|
|
||||||
|
const addVal = (val: string) => {
|
||||||
|
if (list.includes(val)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setList([...list, val]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const editVal = (index: number, val: string) => {
|
||||||
|
const newList = [...list];
|
||||||
|
newList[index] = val;
|
||||||
|
setList(newList);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onRemoveClick = (index: number) => {
|
||||||
|
const newList = [...list];
|
||||||
|
newList.splice(index, 1);
|
||||||
|
setList(newList);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={cn(className)}>
|
||||||
|
<FormLabel className="flex justify-between items-center">
|
||||||
|
<div>{t(titles[valueType])}</div>
|
||||||
|
|
||||||
|
<Show when={list.length > 0}>
|
||||||
|
<StringEdit
|
||||||
|
op="add"
|
||||||
|
onValueChange={(val: string) => {
|
||||||
|
addVal(val);
|
||||||
|
}}
|
||||||
|
valueType={valueType}
|
||||||
|
value={""}
|
||||||
|
trigger={
|
||||||
|
<div className="flex items-center text-primary">
|
||||||
|
<Plus size={16} className="cursor-pointer " />
|
||||||
|
|
||||||
|
<div className="text-sm ">{t("add")}</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Show
|
||||||
|
when={list.length > 0}
|
||||||
|
fallback={
|
||||||
|
<div className="border rounded-md p-3 text-sm mt-2 flex flex-col items-center">
|
||||||
|
<div className="text-muted-foreground">暂未添加域名</div>
|
||||||
|
|
||||||
|
<StringEdit
|
||||||
|
value={""}
|
||||||
|
trigger={t("add")}
|
||||||
|
onValueChange={addVal}
|
||||||
|
valueType={valueType}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="border rounded-md p-3 text-sm mt-2 text-gray-700 space-y-2">
|
||||||
|
{list.map((item, index) => (
|
||||||
|
<div key={index} className="flex justify-between items-center">
|
||||||
|
<div>{item}</div>
|
||||||
|
<div className="flex space-x-2">
|
||||||
|
<StringEdit
|
||||||
|
op="edit"
|
||||||
|
valueType={valueType}
|
||||||
|
trigger={
|
||||||
|
<Edit
|
||||||
|
size={16}
|
||||||
|
className="cursor-pointer text-gray-600"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
value={item}
|
||||||
|
onValueChange={(val: string) => {
|
||||||
|
editVal(index, val);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Trash2
|
||||||
|
size={16}
|
||||||
|
className="cursor-pointer"
|
||||||
|
onClick={() => {
|
||||||
|
onRemoveClick(index);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StringList;
|
||||||
|
|
||||||
|
type ValueType = "domain" | "ip";
|
||||||
|
|
||||||
|
type StringEditProps = {
|
||||||
|
value: string;
|
||||||
|
trigger: React.ReactNode;
|
||||||
|
onValueChange: (value: string) => void;
|
||||||
|
valueType: ValueType;
|
||||||
|
op?: "add" | "edit";
|
||||||
|
};
|
||||||
|
|
||||||
|
const StringEdit = ({
|
||||||
|
trigger,
|
||||||
|
value,
|
||||||
|
onValueChange,
|
||||||
|
op = "add",
|
||||||
|
valueType,
|
||||||
|
}: StringEditProps) => {
|
||||||
|
const [currentValue, setCurrentValue] = useState<string>("");
|
||||||
|
const [open, setOpen] = useState<boolean>(false);
|
||||||
|
const [error, setError] = useState<string>("");
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setCurrentValue(value);
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
const domainSchema = z
|
||||||
|
.string()
|
||||||
|
.regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
||||||
|
message: t("domain.not.empty.verify.message"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const ipSchema = z.string().ip({ message: t("ip.not.empty.verify.message") });
|
||||||
|
|
||||||
|
const schedules: Record<ValueType, z.ZodString> = {
|
||||||
|
domain: domainSchema,
|
||||||
|
ip: ipSchema,
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSaveClick = useCallback(() => {
|
||||||
|
const schema = schedules[valueType];
|
||||||
|
|
||||||
|
const resp = schema.safeParse(currentValue);
|
||||||
|
if (!resp.success) {
|
||||||
|
setError(JSON.parse(resp.error.message)[0].message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentValue("");
|
||||||
|
setOpen(false);
|
||||||
|
setError("");
|
||||||
|
|
||||||
|
onValueChange(currentValue);
|
||||||
|
}, [currentValue]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={open}
|
||||||
|
onOpenChange={(open) => {
|
||||||
|
setOpen(open);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogTrigger className="text-primary">{trigger}</DialogTrigger>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>{t(titles[valueType])}</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
<Input
|
||||||
|
value={currentValue}
|
||||||
|
onChange={(e) => {
|
||||||
|
setCurrentValue(e.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Show when={error.length > 0}>
|
||||||
|
<div className="text-red-500 text-sm">{error}</div>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<DialogFooter>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
onSaveClick();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{op === "add" ? t("add") : t("confirm")}
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
|
@ -26,6 +26,22 @@ export type Domain = {
|
||||||
expand?: {
|
expand?: {
|
||||||
lastDeployment?: Deployment;
|
lastDeployment?: Deployment;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
applyConfig?: ApplyConfig;
|
||||||
|
deployConfig?: DeployConfig[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DeployConfig = {
|
||||||
|
access: string;
|
||||||
|
type: string;
|
||||||
|
config?: Record<string, string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ApplyConfig = {
|
||||||
|
access: string;
|
||||||
|
email: string;
|
||||||
|
timeout?: number;
|
||||||
|
nameservers?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Statistic = {
|
export type Statistic = {
|
||||||
|
|
|
@ -83,6 +83,7 @@
|
||||||
"pagination.prev": "Previous",
|
"pagination.prev": "Previous",
|
||||||
"domain": "Domain",
|
"domain": "Domain",
|
||||||
"domain.add": "Add Domain",
|
"domain.add": "Add Domain",
|
||||||
|
"domain.edit":"Edit Domain",
|
||||||
"domain.delete": "Delete Domain",
|
"domain.delete": "Delete Domain",
|
||||||
"domain.not.empty.verify.message": "Please enter domain",
|
"domain.not.empty.verify.message": "Please enter domain",
|
||||||
"domain.management.name": "Domain List",
|
"domain.management.name": "Domain List",
|
||||||
|
|
|
@ -83,6 +83,7 @@
|
||||||
"pagination.prev": "上一页",
|
"pagination.prev": "上一页",
|
||||||
"domain": "域名",
|
"domain": "域名",
|
||||||
"domain.add": "新增域名",
|
"domain.add": "新增域名",
|
||||||
|
"domain.edit": "编辑域名",
|
||||||
"domain.delete": "删除域名",
|
"domain.delete": "删除域名",
|
||||||
"domain.not.empty.verify.message": "请输入域名",
|
"domain.not.empty.verify.message": "请输入域名",
|
||||||
"domain.management.name": "域名列表",
|
"domain.management.name": "域名列表",
|
||||||
|
|
|
@ -57,7 +57,7 @@ const Dashboard = () => {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<div className="text-muted-foreground">{t('dashboard')}</div>
|
<div className="text-muted-foreground">{t("dashboard")}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex mt-10 gap-5 flex-col flex-wrap md:flex-row">
|
<div className="flex mt-10 gap-5 flex-col flex-wrap md:flex-row">
|
||||||
<div className="w-full md:w-[250px] 3xl:w-[300px] flex items-center rounded-md p-3 shadow-lg border">
|
<div className="w-full md:w-[250px] 3xl:w-[300px] flex items-center rounded-md p-3 shadow-lg border">
|
||||||
|
@ -66,7 +66,7 @@ const Dashboard = () => {
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-muted-foreground font-semibold">
|
<div className="text-muted-foreground font-semibold">
|
||||||
{t('dashboard.all')}
|
{t("dashboard.all")}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-baseline">
|
<div className="flex items-baseline">
|
||||||
<div className="text-3xl text-stone-700 dark:text-stone-200">
|
<div className="text-3xl text-stone-700 dark:text-stone-200">
|
||||||
|
@ -91,7 +91,7 @@ const Dashboard = () => {
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-muted-foreground font-semibold">
|
<div className="text-muted-foreground font-semibold">
|
||||||
{t('dashboard.near.expired')}
|
{t("dashboard.near.expired")}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-baseline">
|
<div className="flex items-baseline">
|
||||||
<div className="text-3xl text-stone-700 dark:text-stone-200">
|
<div className="text-3xl text-stone-700 dark:text-stone-200">
|
||||||
|
@ -120,7 +120,7 @@ const Dashboard = () => {
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-muted-foreground font-semibold">
|
<div className="text-muted-foreground font-semibold">
|
||||||
{t('dashboard.enabled')}
|
{t("dashboard.enabled")}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-baseline">
|
<div className="flex items-baseline">
|
||||||
<div className="text-3xl text-stone-700 dark:text-stone-200">
|
<div className="text-3xl text-stone-700 dark:text-stone-200">
|
||||||
|
@ -144,7 +144,9 @@ const Dashboard = () => {
|
||||||
<Ban size={48} strokeWidth={1} className="text-gray-400" />
|
<Ban size={48} strokeWidth={1} className="text-gray-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-muted-foreground font-semibold">{t('dashboard.not.enabled')}</div>
|
<div className="text-muted-foreground font-semibold">
|
||||||
|
{t("dashboard.not.enabled")}
|
||||||
|
</div>
|
||||||
<div className="flex items-baseline">
|
<div className="flex items-baseline">
|
||||||
<div className="text-3xl text-stone-700 dark:text-stone-200">
|
<div className="text-3xl text-stone-700 dark:text-stone-200">
|
||||||
{statistic?.disabled ? (
|
{statistic?.disabled ? (
|
||||||
|
@ -168,22 +170,19 @@ const Dashboard = () => {
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div className="text-muted-foreground mt-5 text-sm">
|
<div className="text-muted-foreground mt-5 text-sm">
|
||||||
{t('deployment.log.name')}
|
{t("deployment.log.name")}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{deployments?.length == 0 ? (
|
{deployments?.length == 0 ? (
|
||||||
<>
|
<>
|
||||||
<Alert className="max-w-[40em] mt-10">
|
<Alert className="max-w-[40em] mt-10">
|
||||||
<AlertTitle>{t('no.data')}</AlertTitle>
|
<AlertTitle>{t("no.data")}</AlertTitle>
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
<div className="flex items-center mt-5">
|
<div className="flex items-center mt-5">
|
||||||
<div>
|
<div>
|
||||||
<Smile className="text-yellow-400" size={36} />
|
<Smile className="text-yellow-400" size={36} />
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-2">
|
<div className="ml-2"> {t("deployment.log.empty")}</div>
|
||||||
{" "}
|
|
||||||
{t('deployment.log.empty')}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 flex justify-end">
|
<div className="mt-2 flex justify-end">
|
||||||
<Button
|
<Button
|
||||||
|
@ -191,7 +190,7 @@ const Dashboard = () => {
|
||||||
navigate("/edit");
|
navigate("/edit");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('domain.add')}
|
{t("domain.add")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
|
@ -200,16 +199,18 @@ const Dashboard = () => {
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="hidden sm:flex sm:flex-row text-muted-foreground text-sm border-b dark:border-stone-500 sm:p-2 mt-5">
|
<div className="hidden sm:flex sm:flex-row text-muted-foreground text-sm border-b dark:border-stone-500 sm:p-2 mt-5">
|
||||||
<div className="w-48">{t('domain')}</div>
|
<div className="w-48">{t("domain")}</div>
|
||||||
|
|
||||||
<div className="w-24">{t('deployment.log.status')}</div>
|
<div className="w-24">{t("deployment.log.status")}</div>
|
||||||
<div className="w-56">{t('deployment.log.stage')}</div>
|
<div className="w-56">{t("deployment.log.stage")}</div>
|
||||||
<div className="w-56 sm:ml-2 text-center">{t('deployment.log.last.execution.time')}</div>
|
<div className="w-56 sm:ml-2 text-center">
|
||||||
|
{t("deployment.log.last.execution.time")}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="grow">{t('operation')}</div>
|
<div className="grow">{t("operation")}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="sm:hidden flex text-sm text-muted-foreground">
|
<div className="sm:hidden flex text-sm text-muted-foreground">
|
||||||
{t('deployment.log.name')}
|
{t("deployment.log.name")}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{deployments?.map((deployment) => (
|
{deployments?.map((deployment) => (
|
||||||
|
@ -218,7 +219,14 @@ const Dashboard = () => {
|
||||||
className="flex flex-col sm:flex-row text-secondary-foreground border-b dark:border-stone-500 sm:p-2 hover:bg-muted/50 text-sm"
|
className="flex flex-col sm:flex-row text-secondary-foreground border-b dark:border-stone-500 sm:p-2 hover:bg-muted/50 text-sm"
|
||||||
>
|
>
|
||||||
<div className="sm:w-48 w-full pt-1 sm:pt-0 flex items-center">
|
<div className="sm:w-48 w-full pt-1 sm:pt-0 flex items-center">
|
||||||
{deployment.expand.domain?.domain}
|
{deployment.expand.domain?.domain
|
||||||
|
.split(";")
|
||||||
|
.map((domain: string) => (
|
||||||
|
<>
|
||||||
|
{domain}
|
||||||
|
<br />
|
||||||
|
</>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="sm:w-24 w-full pt-1 sm:pt-0 flex items-center">
|
<div className="sm:w-24 w-full pt-1 sm:pt-0 flex items-center">
|
||||||
<DeployState deployment={deployment} />
|
<DeployState deployment={deployment} />
|
||||||
|
@ -236,14 +244,14 @@ const Dashboard = () => {
|
||||||
<Sheet>
|
<Sheet>
|
||||||
<SheetTrigger asChild>
|
<SheetTrigger asChild>
|
||||||
<Button variant={"link"} className="p-0">
|
<Button variant={"link"} className="p-0">
|
||||||
{t('deployment.log.detail.button.text')}
|
{t("deployment.log.detail.button.text")}
|
||||||
</Button>
|
</Button>
|
||||||
</SheetTrigger>
|
</SheetTrigger>
|
||||||
<SheetContent className="sm:max-w-5xl">
|
<SheetContent className="sm:max-w-5xl">
|
||||||
<SheetHeader>
|
<SheetHeader>
|
||||||
<SheetTitle>
|
<SheetTitle>
|
||||||
{deployment.expand.domain?.domain}-{deployment.id}
|
{deployment.expand.domain?.domain}-{deployment.id}
|
||||||
{t('deployment.log.detail')}
|
{t("deployment.log.detail")}
|
||||||
</SheetTitle>
|
</SheetTitle>
|
||||||
</SheetHeader>
|
</SheetHeader>
|
||||||
<div className="bg-gray-950 text-stone-100 p-5 text-sm h-[80dvh]">
|
<div className="bg-gray-950 text-stone-100 p-5 text-sm h-[80dvh]">
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { Input } from "@/components/ui/input";
|
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
@ -39,6 +38,7 @@ import { Textarea } from "@/components/ui/textarea";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { EmailsSetting } from "@/domain/settings";
|
import { EmailsSetting } from "@/domain/settings";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import StringList from "@/components/certimate/StringList";
|
||||||
|
|
||||||
const Edit = () => {
|
const Edit = () => {
|
||||||
const {
|
const {
|
||||||
|
@ -70,16 +70,16 @@ const Edit = () => {
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
id: z.string().optional(),
|
id: z.string().optional(),
|
||||||
domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
|
domain: z.string().min(1, {
|
||||||
message: 'domain.not.empty.verify.message',
|
message: "domain.not.empty.verify.message",
|
||||||
}),
|
}),
|
||||||
email: z.string().email('email.valid.message').optional(),
|
email: z.string().email("email.valid.message").optional(),
|
||||||
access: z.string().regex(/^[a-zA-Z0-9]+$/, {
|
access: z.string().regex(/^[a-zA-Z0-9]+$/, {
|
||||||
message: 'domain.management.edit.dns.access.not.empty.message',
|
message: "domain.management.edit.dns.access.not.empty.message",
|
||||||
}),
|
}),
|
||||||
targetAccess: z.string().optional(),
|
targetAccess: z.string().optional(),
|
||||||
targetType: z.string().regex(/^[a-zA-Z0-9-]+$/, {
|
targetType: z.string().regex(/^[a-zA-Z0-9-]+$/, {
|
||||||
message: 'domain.management.edit.target.type.not.empty.message',
|
message: "domain.management.edit.target.type.not.empty.message",
|
||||||
}),
|
}),
|
||||||
variables: z.string().optional(),
|
variables: z.string().optional(),
|
||||||
group: z.string().optional(),
|
group: z.string().optional(),
|
||||||
|
@ -140,11 +140,11 @@ const Edit = () => {
|
||||||
if (group == "" && targetAccess == "") {
|
if (group == "" && targetAccess == "") {
|
||||||
form.setError("group", {
|
form.setError("group", {
|
||||||
type: "manual",
|
type: "manual",
|
||||||
message: 'domain.management.edit.target.access.verify.msg',
|
message: "domain.management.edit.target.access.verify.msg",
|
||||||
});
|
});
|
||||||
form.setError("targetAccess", {
|
form.setError("targetAccess", {
|
||||||
type: "manual",
|
type: "manual",
|
||||||
message: 'domain.management.edit.target.access.verify.msg',
|
message: "domain.management.edit.target.access.verify.msg",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -164,13 +164,13 @@ const Edit = () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await save(req);
|
await save(req);
|
||||||
let description = t('domain.management.edit.succeed.tips');
|
let description = t("domain.management.edit.succeed.tips");
|
||||||
if (req.id == "") {
|
if (req.id == "") {
|
||||||
description = t('domain.management.add.succeed.tips');
|
description = t("domain.management.add.succeed.tips");
|
||||||
}
|
}
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: t('succeed'),
|
title: t("succeed"),
|
||||||
description,
|
description,
|
||||||
});
|
});
|
||||||
navigate("/domains");
|
navigate("/domains");
|
||||||
|
@ -195,7 +195,7 @@ const Edit = () => {
|
||||||
<div className="">
|
<div className="">
|
||||||
<Toaster />
|
<Toaster />
|
||||||
<div className=" h-5 text-muted-foreground">
|
<div className=" h-5 text-muted-foreground">
|
||||||
{domain?.id ? t('domain.edit') : t('domain.add')}
|
{domain?.id ? t("domain.edit") : t("domain.add")}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5 flex w-full justify-center md:space-x-10 flex-col md:flex-row">
|
<div className="mt-5 flex w-full justify-center md:space-x-10 flex-col md:flex-row">
|
||||||
<div className="w-full md:w-[200px] text-muted-foreground space-x-3 md:space-y-3 flex-row md:flex-col flex">
|
<div className="w-full md:w-[200px] text-muted-foreground space-x-3 md:space-y-3 flex-row md:flex-col flex">
|
||||||
|
@ -208,7 +208,7 @@ const Edit = () => {
|
||||||
setTab("base");
|
setTab("base");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('basic.setting')}
|
{t("basic.setting")}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
|
@ -219,7 +219,7 @@ const Edit = () => {
|
||||||
setTab("advance");
|
setTab("advance");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('advanced.setting')}
|
{t("advanced.setting")}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -234,10 +234,15 @@ const Edit = () => {
|
||||||
name="domain"
|
name="domain"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem hidden={tab != "base"}>
|
<FormItem hidden={tab != "base"}>
|
||||||
<FormLabel>{t('domain')}</FormLabel>
|
<>
|
||||||
<FormControl>
|
<StringList
|
||||||
<Input placeholder={t('domain.not.empty.verify.message')} {...field} />
|
value={field.value}
|
||||||
</FormControl>
|
valueType="domain"
|
||||||
|
onValueChange={(domain: string) => {
|
||||||
|
form.setValue("domain", domain);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
@ -249,12 +254,15 @@ const Edit = () => {
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem hidden={tab != "base"}>
|
<FormItem hidden={tab != "base"}>
|
||||||
<FormLabel className="flex w-full justify-between">
|
<FormLabel className="flex w-full justify-between">
|
||||||
<div>{t('email') + t('domain.management.edit.email.description')}</div>
|
<div>
|
||||||
|
{t("email") +
|
||||||
|
t("domain.management.edit.email.description")}
|
||||||
|
</div>
|
||||||
<EmailsEdit
|
<EmailsEdit
|
||||||
trigger={
|
trigger={
|
||||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||||
<Plus size={14} />
|
<Plus size={14} />
|
||||||
{t('add')}
|
{t("add")}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -268,11 +276,15 @@ const Edit = () => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder={t('domain.management.edit.email.not.empty.message')} />
|
<SelectValue
|
||||||
|
placeholder={t(
|
||||||
|
"domain.management.edit.email.not.empty.message"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectGroup>
|
<SelectGroup>
|
||||||
<SelectLabel>{t('email.list')}</SelectLabel>
|
<SelectLabel>{t("email.list")}</SelectLabel>
|
||||||
{(emails.content as EmailsSetting).emails.map(
|
{(emails.content as EmailsSetting).emails.map(
|
||||||
(item) => (
|
(item) => (
|
||||||
<SelectItem key={item} value={item}>
|
<SelectItem key={item} value={item}>
|
||||||
|
@ -295,12 +307,14 @@ const Edit = () => {
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem hidden={tab != "base"}>
|
<FormItem hidden={tab != "base"}>
|
||||||
<FormLabel className="flex w-full justify-between">
|
<FormLabel className="flex w-full justify-between">
|
||||||
<div>{t('domain.management.edit.dns.access.label')}</div>
|
<div>
|
||||||
|
{t("domain.management.edit.dns.access.label")}
|
||||||
|
</div>
|
||||||
<AccessEdit
|
<AccessEdit
|
||||||
trigger={
|
trigger={
|
||||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||||
<Plus size={14} />
|
<Plus size={14} />
|
||||||
{t('add')}
|
{t("add")}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
op="add"
|
op="add"
|
||||||
|
@ -315,11 +329,17 @@ const Edit = () => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder={t('domain.management.edit.access.not.empty.message')} />
|
<SelectValue
|
||||||
|
placeholder={t(
|
||||||
|
"domain.management.edit.access.not.empty.message"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectGroup>
|
<SelectGroup>
|
||||||
<SelectLabel>{t('domain.management.edit.access.label')}</SelectLabel>
|
<SelectLabel>
|
||||||
|
{t("domain.management.edit.access.label")}
|
||||||
|
</SelectLabel>
|
||||||
{accesses
|
{accesses
|
||||||
.filter((item) => item.usage != "deploy")
|
.filter((item) => item.usage != "deploy")
|
||||||
.map((item) => (
|
.map((item) => (
|
||||||
|
@ -351,7 +371,9 @@ const Edit = () => {
|
||||||
name="targetType"
|
name="targetType"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem hidden={tab != "base"}>
|
<FormItem hidden={tab != "base"}>
|
||||||
<FormLabel>{t('domain.management.edit.target.type')}</FormLabel>
|
<FormLabel>
|
||||||
|
{t("domain.management.edit.target.type")}
|
||||||
|
</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Select
|
<Select
|
||||||
{...field}
|
{...field}
|
||||||
|
@ -361,11 +383,17 @@ const Edit = () => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder={t('domain.management.edit.target.type.not.empty.message')} />
|
<SelectValue
|
||||||
|
placeholder={t(
|
||||||
|
"domain.management.edit.target.type.not.empty.message"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectGroup>
|
<SelectGroup>
|
||||||
<SelectLabel>{t('domain.management.edit.target.type')}</SelectLabel>
|
<SelectLabel>
|
||||||
|
{t("domain.management.edit.target.type")}
|
||||||
|
</SelectLabel>
|
||||||
{targetTypeKeys.map((key) => (
|
{targetTypeKeys.map((key) => (
|
||||||
<SelectItem key={key} value={key}>
|
<SelectItem key={key} value={key}>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
|
@ -373,7 +401,9 @@ const Edit = () => {
|
||||||
className="w-6"
|
className="w-6"
|
||||||
src={targetTypeMap.get(key)?.[1]}
|
src={targetTypeMap.get(key)?.[1]}
|
||||||
/>
|
/>
|
||||||
<div>{t(targetTypeMap.get(key)?.[0] || '')}</div>
|
<div>
|
||||||
|
{t(targetTypeMap.get(key)?.[0] || "")}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
|
@ -392,12 +422,12 @@ const Edit = () => {
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem hidden={tab != "base"}>
|
<FormItem hidden={tab != "base"}>
|
||||||
<FormLabel className="w-full flex justify-between">
|
<FormLabel className="w-full flex justify-between">
|
||||||
<div>{t('domain.management.edit.target.access')}</div>
|
<div>{t("domain.management.edit.target.access")}</div>
|
||||||
<AccessEdit
|
<AccessEdit
|
||||||
trigger={
|
trigger={
|
||||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||||
<Plus size={14} />
|
<Plus size={14} />
|
||||||
{t('add')}
|
{t("add")}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
op="add"
|
op="add"
|
||||||
|
@ -411,12 +441,19 @@ const Edit = () => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder={t('domain.management.edit.target.access.not.empty.message')} />
|
<SelectValue
|
||||||
|
placeholder={t(
|
||||||
|
"domain.management.edit.target.access.not.empty.message"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectGroup>
|
<SelectGroup>
|
||||||
<SelectLabel>
|
<SelectLabel>
|
||||||
{t('domain.management.edit.target.access.content.label')} {form.getValues().targetAccess}
|
{t(
|
||||||
|
"domain.management.edit.target.access.content.label"
|
||||||
|
)}{" "}
|
||||||
|
{form.getValues().targetAccess}
|
||||||
</SelectLabel>
|
</SelectLabel>
|
||||||
<SelectItem value="emptyId">
|
<SelectItem value="emptyId">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
|
@ -452,9 +489,7 @@ const Edit = () => {
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem hidden={tab != "advance" || targetType != "ssh"}>
|
<FormItem hidden={tab != "advance" || targetType != "ssh"}>
|
||||||
<FormLabel className="w-full flex justify-between">
|
<FormLabel className="w-full flex justify-between">
|
||||||
<div>
|
<div>{t("domain.management.edit.group.label")}</div>
|
||||||
{t('domain.management.edit.group.label')}
|
|
||||||
</div>
|
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Select
|
<Select
|
||||||
|
@ -466,7 +501,11 @@ const Edit = () => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder={t('domain.management.edit.group.not.empty.message')} />
|
<SelectValue
|
||||||
|
placeholder={t(
|
||||||
|
"domain.management.edit.group.not.empty.message"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="emptyId">
|
<SelectItem value="emptyId">
|
||||||
|
@ -511,10 +550,12 @@ const Edit = () => {
|
||||||
name="variables"
|
name="variables"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem hidden={tab != "advance"}>
|
<FormItem hidden={tab != "advance"}>
|
||||||
<FormLabel>{t('variables')}</FormLabel>
|
<FormLabel>{t("variables")}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Textarea
|
<Textarea
|
||||||
placeholder={t('domain.management.edit.variables.placeholder')}
|
placeholder={t(
|
||||||
|
"domain.management.edit.variables.placeholder"
|
||||||
|
)}
|
||||||
{...field}
|
{...field}
|
||||||
className="placeholder:whitespace-pre-wrap"
|
className="placeholder:whitespace-pre-wrap"
|
||||||
/>
|
/>
|
||||||
|
@ -530,10 +571,12 @@ const Edit = () => {
|
||||||
name="nameservers"
|
name="nameservers"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem hidden={tab != "advance"}>
|
<FormItem hidden={tab != "advance"}>
|
||||||
<FormLabel>{t('dns')}</FormLabel>
|
<FormLabel>{t("dns")}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Textarea
|
<Textarea
|
||||||
placeholder={t('domain.management.edit.dns.placeholder')}
|
placeholder={t(
|
||||||
|
"domain.management.edit.dns.placeholder"
|
||||||
|
)}
|
||||||
{...field}
|
{...field}
|
||||||
className="placeholder:whitespace-pre-wrap"
|
className="placeholder:whitespace-pre-wrap"
|
||||||
/>
|
/>
|
||||||
|
@ -545,7 +588,7 @@ const Edit = () => {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<Button type="submit">{t('save')}</Button>
|
<Button type="submit">{t("save")}</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
|
@ -41,7 +41,7 @@ const Home = () => {
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const query = new URLSearchParams(location.search);
|
const query = new URLSearchParams(location.search);
|
||||||
|
@ -129,12 +129,12 @@ const Home = () => {
|
||||||
await save(domain);
|
await save(domain);
|
||||||
|
|
||||||
toast.toast({
|
toast.toast({
|
||||||
title: t('operation.succeed'),
|
title: t("operation.succeed"),
|
||||||
description: t('domain.management.start.deploy.succeed.tips'),
|
description: t("domain.management.start.deploy.succeed.tips"),
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast.toast({
|
toast.toast({
|
||||||
title: t('domain.management.execution.failed'),
|
title: t("domain.management.execution.failed"),
|
||||||
description: (
|
description: (
|
||||||
// 这里的 text 只是占位作用,实际文案在 src/i18n/locales/[lang].json
|
// 这里的 text 只是占位作用,实际文案在 src/i18n/locales/[lang].json
|
||||||
<Trans i18nKey="domain.management.execution.failed.tips">
|
<Trans i18nKey="domain.management.execution.failed.tips">
|
||||||
|
@ -142,7 +142,9 @@ const Home = () => {
|
||||||
<Link
|
<Link
|
||||||
to={`/history?domain=${domain.id}`}
|
to={`/history?domain=${domain.id}`}
|
||||||
className="underline text-blue-500"
|
className="underline text-blue-500"
|
||||||
>text2</Link>
|
>
|
||||||
|
text2
|
||||||
|
</Link>
|
||||||
text3
|
text3
|
||||||
</Trans>
|
</Trans>
|
||||||
),
|
),
|
||||||
|
@ -176,10 +178,10 @@ const Home = () => {
|
||||||
<div className="">
|
<div className="">
|
||||||
<Toaster />
|
<Toaster />
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<div className="text-muted-foreground">{t('domain.management.name')}</div>
|
<div className="text-muted-foreground">
|
||||||
<Button onClick={handleCreateClick}>
|
{t("domain.management.name")}
|
||||||
{t('domain.add')}
|
</div>
|
||||||
</Button>
|
<Button onClick={handleCreateClick}>{t("domain.add")}</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!domains.length ? (
|
{!domains.length ? (
|
||||||
|
@ -190,26 +192,32 @@ const Home = () => {
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div className="text-center text-sm text-muted-foreground mt-3">
|
<div className="text-center text-sm text-muted-foreground mt-3">
|
||||||
{t('domain.management.empty')}
|
{t("domain.management.empty")}
|
||||||
</div>
|
</div>
|
||||||
<Button onClick={handleCreateClick} className="mt-3">
|
<Button onClick={handleCreateClick} className="mt-3">
|
||||||
{t('domain.add')}
|
{t("domain.add")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="hidden sm:flex sm:flex-row text-muted-foreground text-sm border-b dark:border-stone-500 sm:p-2 mt-5">
|
<div className="hidden sm:flex sm:flex-row text-muted-foreground text-sm border-b dark:border-stone-500 sm:p-2 mt-5">
|
||||||
<div className="w-36">{t('domain')}</div>
|
<div className="w-36">{t("domain")}</div>
|
||||||
<div className="w-40">{t('domain.management.expiry.date')}</div>
|
<div className="w-40">{t("domain.management.expiry.date")}</div>
|
||||||
<div className="w-32">{t('domain.management.last.execution.status')}</div>
|
<div className="w-32">
|
||||||
<div className="w-64">{t('domain.management.last.execution.stage')}</div>
|
{t("domain.management.last.execution.status")}
|
||||||
<div className="w-40 sm:ml-2">{t('domain.management.last.execution.time')}</div>
|
</div>
|
||||||
<div className="w-24">{t('domain.management.enable')}</div>
|
<div className="w-64">
|
||||||
<div className="grow">{t('operation')}</div>
|
{t("domain.management.last.execution.stage")}
|
||||||
|
</div>
|
||||||
|
<div className="w-40 sm:ml-2">
|
||||||
|
{t("domain.management.last.execution.time")}
|
||||||
|
</div>
|
||||||
|
<div className="w-24">{t("domain.management.enable")}</div>
|
||||||
|
<div className="grow">{t("operation")}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="sm:hidden flex text-sm text-muted-foreground">
|
<div className="sm:hidden flex text-sm text-muted-foreground">
|
||||||
{t('domain')}
|
{t("domain")}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{domains.map((domain) => (
|
{domains.map((domain) => (
|
||||||
|
@ -217,15 +225,26 @@ const Home = () => {
|
||||||
className="flex flex-col sm:flex-row text-secondary-foreground border-b dark:border-stone-500 sm:p-2 hover:bg-muted/50 text-sm"
|
className="flex flex-col sm:flex-row text-secondary-foreground border-b dark:border-stone-500 sm:p-2 hover:bg-muted/50 text-sm"
|
||||||
key={domain.id}
|
key={domain.id}
|
||||||
>
|
>
|
||||||
<div className="sm:w-36 w-full pt-1 sm:pt-0 flex items-center">
|
<div className="sm:w-36 w-full pt-1 sm:pt-0 flex items-center truncate">
|
||||||
{domain.domain}
|
{domain.domain.split(";").map((item) => (
|
||||||
|
<>
|
||||||
|
{item}
|
||||||
|
<br />
|
||||||
|
</>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="sm:w-40 w-full pt-1 sm:pt-0 flex items-center">
|
<div className="sm:w-40 w-full pt-1 sm:pt-0 flex items-center">
|
||||||
<div>
|
<div>
|
||||||
{domain.expiredAt ? (
|
{domain.expiredAt ? (
|
||||||
<>
|
<>
|
||||||
<div>{t('domain.management.expiry.date1', { date: 90 })}</div>
|
<div>
|
||||||
<div>{t('domain.management.expiry.date2', { date: getDate(domain.expiredAt) })}</div>
|
{t("domain.management.expiry.date1", { date: 90 })}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{t("domain.management.expiry.date2", {
|
||||||
|
date: getDate(domain.expiredAt),
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
"---"
|
"---"
|
||||||
|
@ -269,7 +288,7 @@ const Home = () => {
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<div className="border rounded-sm px-3 bg-background text-muted-foreground text-xs">
|
<div className="border rounded-sm px-3 bg-background text-muted-foreground text-xs">
|
||||||
{domain.enabled ? t('disable') : t('enable')}
|
{domain.enabled ? t("disable") : t("enable")}
|
||||||
</div>
|
</div>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
@ -281,7 +300,7 @@ const Home = () => {
|
||||||
className="p-0"
|
className="p-0"
|
||||||
onClick={() => handleHistoryClick(domain.id)}
|
onClick={() => handleHistoryClick(domain.id)}
|
||||||
>
|
>
|
||||||
{t('deployment.log.name')}
|
{t("deployment.log.name")}
|
||||||
</Button>
|
</Button>
|
||||||
<Show when={domain.enabled ? true : false}>
|
<Show when={domain.enabled ? true : false}>
|
||||||
<Separator orientation="vertical" className="h-4 mx-2" />
|
<Separator orientation="vertical" className="h-4 mx-2" />
|
||||||
|
@ -290,7 +309,7 @@ const Home = () => {
|
||||||
className="p-0"
|
className="p-0"
|
||||||
onClick={() => handleRightNowClick(domain)}
|
onClick={() => handleRightNowClick(domain)}
|
||||||
>
|
>
|
||||||
{t('domain.management.start.deploying')}
|
{t("domain.management.start.deploying")}
|
||||||
</Button>
|
</Button>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
|
@ -307,7 +326,7 @@ const Home = () => {
|
||||||
className="p-0"
|
className="p-0"
|
||||||
onClick={() => handleForceClick(domain)}
|
onClick={() => handleForceClick(domain)}
|
||||||
>
|
>
|
||||||
{t('domain.management.forced.deployment')}
|
{t("domain.management.forced.deployment")}
|
||||||
</Button>
|
</Button>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
|
@ -318,7 +337,7 @@ const Home = () => {
|
||||||
className="p-0"
|
className="p-0"
|
||||||
onClick={() => handleDownloadClick(domain)}
|
onClick={() => handleDownloadClick(domain)}
|
||||||
>
|
>
|
||||||
{t('download')}
|
{t("download")}
|
||||||
</Button>
|
</Button>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
|
@ -328,24 +347,26 @@ const Home = () => {
|
||||||
<AlertDialog>
|
<AlertDialog>
|
||||||
<AlertDialogTrigger asChild>
|
<AlertDialogTrigger asChild>
|
||||||
<Button variant={"link"} className="p-0">
|
<Button variant={"link"} className="p-0">
|
||||||
{t('delete')}
|
{t("delete")}
|
||||||
</Button>
|
</Button>
|
||||||
</AlertDialogTrigger>
|
</AlertDialogTrigger>
|
||||||
<AlertDialogContent>
|
<AlertDialogContent>
|
||||||
<AlertDialogHeader>
|
<AlertDialogHeader>
|
||||||
<AlertDialogTitle>{t('domain.delete')}</AlertDialogTitle>
|
<AlertDialogTitle>
|
||||||
|
{t("domain.delete")}
|
||||||
|
</AlertDialogTitle>
|
||||||
<AlertDialogDescription>
|
<AlertDialogDescription>
|
||||||
{t('domain.management.delete.confirm')}
|
{t("domain.management.delete.confirm")}
|
||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
<AlertDialogCancel>{t('cancel')}</AlertDialogCancel>
|
<AlertDialogCancel>{t("cancel")}</AlertDialogCancel>
|
||||||
<AlertDialogAction
|
<AlertDialogAction
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleDeleteClick(domain.id);
|
handleDeleteClick(domain.id);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('confirm')}
|
{t("confirm")}
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
|
@ -357,7 +378,7 @@ const Home = () => {
|
||||||
className="p-0"
|
className="p-0"
|
||||||
onClick={() => handleEditClick(domain.id)}
|
onClick={() => handleEditClick(domain.id)}
|
||||||
>
|
>
|
||||||
{t('edit')}
|
{t("edit")}
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -40,20 +40,17 @@ const History = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollArea className="h-[80vh] overflow-hidden">
|
<ScrollArea className="h-[80vh] overflow-hidden">
|
||||||
<div className="text-muted-foreground">{t('deployment.log.name')}</div>
|
<div className="text-muted-foreground">{t("deployment.log.name")}</div>
|
||||||
{!deployments?.length ? (
|
{!deployments?.length ? (
|
||||||
<>
|
<>
|
||||||
<Alert className="max-w-[40em] mx-auto mt-20">
|
<Alert className="max-w-[40em] mx-auto mt-20">
|
||||||
<AlertTitle>{t('no.data')}</AlertTitle>
|
<AlertTitle>{t("no.data")}</AlertTitle>
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
<div className="flex items-center mt-5">
|
<div className="flex items-center mt-5">
|
||||||
<div>
|
<div>
|
||||||
<Smile className="text-yellow-400" size={36} />
|
<Smile className="text-yellow-400" size={36} />
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-2">
|
<div className="ml-2"> {t("deployment.log.empty")}</div>
|
||||||
{" "}
|
|
||||||
{t('deployment.log.empty')}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 flex justify-end">
|
<div className="mt-2 flex justify-end">
|
||||||
<Button
|
<Button
|
||||||
|
@ -61,7 +58,7 @@ const History = () => {
|
||||||
navigate("/");
|
navigate("/");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('domain.add')}
|
{t("domain.add")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
|
@ -70,16 +67,18 @@ const History = () => {
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="hidden sm:flex sm:flex-row text-muted-foreground text-sm border-b dark:border-stone-500 sm:p-2 mt-5">
|
<div className="hidden sm:flex sm:flex-row text-muted-foreground text-sm border-b dark:border-stone-500 sm:p-2 mt-5">
|
||||||
<div className="w-48">{t('domain')}</div>
|
<div className="w-48">{t("domain")}</div>
|
||||||
|
|
||||||
<div className="w-24">{t('deployment.log.status')}</div>
|
<div className="w-24">{t("deployment.log.status")}</div>
|
||||||
<div className="w-56">{t('deployment.log.stage')}</div>
|
<div className="w-56">{t("deployment.log.stage")}</div>
|
||||||
<div className="w-56 sm:ml-2 text-center">{t('deployment.log.last.execution.time')}</div>
|
<div className="w-56 sm:ml-2 text-center">
|
||||||
|
{t("deployment.log.last.execution.time")}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="grow">{t('operation')}</div>
|
<div className="grow">{t("operation")}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="sm:hidden flex text-sm text-muted-foreground">
|
<div className="sm:hidden flex text-sm text-muted-foreground">
|
||||||
{t('deployment.log.name')}
|
{t("deployment.log.name")}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{deployments?.map((deployment) => (
|
{deployments?.map((deployment) => (
|
||||||
|
@ -88,7 +87,14 @@ const History = () => {
|
||||||
className="flex flex-col sm:flex-row text-secondary-foreground border-b dark:border-stone-500 sm:p-2 hover:bg-muted/50 text-sm"
|
className="flex flex-col sm:flex-row text-secondary-foreground border-b dark:border-stone-500 sm:p-2 hover:bg-muted/50 text-sm"
|
||||||
>
|
>
|
||||||
<div className="sm:w-48 w-full pt-1 sm:pt-0 flex items-center">
|
<div className="sm:w-48 w-full pt-1 sm:pt-0 flex items-center">
|
||||||
{deployment.expand.domain?.domain}
|
{deployment.expand.domain?.domain
|
||||||
|
.split(";")
|
||||||
|
.map((domain: string) => (
|
||||||
|
<>
|
||||||
|
{domain}
|
||||||
|
<br />
|
||||||
|
</>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="sm:w-24 w-full pt-1 sm:pt-0 flex items-center">
|
<div className="sm:w-24 w-full pt-1 sm:pt-0 flex items-center">
|
||||||
<DeployState deployment={deployment} />
|
<DeployState deployment={deployment} />
|
||||||
|
@ -106,14 +112,14 @@ const History = () => {
|
||||||
<Sheet>
|
<Sheet>
|
||||||
<SheetTrigger asChild>
|
<SheetTrigger asChild>
|
||||||
<Button variant={"link"} className="p-0">
|
<Button variant={"link"} className="p-0">
|
||||||
{t('deployment.log.detail.button.text')}
|
{t("deployment.log.detail.button.text")}
|
||||||
</Button>
|
</Button>
|
||||||
</SheetTrigger>
|
</SheetTrigger>
|
||||||
<SheetContent className="sm:max-w-5xl">
|
<SheetContent className="sm:max-w-5xl">
|
||||||
<SheetHeader>
|
<SheetHeader>
|
||||||
<SheetTitle>
|
<SheetTitle>
|
||||||
{deployment.expand.domain?.domain}-{deployment.id}
|
{deployment.expand.domain?.domain}-{deployment.id}
|
||||||
{t('deployment.log.detail')}
|
{t("deployment.log.detail")}
|
||||||
</SheetTitle>
|
</SheetTitle>
|
||||||
</SheetHeader>
|
</SheetHeader>
|
||||||
<div className="bg-gray-950 text-stone-100 p-5 text-sm h-[80dvh]">
|
<div className="bg-gray-950 text-stone-100 p-5 text-sm h-[80dvh]">
|
||||||
|
|
Loading…
Reference in New Issue