feat: separate access providers and dns providers
This commit is contained in:
67
ui/src/components/provider/ApplyDNSProviderPicker.tsx
Normal file
67
ui/src/components/provider/ApplyDNSProviderPicker.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import { memo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Avatar, Card, Col, Empty, Flex, Input, Row, Typography } from "antd";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
import { applyDNSProvidersMap } from "@/domain/provider";
|
||||
|
||||
export type ApplyDNSProviderPickerProps = {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
placeholder?: string;
|
||||
onSelect?: (value: string) => void;
|
||||
};
|
||||
|
||||
const ApplyDNSProviderPicker = ({ className, style, placeholder, onSelect }: ApplyDNSProviderPickerProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [keyword, setKeyword] = useState<string>();
|
||||
|
||||
const providers = Array.from(applyDNSProvidersMap.values());
|
||||
const filteredProviders = providers.filter((provider) => {
|
||||
if (keyword) {
|
||||
const value = keyword.toLowerCase();
|
||||
return provider.type.toLowerCase().includes(value) || provider.name.toLowerCase().includes(value);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
const handleProviderTypeSelect = (value: string) => {
|
||||
onSelect?.(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={className} style={style}>
|
||||
<Input.Search placeholder={placeholder} onChange={(e) => setKeyword(e.target.value.trim())} />
|
||||
|
||||
<div className="mt-4">
|
||||
<Show when={filteredProviders.length > 0} fallback={<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}>
|
||||
<Row gutter={[16, 16]}>
|
||||
{filteredProviders.map((provider, index) => {
|
||||
return (
|
||||
<Col key={index} span={12}>
|
||||
<Card
|
||||
className="h-16 w-full overflow-hidden shadow-sm"
|
||||
styles={{ body: { height: "100%", padding: "0.5rem 1rem" } }}
|
||||
hoverable
|
||||
onClick={() => {
|
||||
handleProviderTypeSelect(provider.type);
|
||||
}}
|
||||
>
|
||||
<Flex className="size-full overflow-hidden" align="center" gap={8}>
|
||||
<Avatar src={provider.icon} size="small" />
|
||||
<Typography.Text className="line-clamp-2">{t(provider.name)}</Typography.Text>
|
||||
</Flex>
|
||||
</Card>
|
||||
</Col>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ApplyDNSProviderPicker);
|
||||
51
ui/src/components/provider/ApplyDNSProviderSelect.tsx
Normal file
51
ui/src/components/provider/ApplyDNSProviderSelect.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { memo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Avatar, Select, type SelectProps, Space, Typography } from "antd";
|
||||
|
||||
import { applyDNSProvidersMap } from "@/domain/provider";
|
||||
|
||||
export type ApplyDNSProviderSelectProps = Omit<
|
||||
SelectProps,
|
||||
"filterOption" | "filterSort" | "labelRender" | "options" | "optionFilterProp" | "optionLabelProp" | "optionRender"
|
||||
>;
|
||||
|
||||
const ApplyDNSProviderSelect = (props: ApplyDNSProviderSelectProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const options = Array.from(applyDNSProvidersMap.values()).map((item) => ({
|
||||
key: item.type,
|
||||
value: item.type,
|
||||
label: t(item.name),
|
||||
}));
|
||||
|
||||
const renderOption = (key: string) => {
|
||||
const provider = applyDNSProvidersMap.get(key);
|
||||
return (
|
||||
<Space className="max-w-full grow overflow-hidden truncate" size={4}>
|
||||
<Avatar src={provider?.icon} size="small" />
|
||||
<Typography.Text className="leading-loose" ellipsis>
|
||||
{t(provider?.name ?? "")}
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Select
|
||||
{...props}
|
||||
labelRender={({ label, value }) => {
|
||||
if (label) {
|
||||
return renderOption(value as string);
|
||||
}
|
||||
|
||||
return <Typography.Text type="secondary">{props.placeholder}</Typography.Text>;
|
||||
}}
|
||||
options={options}
|
||||
optionFilterProp={undefined}
|
||||
optionLabelProp={undefined}
|
||||
optionRender={(option) => renderOption(option.data.value)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ApplyDNSProviderSelect);
|
||||
@@ -8,10 +8,11 @@ import { deployProvidersMap } from "@/domain/provider";
|
||||
export type DeployProviderPickerProps = {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
placeholder?: string;
|
||||
onSelect?: (value: string) => void;
|
||||
};
|
||||
|
||||
const DeployProviderPicker = ({ className, style, onSelect }: DeployProviderPickerProps) => {
|
||||
const DeployProviderPicker = ({ className, style, placeholder, onSelect }: DeployProviderPickerProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [keyword, setKeyword] = useState<string>();
|
||||
@@ -32,7 +33,7 @@ const DeployProviderPicker = ({ className, style, onSelect }: DeployProviderPick
|
||||
|
||||
return (
|
||||
<div className={className} style={style}>
|
||||
<Input.Search placeholder={t("workflow_node.deploy.search.provider.placeholder")} onChange={(e) => setKeyword(e.target.value.trim())} />
|
||||
<Input.Search placeholder={placeholder} onChange={(e) => setKeyword(e.target.value.trim())} />
|
||||
|
||||
<div className="mt-4">
|
||||
<Show when={filteredProviders.length > 0} fallback={<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}>
|
||||
|
||||
Reference in New Issue
Block a user