feat(default): redesign dashboard overview

Refresh the overview page with an actionable Get Started guide, live API request details, real usage sparklines, and OpenAI-inspired dashboard panels. Add collapsible setup state, role-aware quick actions, and localized copy so returning users can focus on platform health.
This commit is contained in:
t0ng7u
2026-05-07 03:20:35 +08:00
parent e8cfb546fa
commit a7d019e3a9
30 changed files with 1389 additions and 195 deletions
@@ -1,11 +1,11 @@
import { parseCurrencyDisplayType } from '@/lib/currency'
import type { BillingSettings } from '../types'
import { createSectionRegistry } from '../utils/section-registry'
import { CheckinSettingsSection } from '../general/checkin-settings-section'
import { PricingSection } from '../general/pricing-section'
import { QuotaSettingsSection } from '../general/quota-settings-section'
import { PaymentSettingsSection } from '../integrations/payment-settings-section'
import { RatioSettingsCard } from '../models/ratio-settings-card'
import type { BillingSettings } from '../types'
import { createSectionRegistry } from '../utils/section-registry'
const getModelDefaults = (settings: BillingSettings) => ({
ModelPrice: settings.ModelPrice,
@@ -161,8 +161,7 @@ const BILLING_SECTIONS = [
WaffoPancakePrivateKey: settings.WaffoPancakePrivateKey ?? '',
WaffoPancakeWebhookPublicKey:
settings.WaffoPancakeWebhookPublicKey ?? '',
WaffoPancakeWebhookTestKey:
settings.WaffoPancakeWebhookTestKey ?? '',
WaffoPancakeWebhookTestKey: settings.WaffoPancakeWebhookTestKey ?? '',
WaffoPancakeStoreID: settings.WaffoPancakeStoreID ?? '',
WaffoPancakeProductID: settings.WaffoPancakeProductID ?? '',
WaffoPancakeReturnURL: settings.WaffoPancakeReturnURL ?? '',
@@ -191,14 +190,15 @@ const BILLING_SECTIONS = [
export type BillingSectionId = (typeof BILLING_SECTIONS)[number]['id']
const billingRegistry = createSectionRegistry<BillingSectionId, BillingSettings>(
{
sections: BILLING_SECTIONS,
defaultSection: 'quota',
basePath: '/system-settings/billing',
urlStyle: 'path',
}
)
const billingRegistry = createSectionRegistry<
BillingSectionId,
BillingSettings
>({
sections: BILLING_SECTIONS,
defaultSection: 'quota',
basePath: '/system-settings/billing',
urlStyle: 'path',
})
export const BILLING_SECTION_IDS = billingRegistry.sectionIds
export const BILLING_DEFAULT_SECTION = billingRegistry.defaultSection
@@ -1,5 +1,5 @@
import * as z from 'zod'
import type { ChangeEvent } from 'react'
import * as z from 'zod'
import type { Resolver } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { useTranslation } from 'react-i18next'
@@ -2,13 +2,13 @@ import { memo, useCallback, useState } from 'react'
import { type UseFormReturn } from 'react-hook-form'
import { Code2, Eye, HelpCircle } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { Button } from '@/components/ui/button'
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from '@/components/ui/accordion'
import { Button } from '@/components/ui/button'
import {
Form,
FormControl,
@@ -18,8 +18,6 @@ import {
FormLabel,
FormMessage,
} from '@/components/ui/form'
import { Switch } from '@/components/ui/switch'
import { Textarea } from '@/components/ui/textarea'
import {
Sheet,
SheetContent,
@@ -27,6 +25,8 @@ import {
SheetHeader,
SheetTitle,
} from '@/components/ui/sheet'
import { Switch } from '@/components/ui/switch'
import { Textarea } from '@/components/ui/textarea'
import { GroupRatioVisualEditor } from './group-ratio-visual-editor'
import { GroupSpecialUsableRulesEditor } from './group-special-usable-editor'
@@ -72,11 +72,7 @@ export const GroupRatioForm = memo(function GroupRatioForm({
return (
<div className='space-y-6'>
<div className='flex flex-wrap justify-end gap-2'>
<Button
variant='outline'
size='sm'
onClick={() => setGuideOpen(true)}
>
<Button variant='outline' size='sm' onClick={() => setGuideOpen(true)}>
<HelpCircle className='mr-2 h-4 w-4' />
{t('Usage guide')}
</Button>
@@ -435,7 +431,9 @@ vip 0.5 ${t('No')} ${t('Assigned by administrator on
</AccordionItem>
<AccordionItem value='usable'>
<AccordionTrigger>{t('Special usable group rules')}</AccordionTrigger>
<AccordionTrigger>
{t('Special usable group rules')}
</AccordionTrigger>
<AccordionContent className='space-y-3'>
<p className='text-muted-foreground text-sm leading-6'>
{t(
@@ -9,12 +9,12 @@ import {
CardHeader,
CardTitle,
} from '@/components/ui/card'
import { Checkbox } from '@/components/ui/checkbox'
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from '@/components/ui/collapsible'
import { Checkbox } from '@/components/ui/checkbox'
import {
Dialog,
DialogContent,
@@ -830,7 +830,9 @@ function GroupPricingTable({
<div>
<CardTitle>{t('Pricing groups')}</CardTitle>
<CardDescription>
{t('Edit billing ratios and user-selectable groups in one table.')}
{t(
'Edit billing ratios and user-selectable groups in one table.'
)}
</CardDescription>
</div>
<Button onClick={addRow} size='sm' className='sm:self-start'>
@@ -900,11 +902,7 @@ function GroupPricingTable({
<Checkbox
checked={row.selectable}
onCheckedChange={(checked) =>
updateRow(
row._id,
'selectable',
checked === true
)
updateRow(row._id, 'selectable', checked === true)
}
aria-label={t('User selectable')}
/>
@@ -1,11 +1,11 @@
import { ChannelAffinitySection } from '../general/channel-affinity'
import { IoNetDeploymentSettingsSection } from '../integrations/ionet-deployment-settings-section'
import type { ModelSettings } from '../types'
import { createSectionRegistry } from '../utils/section-registry'
import { ClaudeSettingsCard } from './claude-settings-card'
import { GeminiSettingsCard } from './gemini-settings-card'
import { GlobalSettingsCard } from './global-settings-card'
import { GrokSettingsCard } from './grok-settings-card'
import { ChannelAffinitySection } from '../general/channel-affinity'
import { IoNetDeploymentSettingsSection } from '../integrations/ionet-deployment-settings-section'
function formatJsonForEditor(value: string, fallback: string) {
const raw = (value ?? '').toString().trim()
@@ -1,5 +1,3 @@
import type { OperationsSettings } from '../types'
import { createSectionRegistry } from '../utils/section-registry'
import { SystemBehaviorSection } from '../general/system-behavior-section'
import { EmailSettingsSection } from '../integrations/email-settings-section'
import { MonitoringSettingsSection } from '../integrations/monitoring-settings-section'
@@ -7,6 +5,8 @@ import { WorkerSettingsSection } from '../integrations/worker-settings-section'
import { LogSettingsSection } from '../maintenance/log-settings-section'
import { PerformanceSection } from '../maintenance/performance-section'
import { UpdateCheckerSection } from '../maintenance/update-checker-section'
import type { OperationsSettings } from '../types'
import { createSectionRegistry } from '../utils/section-registry'
const OPERATIONS_SECTIONS = [
{
@@ -159,5 +159,4 @@ export const OPERATIONS_SECTION_IDS = operationsRegistry.sectionIds
export const OPERATIONS_DEFAULT_SECTION = operationsRegistry.defaultSection
export const getOperationsSectionNavItems =
operationsRegistry.getSectionNavItems
export const getOperationsSectionContent =
operationsRegistry.getSectionContent
export const getOperationsSectionContent = operationsRegistry.getSectionContent
@@ -1,8 +1,8 @@
import type { SecuritySettings } from '../types'
import { createSectionRegistry } from '../utils/section-registry'
import { RateLimitSection } from '../request-limits/rate-limit-section'
import { SensitiveWordsSection } from '../request-limits/sensitive-words-section'
import { SSRFSection } from '../request-limits/ssrf-section'
import type { SecuritySettings } from '../types'
import { createSectionRegistry } from '../utils/section-registry'
const SECURITY_SECTIONS = [
{
@@ -1,5 +1,4 @@
import type { SiteSettings } from '../types'
import { createSectionRegistry } from '../utils/section-registry'
import { SystemInfoSection } from '../general/system-info-section'
import {
parseHeaderNavModules,
parseSidebarModulesAdmin,
@@ -9,7 +8,8 @@ import {
import { HeaderNavigationSection } from '../maintenance/header-navigation-section'
import { NoticeSection } from '../maintenance/notice-section'
import { SidebarModulesSection } from '../maintenance/sidebar-modules-section'
import { SystemInfoSection } from '../general/system-info-section'
import type { SiteSettings } from '../types'
import { createSectionRegistry } from '../utils/section-registry'
const SITE_SECTIONS = [
{
@@ -44,12 +44,12 @@ export type SettingsRouteConfigOptions<
*
* @example
* ```tsx
* export const Route = createFileRoute('/_authenticated/system-settings/site')(
* export const Route = createFileRoute('/_authenticated/system-settings/site')(
* createSettingsRouteConfig({
* sectionIds: SITE_SECTION_IDS,
* defaultSection: SITE_DEFAULT_SECTION,
* component: SiteSettings,
* routePath: '/system-settings/site',
* sectionIds: SITE_SECTION_IDS,
* defaultSection: SITE_DEFAULT_SECTION,
* component: SiteSettings,
* routePath: '/system-settings/site',
* redirectToDefault: true,
* })
* )