feat(ui): enhance acme profiles and preferred chain autocomplete

This commit is contained in:
Fu Diwei 2025-12-18 18:07:23 +08:00
parent 7b67935768
commit 8460d08b6c
2 changed files with 61 additions and 12 deletions

View File

@ -1,9 +1,11 @@
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { useControllableValue } from "ahooks";
import { useControllableValue, useMount } from "ahooks";
import { Avatar, Select, Typography, theme } from "antd";
import { type CAProvider, caProvidersMap } from "@/domain/provider";
import { useZustandShallowSelector } from "@/hooks";
import { useSSLProviderSettingsStore } from "@/stores/settings";
import { type SharedSelectProps, useSelectDataSource } from "./_shared";
@ -17,12 +19,20 @@ const CAProviderSelect = ({ showAvailability, showDefault, onFilter, ...props }:
const { token: themeToken } = theme.useToken();
const { settings: sslProviderSettings, loadSettings: loadSSLProviderSettings } = useSSLProviderSettingsStore(
useZustandShallowSelector(["settings", "loadSettings"])
);
useMount(() => loadSSLProviderSettings(false));
const [value, setValue] = useControllableValue<string | undefined>(props, {
valuePropName: "value",
defaultValuePropName: "defaultValue",
trigger: "onChange",
});
const defaultCAProvider = useMemo(() => {
return caProvidersMap.get(sslProviderSettings.provider);
}, [sslProviderSettings]);
const dataSources = useSelectDataSource({
dataSource: Array.from(caProvidersMap.values()),
filters: [onFilter!],
@ -54,22 +64,27 @@ const CAProviderSelect = ({ showAvailability, showDefault, onFilter, ...props }:
},
].filter((group) => group.options.length > 0);
const temp = showAvailability
return showAvailability
? showDefault
? [{ label: t("provider.text.default_group"), options: [defaultOption] }, ...groupOptions]
: groupOptions
: showDefault
? [defaultOption, ...plainOptions]
: plainOptions;
return temp;
}, [showAvailability, showDefault, dataSources]);
const renderOption = (key: string) => {
if (key === "") {
return (
<div className="truncate">
<Typography.Text ellipsis>{showAvailability ? t("provider.text.default_ca_in_group") : t("provider.text.default_ca")}</Typography.Text>
<div className="flex items-center justify-between gap-4">
<div className="flex-1 truncate">
<Typography.Text ellipsis>{showAvailability ? t("provider.text.default_ca_in_group") : t("provider.text.default_ca")}</Typography.Text>
</div>
{defaultCAProvider && (
<Typography.Text className="text-xs" type="secondary" ellipsis>
{t(defaultCAProvider.name)}
</Typography.Text>
)}
</div>
);
}

View File

@ -510,7 +510,29 @@ const BizApplyNodeConfigForm = ({ node, ...props }: BizApplyNodeConfigFormProps)
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.preferred_chain.tooltip") }}></span>}
>
<Input allowClear placeholder={t("workflow_node.apply.form.preferred_chain.placeholder")} />
<AutoComplete
allowClear
options={[
{
ca: "Let's Encrypt",
roots: ["ISRG", "ISRG Root X1", "ISRG Root X2"],
},
{
ca: "Google Trust Services",
roots: ["GTS", "GTS Root R1", "GTS Root R2", "GTS Root R3", "GTS Root R4", "GlobalSign", "GlobalSign R4"],
},
].map((e) => ({
label: e.ca,
options: e.roots.map((s) => ({
label: s,
value: s,
})),
}))}
placeholder={t("workflow_node.apply.form.preferred_chain.placeholder")}
showSearch={{
filterOption: (inputValue, option) => "value" in option! && String(option.value).toLowerCase().includes(inputValue.toLowerCase()),
}}
/>
</Form.Item>
<Form.Item
@ -522,10 +544,21 @@ const BizApplyNodeConfigForm = ({ node, ...props }: BizApplyNodeConfigFormProps)
>
<AutoComplete
allowClear
options={["classic", "tlsserver", "shortlived"].map((s) => ({ value: s }))}
options={[
{
ca: "Let's Encrypt",
profiles: ["classic", "tlsserver", "shortlived"],
},
].map((e) => ({
label: e.ca,
options: e.profiles.map((s) => ({
label: s,
value: s,
})),
}))}
placeholder={t("workflow_node.apply.form.acme_profile.placeholder")}
showSearch={{
filterOption: (inputValue, option) => option!.value.toLowerCase().includes(inputValue.toLowerCase()),
filterOption: (inputValue, option) => "value" in option! && String(option.value).toLowerCase().includes(inputValue.toLowerCase()),
}}
/>
</Form.Item>
@ -715,13 +748,14 @@ const InternalEmailInput = memo(
backfill
defaultValue={value}
disabled={disabled}
filterOption
options={options}
placeholder={placeholder}
showSearch
showSearch={{
filterOption: true,
onSearch: handleSearch,
}}
value={value}
onChange={handleChange}
onSearch={handleSearch}
/>
);
}