feat: deploy provider category
This commit is contained in:
@@ -35,7 +35,7 @@ const CertificateDetailDrawer = ({ data, loading, trigger, ...props }: Certifica
|
||||
loading={loading}
|
||||
placement="right"
|
||||
title={`Certificate #${data?.id}`}
|
||||
width={640}
|
||||
width={720}
|
||||
onClose={() => setOpen(false)}
|
||||
>
|
||||
<Show when={!!data}>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { memo, useEffect, useRef, useState } from "react";
|
||||
import { memo, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Avatar, Card, Col, Empty, Flex, Input, type InputRef, Row, Typography } from "antd";
|
||||
import { Avatar, Card, Col, Empty, Flex, Input, type InputRef, Row, Tabs, Tooltip, Typography } from "antd";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
import { deployProvidersMap } from "@/domain/provider";
|
||||
import { DEPLOY_CATEGORIES, type DeployProvider, deployProvidersMap } from "@/domain/provider";
|
||||
|
||||
export type DeployProviderPickerProps = {
|
||||
className?: string;
|
||||
@@ -24,15 +24,26 @@ const DeployProviderPicker = ({ className, style, autoFocus, placeholder, onSele
|
||||
}
|
||||
}, []);
|
||||
|
||||
const providers = Array.from(deployProvidersMap.values());
|
||||
const filteredProviders = providers.filter((provider) => {
|
||||
if (keyword) {
|
||||
const value = keyword.toLowerCase();
|
||||
return provider.type.toLowerCase().includes(value) || t(provider.name).toLowerCase().includes(value);
|
||||
}
|
||||
const [category, setCategory] = useState<string>(DEPLOY_CATEGORIES.ALL);
|
||||
|
||||
return true;
|
||||
});
|
||||
const providers = useMemo(() => {
|
||||
return Array.from(deployProvidersMap.values())
|
||||
.filter((provider) => {
|
||||
if (keyword) {
|
||||
const value = keyword.toLowerCase();
|
||||
return provider.type.toLowerCase().includes(value) || t(provider.name).toLowerCase().includes(value);
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.filter((provider) => {
|
||||
if (category && category !== DEPLOY_CATEGORIES.ALL) {
|
||||
return provider.category === category;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}, [keyword, category]);
|
||||
|
||||
const handleProviderTypeSelect = (value: string) => {
|
||||
onSelect?.(value);
|
||||
@@ -43,29 +54,55 @@ const DeployProviderPicker = ({ className, style, autoFocus, placeholder, onSele
|
||||
<Input.Search ref={keywordInputRef} 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} xs={24} md={12} 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 flex-1">{t(provider.name)}</Typography.Text>
|
||||
</Flex>
|
||||
</Card>
|
||||
</Col>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
</Show>
|
||||
<Flex>
|
||||
<Tabs
|
||||
defaultActiveKey={DEPLOY_CATEGORIES.ALL}
|
||||
items={[
|
||||
DEPLOY_CATEGORIES.ALL,
|
||||
DEPLOY_CATEGORIES.CDN,
|
||||
DEPLOY_CATEGORIES.STORAGE,
|
||||
DEPLOY_CATEGORIES.LOADBALANCE,
|
||||
DEPLOY_CATEGORIES.FIREWALL,
|
||||
DEPLOY_CATEGORIES.LIVE,
|
||||
DEPLOY_CATEGORIES.OTHER,
|
||||
].map((key) => ({
|
||||
key: key,
|
||||
label: t(`provider.category.${key}`),
|
||||
}))}
|
||||
size="small"
|
||||
tabBarStyle={{ marginLeft: "-1rem" }}
|
||||
tabPosition="left"
|
||||
onChange={(key) => setCategory(key)}
|
||||
/>
|
||||
|
||||
<div className="flex-1">
|
||||
<Show when={providers.length > 0} fallback={<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}>
|
||||
<Row gutter={[16, 16]}>
|
||||
{providers.map((provider, index) => {
|
||||
return (
|
||||
<Col key={index} xs={24} md={12} 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);
|
||||
}}
|
||||
>
|
||||
<Tooltip title={t(provider.name)} mouseEnterDelay={1}>
|
||||
<Flex className="size-full overflow-hidden" align="center" gap={8}>
|
||||
<Avatar src={provider.icon} size="small" />
|
||||
<Typography.Text className="line-clamp-2 flex-1">{t(provider.name)}</Typography.Text>
|
||||
</Flex>
|
||||
</Tooltip>
|
||||
</Card>
|
||||
</Col>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
</Show>
|
||||
</div>
|
||||
</Flex>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -36,7 +36,7 @@ const WorkflowRunDetailDrawer = ({ data, loading, trigger, ...props }: WorkflowR
|
||||
loading={loading}
|
||||
placement="right"
|
||||
title={`WorkflowRun #${data?.id}`}
|
||||
width={640}
|
||||
width={720}
|
||||
onClose={() => setOpen(false)}
|
||||
>
|
||||
<Show when={!!data}>
|
||||
|
||||
@@ -307,7 +307,7 @@ const SharedNodeConfigDrawer = ({
|
||||
loading={loading}
|
||||
open={open}
|
||||
title={<div className="max-w-[480px] truncate">{node.name}</div>}
|
||||
width={640}
|
||||
width={720}
|
||||
onClose={handleClose}
|
||||
>
|
||||
{children}
|
||||
|
||||
Reference in New Issue
Block a user