feat: add a billing holder page
This commit is contained in:
@@ -338,6 +338,19 @@ const baseRoutes = [
|
|||||||
selectedIcon: 'icon-usage-filled',
|
selectedIcon: 'icon-usage-filled',
|
||||||
defaultIcon: 'icon-usage-outlined',
|
defaultIcon: 'icon-usage-outlined',
|
||||||
component: './usage/index'
|
component: './usage/index'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'billing',
|
||||||
|
path: '/usage/billing',
|
||||||
|
key: 'billing',
|
||||||
|
icon: 'icon-billing-outlined',
|
||||||
|
selectedIcon: 'icon-billing-filled',
|
||||||
|
defaultIcon: 'icon-billing-outlined',
|
||||||
|
// OSS exposes the menu as a teaser for the enterprise billing
|
||||||
|
// module. The page itself just renders an upsell notice — the real
|
||||||
|
// billing UI lives in the enterprise plugin and shadows this route
|
||||||
|
// via `routes.extensions.ts`.
|
||||||
|
component: './billing'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ export default (props: any) => {
|
|||||||
config={{
|
config={{
|
||||||
apiBaseUrl: GPUSTACK_API_BASE_URL,
|
apiBaseUrl: GPUSTACK_API_BASE_URL,
|
||||||
theme: userSettings.theme,
|
theme: userSettings.theme,
|
||||||
iconUrl: '//at.alicdn.com/t/c/font_4613488_rwchdketjg8.js',
|
iconUrl: '//at.alicdn.com/t/c/font_4613488_or5t9922sfk.js',
|
||||||
isDarkTheme: userSettings.isDarkTheme,
|
isDarkTheme: userSettings.isDarkTheme,
|
||||||
defaultColorPrimary: COLOR_PRIMARY
|
defaultColorPrimary: COLOR_PRIMARY
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
export default {
|
||||||
|
'billing.upsell.title': 'Billing is an Enterprise feature',
|
||||||
|
'billing.upsell.subtitle':
|
||||||
|
'Track spend, generate invoices, and enforce budgets across teams. Upgrade to GPUStack Enterprise to manage billing.',
|
||||||
|
'billing.upsell.featuresTitle': 'What you get in Enterprise',
|
||||||
|
'billing.upsell.feature.usage':
|
||||||
|
'See cost breakdowns by organization, user, and model',
|
||||||
|
'billing.upsell.feature.invoices':
|
||||||
|
'Generate invoices and export billing reports',
|
||||||
|
'billing.upsell.feature.budgets':
|
||||||
|
'Set budgets and spending limits with alerts',
|
||||||
|
'billing.upsell.feature.chargeback':
|
||||||
|
'Attribute and charge back usage to teams and projects',
|
||||||
|
'billing.upsell.cta': 'Learn about Enterprise'
|
||||||
|
};
|
||||||
@@ -38,6 +38,7 @@ export default {
|
|||||||
'menu.usage.usage': 'Usage',
|
'menu.usage.usage': 'Usage',
|
||||||
'menu.billingAndUsage': 'Usage & Billing',
|
'menu.billingAndUsage': 'Usage & Billing',
|
||||||
'menu.billingAndUsage.usage': 'Usage',
|
'menu.billingAndUsage.usage': 'Usage',
|
||||||
|
'menu.billingAndUsage.billing': 'Billing',
|
||||||
'menu.404': '404',
|
'menu.404': '404',
|
||||||
'menu.resources.clusters': 'Clusters',
|
'menu.resources.clusters': 'Clusters',
|
||||||
'menu.resources.credentials': 'Cloud Credentials',
|
'menu.resources.credentials': 'Cloud Credentials',
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
export default {
|
||||||
|
'billing.upsell.title': 'Billing is an Enterprise feature',
|
||||||
|
'billing.upsell.subtitle':
|
||||||
|
'Track spend, generate invoices, and enforce budgets across teams. Upgrade to GPUStack Enterprise to manage billing.',
|
||||||
|
'billing.upsell.featuresTitle': 'What you get in Enterprise',
|
||||||
|
'billing.upsell.feature.usage':
|
||||||
|
'See cost breakdowns by organization, user, and model',
|
||||||
|
'billing.upsell.feature.invoices':
|
||||||
|
'Generate invoices and export billing reports',
|
||||||
|
'billing.upsell.feature.budgets':
|
||||||
|
'Set budgets and spending limits with alerts',
|
||||||
|
'billing.upsell.feature.chargeback':
|
||||||
|
'Attribute and charge back usage to teams and projects',
|
||||||
|
'billing.upsell.cta': 'Learn about Enterprise'
|
||||||
|
};
|
||||||
@@ -29,6 +29,7 @@ export default {
|
|||||||
'menu.usage.usage': '使用状況',
|
'menu.usage.usage': '使用状況',
|
||||||
'menu.billingAndUsage': '使用状況と請求',
|
'menu.billingAndUsage': '使用状況と請求',
|
||||||
'menu.billingAndUsage.usage': '使用状況',
|
'menu.billingAndUsage.usage': '使用状況',
|
||||||
|
'menu.billingAndUsage.billing': '請求',
|
||||||
'menu.404': '404',
|
'menu.404': '404',
|
||||||
'menu.settings': 'Settings',
|
'menu.settings': 'Settings',
|
||||||
'menu.resources.workers': 'Workers',
|
'menu.resources.workers': 'Workers',
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
export default {
|
||||||
|
'billing.upsell.title': 'Billing is an Enterprise feature',
|
||||||
|
'billing.upsell.subtitle':
|
||||||
|
'Track spend, generate invoices, and enforce budgets across teams. Upgrade to GPUStack Enterprise to manage billing.',
|
||||||
|
'billing.upsell.featuresTitle': 'What you get in Enterprise',
|
||||||
|
'billing.upsell.feature.usage':
|
||||||
|
'See cost breakdowns by organization, user, and model',
|
||||||
|
'billing.upsell.feature.invoices':
|
||||||
|
'Generate invoices and export billing reports',
|
||||||
|
'billing.upsell.feature.budgets':
|
||||||
|
'Set budgets and spending limits with alerts',
|
||||||
|
'billing.upsell.feature.chargeback':
|
||||||
|
'Attribute and charge back usage to teams and projects',
|
||||||
|
'billing.upsell.cta': 'Learn about Enterprise'
|
||||||
|
};
|
||||||
@@ -29,6 +29,7 @@ export default {
|
|||||||
'menu.usage.usage': 'Использование',
|
'menu.usage.usage': 'Использование',
|
||||||
'menu.billingAndUsage': 'Использование и биллинг',
|
'menu.billingAndUsage': 'Использование и биллинг',
|
||||||
'menu.billingAndUsage.usage': 'Использование',
|
'menu.billingAndUsage.usage': 'Использование',
|
||||||
|
'menu.billingAndUsage.billing': 'Биллинг',
|
||||||
'menu.404': 'Ошибка 404',
|
'menu.404': 'Ошибка 404',
|
||||||
'menu.resources.workers': 'Воркеры',
|
'menu.resources.workers': 'Воркеры',
|
||||||
'menu.resources.gpus': 'GPUs',
|
'menu.resources.gpus': 'GPUs',
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
export default {
|
||||||
|
'billing.upsell.title': 'Billing is an Enterprise feature',
|
||||||
|
'billing.upsell.subtitle':
|
||||||
|
'Track spend, generate invoices, and enforce budgets across teams. Upgrade to GPUStack Enterprise to manage billing.',
|
||||||
|
'billing.upsell.featuresTitle': 'What you get in Enterprise',
|
||||||
|
'billing.upsell.feature.usage':
|
||||||
|
'See cost breakdowns by organization, user, and model',
|
||||||
|
'billing.upsell.feature.invoices':
|
||||||
|
'Generate invoices and export billing reports',
|
||||||
|
'billing.upsell.feature.budgets':
|
||||||
|
'Set budgets and spending limits with alerts',
|
||||||
|
'billing.upsell.feature.chargeback':
|
||||||
|
'Attribute and charge back usage to teams and projects',
|
||||||
|
'billing.upsell.cta': 'Learn about Enterprise'
|
||||||
|
};
|
||||||
@@ -36,6 +36,7 @@ export default {
|
|||||||
'menu.usage.usage': 'Kullanım',
|
'menu.usage.usage': 'Kullanım',
|
||||||
'menu.billingAndUsage': 'Kullanım ve Faturalandırma',
|
'menu.billingAndUsage': 'Kullanım ve Faturalandırma',
|
||||||
'menu.billingAndUsage.usage': 'Kullanım',
|
'menu.billingAndUsage.usage': 'Kullanım',
|
||||||
|
'menu.billingAndUsage.billing': 'Faturalandırma',
|
||||||
'menu.404': '404',
|
'menu.404': '404',
|
||||||
'menu.resources.clusters': 'Kümeler',
|
'menu.resources.clusters': 'Kümeler',
|
||||||
'menu.resources.credentials': 'Bulut Kimlik Bilgileri',
|
'menu.resources.credentials': 'Bulut Kimlik Bilgileri',
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export default {
|
||||||
|
'billing.upsell.title': '计费是企业版功能',
|
||||||
|
'billing.upsell.subtitle':
|
||||||
|
'在团队间跟踪花费、生成账单并执行预算。升级到 GPUStack 企业版即可管理计费。',
|
||||||
|
'billing.upsell.featuresTitle': '企业版包含的能力',
|
||||||
|
'billing.upsell.feature.usage': '按组织、用户与模型查看成本明细',
|
||||||
|
'billing.upsell.feature.invoices': '生成账单并导出计费报表',
|
||||||
|
'billing.upsell.feature.budgets': '设置预算与花费上限并触发告警',
|
||||||
|
'billing.upsell.feature.chargeback': '将用量归属并分摊到团队与项目',
|
||||||
|
'billing.upsell.cta': '了解企业版'
|
||||||
|
};
|
||||||
@@ -31,6 +31,7 @@ export default {
|
|||||||
'menu.usage.usage': '使用量',
|
'menu.usage.usage': '使用量',
|
||||||
'menu.billingAndUsage': '用量与计费',
|
'menu.billingAndUsage': '用量与计费',
|
||||||
'menu.billingAndUsage.usage': '用量统计',
|
'menu.billingAndUsage.usage': '用量统计',
|
||||||
|
'menu.billingAndUsage.billing': '计费',
|
||||||
'menu.404': '404',
|
'menu.404': '404',
|
||||||
'menu.resources.workers': '节点',
|
'menu.resources.workers': '节点',
|
||||||
'menu.resources.gpus': 'GPU',
|
'menu.resources.gpus': 'GPU',
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import { IconFont } from '@gpustack/core-ui';
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
|
import { Button, Result, Typography } from 'antd';
|
||||||
|
import PageBox from '../_components/page-box';
|
||||||
|
|
||||||
|
// OSS-only upsell page for the billing module. The real Billing UI ships
|
||||||
|
// in the enterprise plugin and shadows this route via
|
||||||
|
// `routes.extensions.ts` — when the enterprise plugin is loaded, the
|
||||||
|
// merger removes this entry by name. So this file is what users see on
|
||||||
|
// the OSS build only.
|
||||||
|
const Billing: React.FC = () => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const features = [
|
||||||
|
'billing.upsell.feature.usage',
|
||||||
|
'billing.upsell.feature.invoices',
|
||||||
|
'billing.upsell.feature.budgets',
|
||||||
|
'billing.upsell.feature.chargeback'
|
||||||
|
];
|
||||||
|
return (
|
||||||
|
<PageBox>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
// Use a viewport-relative min-height so flex centering has
|
||||||
|
// something to work against — percentage heights through
|
||||||
|
// PageBox's wrapper chain don't always resolve. The offset
|
||||||
|
// accounts for the global header + the page title bar.
|
||||||
|
minHeight: 'calc(100vh - 180px)',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Result
|
||||||
|
icon={
|
||||||
|
<IconFont
|
||||||
|
type="icon-billing-outlined"
|
||||||
|
style={{ fontSize: 64, color: 'var(--ant-color-primary)' }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
title={intl.formatMessage({ id: 'billing.upsell.title' })}
|
||||||
|
subTitle={intl.formatMessage({ id: 'billing.upsell.subtitle' })}
|
||||||
|
extra={
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
maxWidth: 520,
|
||||||
|
margin: '0 auto',
|
||||||
|
textAlign: 'left'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography.Title level={5} style={{ marginBottom: 12 }}>
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: 'billing.upsell.featuresTitle'
|
||||||
|
})}
|
||||||
|
</Typography.Title>
|
||||||
|
<ul style={{ paddingLeft: 20, marginBottom: 24 }}>
|
||||||
|
{features.map((id) => (
|
||||||
|
<li key={id} style={{ marginBottom: 6 }}>
|
||||||
|
{intl.formatMessage({ id })}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<div style={{ textAlign: 'center' }}>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
href="https://gpustack.ai/enterprise"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
{intl.formatMessage({ id: 'billing.upsell.cta' })}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</PageBox>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Billing;
|
||||||
Reference in New Issue
Block a user