import { useState } from 'react'; import type { Meta, StoryObj } from '@storybook/react-vite'; import { InputNumber } from 'antd'; import { CloudServerOutlined, DashboardOutlined } from '@ant-design/icons'; import { AllSetting } from '@/models/setting'; import { NotificationGroup } from './NotificationGroup'; import type { NotificationGroupConfig } from './types'; const systemGroup: NotificationGroupConfig = { icon: , title: 'eventGroupSystem', events: [ { key: 'cpu.high', label: 'eventCPUHigh', settingKey: 'tgCpu', extra: ({ value, onChange, ariaLabel }) => ( ), }, { key: 'memory.high', label: 'eventMemoryHigh', settingKey: 'tgMemory', extra: ({ value, onChange, ariaLabel }) => ( ), }, ], }; const outboundGroup: NotificationGroupConfig = { icon: , title: 'eventGroupOutbound', events: [ { key: 'outbound.down', label: 'eventOutboundDown', settingKey: '' }, { key: 'outbound.up', label: 'eventOutboundUp', settingKey: '' }, ], }; const meta = { title: 'UI/Notifications/NotificationGroup', component: NotificationGroup, tags: ['autodocs'], parameters: { layout: 'padded', docs: { description: { component: 'Card for one notification event group (outbound, Xray, node, system, security) with a per-group select-all checkbox, a selected-count tag, and optional per-event threshold inputs. Composed by the Telegram and email notification tabs on the settings page.', }, }, }, argTypes: { config: { description: 'Group definition: icon, `pages.settings` title key, and the event rows to render.' }, selected: { description: 'Enabled event keys; drives each checkbox and the header count.' }, onToggle: { description: 'Called with the event key when a single checkbox is clicked.' }, onToggleAll: { description: 'Called with every event key in the group when the master checkbox is clicked.' }, allSetting: { description: 'Panel settings snapshot; threshold values such as `tgCpu` are read from it.' }, updateSetting: { description: 'Called with a partial settings patch when a threshold input changes.' }, }, } satisfies Meta; export default meta; type Story = StoryObj; function Demo() { const [selected, setSelected] = useState(['cpu.high']); const [settings, setSettings] = useState(new AllSetting({ tgCpu: 85, tgMemory: 90 })); return ( setSelected((prev) => (prev.includes(key) ? prev.filter((k) => k !== key) : [...prev, key])) } onToggleAll={(keys) => setSelected((prev) => (keys.every((k) => prev.includes(k)) ? prev.filter((k) => !keys.includes(k)) : [...new Set([...prev, ...keys])])) } allSetting={settings} updateSetting={(patch) => setSettings((prev) => new AllSetting({ ...prev, ...patch }))} /> ); } export const AllSelected: Story = { args: { config: systemGroup, selected: ['cpu.high', 'memory.high'], onToggle: () => undefined, onToggleAll: () => undefined, allSetting: new AllSetting({ tgCpu: 85, tgMemory: 90 }), updateSetting: () => undefined, }, }; export const PartiallySelected: Story = { args: { config: systemGroup, selected: ['cpu.high'], onToggle: () => undefined, onToggleAll: () => undefined, allSetting: new AllSetting(), updateSetting: () => undefined, }, }; export const NoneSelected: Story = { args: { config: outboundGroup, selected: [], onToggle: () => undefined, onToggleAll: () => undefined, allSetting: new AllSetting(), updateSetting: () => undefined, }, }; export const Interactive: Story = { args: { config: systemGroup, selected: [], onToggle: () => undefined, onToggleAll: () => undefined, allSetting: new AllSetting(), updateSetting: () => undefined, }, render: () => , };