✨ 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:
@@ -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
-1
@@ -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(
|
||||
|
||||
+5
-7
@@ -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,
|
||||
* })
|
||||
* )
|
||||
|
||||
Reference in New Issue
Block a user