feat(billing): on-card charge/pay badge slots for models & instance types
Add the plugin-fed billing price-badge slots to the model cards and the gpu-instance-type / storage cards so the enterprise plugin can surface charge / pay indicators inline.
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import PluginExtraFields from '@/components/plugin-extra-fields';
|
||||||
import { AutoTooltip, IconFont, ThemeTag } from '@gpustack/core-ui';
|
import { AutoTooltip, IconFont, ThemeTag } from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Flex, Tag } from 'antd';
|
import { Flex, Tag } from 'antd';
|
||||||
@@ -271,6 +272,10 @@ const InstanceTypeItem: React.FC<InstanceTypeItemProps> = ({ item }) => {
|
|||||||
{cpuManufacturer}
|
{cpuManufacturer}
|
||||||
</ThemeTag>
|
</ThemeTag>
|
||||||
)}
|
)}
|
||||||
|
<PluginExtraFields
|
||||||
|
name="InstanceTypeBillingBadge"
|
||||||
|
context={{ instanceType: item }}
|
||||||
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Title>
|
</Title>
|
||||||
<InstanceMetadataSection spec={specData}></InstanceMetadataSection>
|
<InstanceMetadataSection spec={specData}></InstanceMetadataSection>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import PluginExtraFields from '@/components/plugin-extra-fields';
|
||||||
import { FileSkeletonRows } from '@/pages/llmodels/components/model-source/file-skeleton';
|
import { FileSkeletonRows } from '@/pages/llmodels/components/model-source/file-skeleton';
|
||||||
import { TemplateCard } from '@gpustack/core-ui';
|
import { TemplateCard } from '@gpustack/core-ui';
|
||||||
import { Empty, Flex, Spin } from 'antd';
|
import { Empty, Flex, Spin } from 'antd';
|
||||||
@@ -40,6 +41,10 @@ const InstanceTypeList: React.FC<InstanceTypeListProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex orientation="vertical" gap={16}>
|
<Flex orientation="vertical" gap={16}>
|
||||||
|
<PluginExtraFields
|
||||||
|
name="InstanceTypeBillingProvider"
|
||||||
|
context={{ instanceTypes: dataList }}
|
||||||
|
/>
|
||||||
{dataList.map((item) => {
|
{dataList.map((item) => {
|
||||||
const name = item.name;
|
const name = item.name;
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
|
import PluginExtraFields from '@/components/plugin-extra-fields';
|
||||||
import {
|
import {
|
||||||
IconFont,
|
IconFont,
|
||||||
StatusTag,
|
StatusDot,
|
||||||
TagsWrapper,
|
TagsWrapper,
|
||||||
TemplateCard,
|
TemplateCard,
|
||||||
ThemeTag
|
ThemeTag
|
||||||
} from '@gpustack/core-ui';
|
} from '@gpustack/core-ui';
|
||||||
import { useIntl, useNavigate } from '@umijs/max';
|
import { useIntl, useNavigate } from '@umijs/max';
|
||||||
import { Button } from 'antd';
|
import { Button, Tooltip } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
@@ -192,6 +193,23 @@ const ModelItem: React.FC<{
|
|||||||
return _.round(max_tokens / 1024);
|
return _.round(max_tokens / 1024);
|
||||||
}, [model]);
|
}, [model]);
|
||||||
|
|
||||||
|
// Ready is the normal state — show just the dot (no label); other states
|
||||||
|
// (Not Ready / Stopped) keep their label so the problem is legible.
|
||||||
|
const statusNode = (
|
||||||
|
<StatusDot
|
||||||
|
statusValue={{
|
||||||
|
status: MyModelsStatusMap[model.status],
|
||||||
|
text:
|
||||||
|
model.status === MyModelsStatusValueMap.Ready ||
|
||||||
|
!MyModelsStatusLabelMap[model.status]
|
||||||
|
? ''
|
||||||
|
: intl.formatMessage({
|
||||||
|
id: MyModelsStatusLabelMap[model.status]
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CardWrapper>
|
<CardWrapper>
|
||||||
<TemplateCard
|
<TemplateCard
|
||||||
@@ -210,18 +228,32 @@ const ModelItem: React.FC<{
|
|||||||
) : (
|
) : (
|
||||||
<ModelLogo src={defaultModelLogo} alt="" />
|
<ModelLogo src={defaultModelLogo} alt="" />
|
||||||
)}
|
)}
|
||||||
<span>{model.name}</span>
|
<span className="flex-center" style={{ gap: 8, minWidth: 0 }}>
|
||||||
|
<span>{model.name}</span>
|
||||||
|
{/* Status moved to a compact dot right after the name, freeing
|
||||||
|
the header's right side for the price summary. The dot keeps
|
||||||
|
the state message on hover (StatusDot has no built-in one). */}
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontWeight: 400,
|
||||||
|
fontSize: 'var(--font-size-small)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{model.state_message ? (
|
||||||
|
<Tooltip title={model.state_message}>
|
||||||
|
<span style={{ display: 'inline-flex' }}>
|
||||||
|
{statusNode}
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
) : (
|
||||||
|
statusNode
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span className="flex-center gap-8">
|
||||||
|
<PluginExtraFields name="ModelPriceSummary" context={{ model }} />
|
||||||
</span>
|
</span>
|
||||||
<StatusTag
|
|
||||||
maxTooltipWidth={400}
|
|
||||||
statusValue={{
|
|
||||||
status: MyModelsStatusMap[model.status],
|
|
||||||
text: intl.formatMessage({
|
|
||||||
id: MyModelsStatusLabelMap[model.status] || ''
|
|
||||||
}),
|
|
||||||
message: model.state_message
|
|
||||||
}}
|
|
||||||
></StatusTag>
|
|
||||||
</Header>
|
</Header>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import PluginExtraFields from '@/components/plugin-extra-fields';
|
||||||
import useTableFetch from '@/hooks/use-table-fetch';
|
import useTableFetch from '@/hooks/use-table-fetch';
|
||||||
import { SyncOutlined } from '@ant-design/icons';
|
import { SyncOutlined } from '@ant-design/icons';
|
||||||
import {
|
import {
|
||||||
@@ -268,6 +269,10 @@ const UserModels: React.FC = () => {
|
|||||||
</Space>
|
</Space>
|
||||||
}
|
}
|
||||||
></PageTools>
|
></PageTools>
|
||||||
|
<PluginExtraFields
|
||||||
|
name="ModelBillingProvider"
|
||||||
|
context={{ models: dataList }}
|
||||||
|
/>
|
||||||
<InfiniteScrollerProvider
|
<InfiniteScrollerProvider
|
||||||
value={{
|
value={{
|
||||||
total: dataSource.totalPage,
|
total: dataSource.totalPage,
|
||||||
|
|||||||
Reference in New Issue
Block a user