From d1c1132e6ef1cde30e97960b2c2be7f719cf9518 Mon Sep 17 00:00:00 2001 From: jialin Date: Thu, 27 Nov 2025 15:51:37 +0800 Subject: [PATCH] style: button for empty --- src/pages/_components/no-result.tsx | 25 ++++++++++++++++--- src/pages/api-keys/index.tsx | 10 +++----- src/pages/backends/config/index.ts | 17 ++++++++++--- src/pages/backends/index.tsx | 9 +++---- src/pages/cluster-management/clusters.tsx | 12 ++++----- src/pages/cluster-management/credentials.tsx | 13 +++------- src/pages/llmodels/components/table-list.tsx | 14 ++++------- .../llmodels/hooks/use-no-resource-result.tsx | 9 +++---- src/pages/users/index.tsx | 10 +++----- 9 files changed, 64 insertions(+), 55 deletions(-) diff --git a/src/pages/_components/no-result.tsx b/src/pages/_components/no-result.tsx index f00bcefc..6a02b622 100644 --- a/src/pages/_components/no-result.tsx +++ b/src/pages/_components/no-result.tsx @@ -1,4 +1,4 @@ -import { Empty, EmptyProps, Typography } from 'antd'; +import { Button, Empty, EmptyProps, Typography } from 'antd'; import _ from 'lodash'; import React, { useMemo } from 'react'; import styled from 'styled-components'; @@ -54,9 +54,19 @@ const NoResult: React.FC< loading?: boolean; loadend?: boolean; dataSource?: any[]; + buttonText?: React.ReactNode; + onClick?: () => void; } > = (props) => { - const { filters, noFoundText, loadend, loading, dataSource } = props; + const { + filters, + noFoundText, + loadend, + loading, + dataSource, + buttonText, + onClick + } = props; const hasFilters = useMemo(() => { const filterValues = _.omit(filters, ['page', 'perPage']); @@ -70,6 +80,15 @@ const NoResult: React.FC< }); }, [filters]); + const renderChildren = () => { + if (!buttonText || !onClick) return null; + return ( + + ); + }; + return ( <> {!loading && loadend && !dataSource?.length ? ( @@ -96,7 +115,7 @@ const NoResult: React.FC< } > - {!hasFilters && props.children} + {!hasFilters && renderChildren()} ) : ( diff --git a/src/pages/api-keys/index.tsx b/src/pages/api-keys/index.tsx index 3e2e9a25..194d09ec 100644 --- a/src/pages/api-keys/index.tsx +++ b/src/pages/api-keys/index.tsx @@ -6,7 +6,7 @@ import type { PageActionType } from '@/config/types'; import useTableFetch from '@/hooks/use-table-fetch'; import { useIntl } from '@umijs/max'; import useMemoizedFn from 'ahooks/lib/useMemoizedFn'; -import { Button, ConfigProvider, Table } from 'antd'; +import { ConfigProvider, Table } from 'antd'; import { useState } from 'react'; import NoResult from '../_components/no-result'; import PageBox from '../_components/page-box'; @@ -111,11 +111,9 @@ const APIKeys: React.FC = () => { })} title={intl.formatMessage({ id: 'noresult.keys.title' })} subTitle={intl.formatMessage({ id: 'noresult.keys.subTitle' })} - > - - + onClick={handleAddKey} + buttonText={intl.formatMessage({ id: 'noresult.button.add' })} + > ); }; diff --git a/src/pages/backends/config/index.ts b/src/pages/backends/config/index.ts index e70e9e95..20f0c12f 100644 --- a/src/pages/backends/config/index.ts +++ b/src/pages/backends/config/index.ts @@ -3,7 +3,6 @@ import SGLangLogo from '@/assets/logo/sglang.png'; import vLLMLogo from '@/assets/logo/vllm.png'; import VoxBoxLogo from '@/assets/logo/voxbox.png'; import icons from '@/components/icon-font/icons'; -import { GPUSTACK_API_BASE_URL } from '@/config/settings'; import { backendOptionsMap } from '@/pages/llmodels/config/backend-parameters'; import { GPUDriverMap, @@ -191,11 +190,23 @@ export const frameworks = [ } ]; -export const yamlTemplate = `# backend configuration template +export const yamlTemplate = `# ---------------------------------------- +# custom backend configuration template +# ---------------------------------------- +# backend_name: +# - required +# - must be endwith '-custom' +# version_configs: +# - image_name: required +# - run_command: required +# - custom_framework: +# - optional +# - choose from: ${Object.values(GPUDriverMap).join(', ')}, CPU + backend_name: vllm-custom description: this is my custom vllm backend default_version: v0.11.0 -health_check_path: /${GPUSTACK_API_BASE_URL}/models +health_check_path: /v1/models default_backend_param: - --host default_run_command: vllm serve {{model_path}} --port {{port}} --host {{worker_ip}} --served-model-name {{model_name}} diff --git a/src/pages/backends/index.tsx b/src/pages/backends/index.tsx index 62f0d924..fc1c4358 100644 --- a/src/pages/backends/index.tsx +++ b/src/pages/backends/index.tsx @@ -5,7 +5,6 @@ import { PageActionType } from '@/config/types'; import useTableFetch from '@/hooks/use-table-fetch'; import { useIntl } from '@umijs/max'; import useMemoizedFn from 'ahooks/lib/useMemoizedFn'; -import { Button } from 'antd'; import _ from 'lodash'; import { useState } from 'react'; import { ScrollerContext } from '../_components/infinite-scroller/use-scroller-context'; @@ -209,11 +208,9 @@ const BackendList = () => { })} title={intl.formatMessage({ id: 'noresult.backend.title' })} subTitle={intl.formatMessage({ id: 'noresult.backend.subTitle' })} - > - - + onClick={handleAddBackend} + buttonText={intl.formatMessage({ id: 'noresult.button.add' })} + > { }); }; - const handleClickDropdown = (item: any) => { + const handleClickDropdown = () => { navigate(`/cluster-management/clusters/create?action=${PageAction.CREATE}`); }; @@ -331,11 +331,9 @@ const Clusters: React.FC = () => { subTitle={intl.formatMessage({ id: 'noresult.cluster.subTitle' })} - > - - + onClick={handleClickDropdown} + buttonText={intl.formatMessage({ id: 'noresult.button.add' })} + > } pagination={{ showSizeChanger: true, diff --git a/src/pages/cluster-management/credentials.tsx b/src/pages/cluster-management/credentials.tsx index cbc3f5d9..d174f31b 100644 --- a/src/pages/cluster-management/credentials.tsx +++ b/src/pages/cluster-management/credentials.tsx @@ -7,7 +7,7 @@ import type { PageActionType } from '@/config/types'; import useTableFetch from '@/hooks/use-table-fetch'; import { useIntl, useNavigate } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; -import { Button, ConfigProvider, Table, message } from 'antd'; +import { ConfigProvider, Table, message } from 'antd'; import { useAtom } from 'jotai'; import { useState } from 'react'; import NoResult from '../_components/no-result'; @@ -164,14 +164,9 @@ const Credentials: React.FC = () => { subTitle={intl.formatMessage({ id: 'noresult.credentials.subTitle' })} - > - - + onClick={() => handleAddCredential(addActions[0])} + buttonText={intl.formatMessage({ id: 'noresult.button.add' })} + > ); }; diff --git a/src/pages/llmodels/components/table-list.tsx b/src/pages/llmodels/components/table-list.tsx index 38db9af2..982881ff 100644 --- a/src/pages/llmodels/components/table-list.tsx +++ b/src/pages/llmodels/components/table-list.tsx @@ -717,15 +717,11 @@ const Models: React.FC = ({ subTitle={intl.formatMessage({ id: 'noresult.deployments.subTitle' })} - > - - + onClick={() => handleClickDropdown({ key: 'catalog' })} + buttonText={intl?.formatMessage?.({ + id: 'models.table.button.deploy' + })} + > } pagination={{ showSizeChanger: true, diff --git a/src/pages/llmodels/hooks/use-no-resource-result.tsx b/src/pages/llmodels/hooks/use-no-resource-result.tsx index 840b78c5..94164c83 100644 --- a/src/pages/llmodels/hooks/use-no-resource-result.tsx +++ b/src/pages/llmodels/hooks/use-no-resource-result.tsx @@ -4,7 +4,6 @@ import { PageAction } from '@/config'; import NoResult from '@/pages/_components/no-result'; import { useIntl, useNavigate } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; -import { Button } from 'antd'; import { useAtom } from 'jotai'; import React, { useMemo } from 'react'; @@ -99,11 +98,9 @@ const useNoResourceResult = (props: { noFoundText={statusContent.noFoundText} title={title} subTitle={statusContent.subTitle} - > - - + onClick={statusContent.onClick} + buttonText={statusContent.buttonText} + > ); return { noResourceResult diff --git a/src/pages/users/index.tsx b/src/pages/users/index.tsx index 937dd71e..4716c6b9 100644 --- a/src/pages/users/index.tsx +++ b/src/pages/users/index.tsx @@ -6,7 +6,7 @@ import type { PageActionType } from '@/config/types'; import useTableFetch from '@/hooks/use-table-fetch'; import { useIntl, useModel } from '@umijs/max'; import { useMemoizedFn } from 'ahooks'; -import { Button, ConfigProvider, message, Table } from 'antd'; +import { ConfigProvider, message, Table } from 'antd'; import { useMemo, useState } from 'react'; import NoResult from '../_components/no-result'; import PageBox from '../_components/page-box'; @@ -150,11 +150,9 @@ const Users: React.FC = () => { })} title={intl.formatMessage({ id: 'noresult.users.title' })} subTitle={intl.formatMessage({ id: 'noresult.users.subTitle' })} - > - - + onClick={handleAddUser} + buttonText={intl.formatMessage({ id: 'noresult.button.add' })} + > ); };