feat(user-models): clickable model card opens API access info

This commit is contained in:
jialin
2026-07-09 20:36:52 +08:00
committed by jialin
parent 794ac724ca
commit dc54c21d70
3 changed files with 136 additions and 85 deletions
+13 -4
View File
@@ -44,7 +44,7 @@ const ModelItemContent = styled.div`
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
width: 100%; width: 100%;
cursor: default; cursor: pointer;
.content { .content {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@@ -127,15 +127,23 @@ const renderTag = (item: any, index = 0) => {
const ModelItem: React.FC<{ const ModelItem: React.FC<{
model: Record<string, any>; model: Record<string, any>;
onClick?: (model: Record<string, any>) => void;
}> = (props) => { }> = (props) => {
const { model } = props; const { model, onClick } = props;
const intl = useIntl(); const intl = useIntl();
const navigate = useNavigate(); const navigate = useNavigate();
const handleCardClick = () => {
onClick?.(model);
};
// ``model.name`` from ``/v2/my-models`` is the OpenAI-style id // ``model.name`` from ``/v2/my-models`` is the OpenAI-style id
// (org-prefixed for non-platform routes, bare for platform). Use it // (org-prefixed for non-platform routes, bare for platform). Use it
// verbatim — the playground / dispatcher both key off that exact id. // verbatim — the playground / dispatcher both key off that exact id.
const handleOpenPlayGroundClick = () => { const handleOpenPlayGroundClick = (e: React.MouseEvent) => {
// Card is clickable (opens API access info); keep the playground
// action isolated so it doesn't also trigger the card click.
e.stopPropagation();
const modelName = encodeURIComponent(model.name); const modelName = encodeURIComponent(model.name);
for (const [category, path] of Object.entries(categoryToPathMap)) { for (const [category, path] of Object.entries(categoryToPathMap)) {
if ( if (
@@ -178,9 +186,10 @@ const ModelItem: React.FC<{
<CardWrapper> <CardWrapper>
<TemplateCard <TemplateCard
height={140} height={140}
clickable={false} clickable={true}
hoverable={true} hoverable={true}
ghost ghost
onClick={handleCardClick}
header={ header={
<Header> <Header>
<span className="text gap-8"> <span className="text gap-8">
@@ -0,0 +1,30 @@
import { useState } from 'react';
const useViewApIInfo = () => {
const [apiAccessInfo, setAPIAccessInfo] = useState<any>({
show: false,
data: {}
});
const openViewAPIInfo = (row: any) => {
setAPIAccessInfo({
show: true,
data: row
});
};
const closeViewAPIInfo = () => {
setAPIAccessInfo({
show: false,
data: {}
});
};
return {
apiAccessInfo,
openViewAPIInfo,
closeViewAPIInfo
};
};
export default useViewApIInfo;
+14 -2
View File
@@ -14,8 +14,10 @@ import { Button, Input, Space } from 'antd';
import React, { useCallback, useMemo } from 'react'; import React, { useCallback, useMemo } from 'react';
import PageBox from '../_components/page-box'; import PageBox from '../_components/page-box';
import { MY_MODELS_API, queryMyModels } from './apis'; import { MY_MODELS_API, queryMyModels } from './apis';
import APIAccessInfoModal from './components/api-access-info';
import ModelItem from './components/model-item'; import ModelItem from './components/model-item';
import { categoryOptions, MyModelsStatusValueMap } from './config'; import { categoryOptions, MyModelsStatusValueMap } from './config';
import useViewApIInfo from './hooks/use-view-api-info';
const Dot = ({ color }: { color: string }) => { const Dot = ({ color }: { color: string }) => {
return ( return (
<span <span
@@ -57,6 +59,7 @@ const UserModels: React.FC = () => {
} }
}); });
const intl = useIntl(); const intl = useIntl();
const { apiAccessInfo, openViewAPIInfo, closeViewAPIInfo } = useViewApIInfo();
const statusOptions = useMemo(() => { const statusOptions = useMemo(() => {
return [ return [
@@ -91,7 +94,7 @@ const UserModels: React.FC = () => {
}; };
const renderCard = (data: any) => { const renderCard = (data: any) => {
return <ModelItem model={data} />; return <ModelItem model={data} onClick={openViewAPIInfo} />;
}; };
const loadMore = useMemoizedFn((nextPage: number) => { const loadMore = useMemoizedFn((nextPage: number) => {
@@ -152,6 +155,7 @@ const UserModels: React.FC = () => {
}; };
return ( return (
<>
<PageBox> <PageBox>
<PageTools <PageTools
marginBottom={22} marginBottom={22}
@@ -175,7 +179,9 @@ const UserModels: React.FC = () => {
<BaseSelect <BaseSelect
allowClear allowClear
showSearch={false} showSearch={false}
placeholder={intl.formatMessage({ id: 'models.filter.category' })} placeholder={intl.formatMessage({
id: 'models.filter.category'
})}
style={{ width: 180 }} style={{ width: 180 }}
size="large" size="large"
maxTagCount={1} maxTagCount={1}
@@ -232,6 +238,12 @@ const UserModels: React.FC = () => {
></NoResult> ></NoResult>
</InfiniteScrollerProvider> </InfiniteScrollerProvider>
</PageBox> </PageBox>
<APIAccessInfoModal
open={apiAccessInfo.show}
data={apiAccessInfo.data}
onClose={closeViewAPIInfo}
></APIAccessInfoModal>
</>
); );
}; };