feat(user-models): clickable model card opens API access info
This commit is contained in:
@@ -44,7 +44,7 @@ const ModelItemContent = styled.div`
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
cursor: default;
|
||||
cursor: pointer;
|
||||
.content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -127,15 +127,23 @@ const renderTag = (item: any, index = 0) => {
|
||||
|
||||
const ModelItem: React.FC<{
|
||||
model: Record<string, any>;
|
||||
onClick?: (model: Record<string, any>) => void;
|
||||
}> = (props) => {
|
||||
const { model } = props;
|
||||
const { model, onClick } = props;
|
||||
const intl = useIntl();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleCardClick = () => {
|
||||
onClick?.(model);
|
||||
};
|
||||
|
||||
// ``model.name`` from ``/v2/my-models`` is the OpenAI-style id
|
||||
// (org-prefixed for non-platform routes, bare for platform). Use it
|
||||
// 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);
|
||||
for (const [category, path] of Object.entries(categoryToPathMap)) {
|
||||
if (
|
||||
@@ -178,9 +186,10 @@ const ModelItem: React.FC<{
|
||||
<CardWrapper>
|
||||
<TemplateCard
|
||||
height={140}
|
||||
clickable={false}
|
||||
clickable={true}
|
||||
hoverable={true}
|
||||
ghost
|
||||
onClick={handleCardClick}
|
||||
header={
|
||||
<Header>
|
||||
<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,8 +14,10 @@ import { Button, Input, Space } from 'antd';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import PageBox from '../_components/page-box';
|
||||
import { MY_MODELS_API, queryMyModels } from './apis';
|
||||
import APIAccessInfoModal from './components/api-access-info';
|
||||
import ModelItem from './components/model-item';
|
||||
import { categoryOptions, MyModelsStatusValueMap } from './config';
|
||||
import useViewApIInfo from './hooks/use-view-api-info';
|
||||
const Dot = ({ color }: { color: string }) => {
|
||||
return (
|
||||
<span
|
||||
@@ -57,6 +59,7 @@ const UserModels: React.FC = () => {
|
||||
}
|
||||
});
|
||||
const intl = useIntl();
|
||||
const { apiAccessInfo, openViewAPIInfo, closeViewAPIInfo } = useViewApIInfo();
|
||||
|
||||
const statusOptions = useMemo(() => {
|
||||
return [
|
||||
@@ -91,7 +94,7 @@ const UserModels: React.FC = () => {
|
||||
};
|
||||
|
||||
const renderCard = (data: any) => {
|
||||
return <ModelItem model={data} />;
|
||||
return <ModelItem model={data} onClick={openViewAPIInfo} />;
|
||||
};
|
||||
|
||||
const loadMore = useMemoizedFn((nextPage: number) => {
|
||||
@@ -152,86 +155,95 @@ const UserModels: React.FC = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<PageBox>
|
||||
<PageTools
|
||||
marginBottom={22}
|
||||
marginTop={0}
|
||||
left={
|
||||
<Space>
|
||||
<Input
|
||||
placeholder={intl.formatMessage({ id: 'common.filter.name' })}
|
||||
style={{ width: 230 }}
|
||||
size="large"
|
||||
allowClear
|
||||
onClear={() =>
|
||||
handleNameChange({
|
||||
target: {
|
||||
value: ''
|
||||
}
|
||||
})
|
||||
}
|
||||
onChange={handleNameChange}
|
||||
></Input>
|
||||
<BaseSelect
|
||||
allowClear
|
||||
showSearch={false}
|
||||
placeholder={intl.formatMessage({ id: 'models.filter.category' })}
|
||||
style={{ width: 180 }}
|
||||
size="large"
|
||||
maxTagCount={1}
|
||||
options={categoryOptions}
|
||||
onChange={handleCategoryChange}
|
||||
></BaseSelect>
|
||||
<BaseSelect
|
||||
allowClear
|
||||
showSearch={false}
|
||||
placeholder={intl.formatMessage({ id: 'common.filter.status' })}
|
||||
style={{ width: 180 }}
|
||||
size="large"
|
||||
maxTagCount={1}
|
||||
optionRender={optionRender}
|
||||
labelRender={labelRender}
|
||||
options={statusOptions}
|
||||
onChange={handleStatusChange}
|
||||
></BaseSelect>
|
||||
<Button
|
||||
type="text"
|
||||
style={{ color: 'var(--ant-color-text-tertiary)' }}
|
||||
icon={<SyncOutlined></SyncOutlined>}
|
||||
onClick={handleRefresh}
|
||||
></Button>
|
||||
</Space>
|
||||
}
|
||||
></PageTools>
|
||||
<InfiniteScrollerProvider
|
||||
value={{
|
||||
total: dataSource.totalPage,
|
||||
current: queryParams.page,
|
||||
loading: dataSource.loading,
|
||||
refresh: loadMore
|
||||
}}
|
||||
>
|
||||
<TemplateCardList
|
||||
dataList={dataList}
|
||||
loading={dataSource.loading}
|
||||
activeId={false}
|
||||
isFirst={!dataSource.loadend}
|
||||
renderItem={renderCard}
|
||||
></TemplateCardList>
|
||||
<NoResult
|
||||
loading={dataSource.loading}
|
||||
loadend={dataSource.loadend}
|
||||
dataSource={dataList}
|
||||
image={<IconFont type="icon-models" />}
|
||||
filters={{ ...queryParams }}
|
||||
noFoundText={intl.formatMessage({
|
||||
id: 'noresult.mymodels.nofound'
|
||||
})}
|
||||
title={intl.formatMessage({ id: 'noresult.mymodels.title' })}
|
||||
subTitle={intl.formatMessage({ id: 'noresult.mymodels.subTitle' })}
|
||||
></NoResult>
|
||||
</InfiniteScrollerProvider>
|
||||
</PageBox>
|
||||
<>
|
||||
<PageBox>
|
||||
<PageTools
|
||||
marginBottom={22}
|
||||
marginTop={0}
|
||||
left={
|
||||
<Space>
|
||||
<Input
|
||||
placeholder={intl.formatMessage({ id: 'common.filter.name' })}
|
||||
style={{ width: 230 }}
|
||||
size="large"
|
||||
allowClear
|
||||
onClear={() =>
|
||||
handleNameChange({
|
||||
target: {
|
||||
value: ''
|
||||
}
|
||||
})
|
||||
}
|
||||
onChange={handleNameChange}
|
||||
></Input>
|
||||
<BaseSelect
|
||||
allowClear
|
||||
showSearch={false}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'models.filter.category'
|
||||
})}
|
||||
style={{ width: 180 }}
|
||||
size="large"
|
||||
maxTagCount={1}
|
||||
options={categoryOptions}
|
||||
onChange={handleCategoryChange}
|
||||
></BaseSelect>
|
||||
<BaseSelect
|
||||
allowClear
|
||||
showSearch={false}
|
||||
placeholder={intl.formatMessage({ id: 'common.filter.status' })}
|
||||
style={{ width: 180 }}
|
||||
size="large"
|
||||
maxTagCount={1}
|
||||
optionRender={optionRender}
|
||||
labelRender={labelRender}
|
||||
options={statusOptions}
|
||||
onChange={handleStatusChange}
|
||||
></BaseSelect>
|
||||
<Button
|
||||
type="text"
|
||||
style={{ color: 'var(--ant-color-text-tertiary)' }}
|
||||
icon={<SyncOutlined></SyncOutlined>}
|
||||
onClick={handleRefresh}
|
||||
></Button>
|
||||
</Space>
|
||||
}
|
||||
></PageTools>
|
||||
<InfiniteScrollerProvider
|
||||
value={{
|
||||
total: dataSource.totalPage,
|
||||
current: queryParams.page,
|
||||
loading: dataSource.loading,
|
||||
refresh: loadMore
|
||||
}}
|
||||
>
|
||||
<TemplateCardList
|
||||
dataList={dataList}
|
||||
loading={dataSource.loading}
|
||||
activeId={false}
|
||||
isFirst={!dataSource.loadend}
|
||||
renderItem={renderCard}
|
||||
></TemplateCardList>
|
||||
<NoResult
|
||||
loading={dataSource.loading}
|
||||
loadend={dataSource.loadend}
|
||||
dataSource={dataList}
|
||||
image={<IconFont type="icon-models" />}
|
||||
filters={{ ...queryParams }}
|
||||
noFoundText={intl.formatMessage({
|
||||
id: 'noresult.mymodels.nofound'
|
||||
})}
|
||||
title={intl.formatMessage({ id: 'noresult.mymodels.title' })}
|
||||
subTitle={intl.formatMessage({ id: 'noresult.mymodels.subTitle' })}
|
||||
></NoResult>
|
||||
</InfiniteScrollerProvider>
|
||||
</PageBox>
|
||||
<APIAccessInfoModal
|
||||
open={apiAccessInfo.show}
|
||||
data={apiAccessInfo.data}
|
||||
onClose={closeViewAPIInfo}
|
||||
></APIAccessInfoModal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user