NotificationGroup.stories.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import { useState } from 'react';
  2. import type { Meta, StoryObj } from '@storybook/react-vite';
  3. import { InputNumber } from 'antd';
  4. import { CloudServerOutlined, DashboardOutlined } from '@ant-design/icons';
  5. import { AllSetting } from '@/models/setting';
  6. import { NotificationGroup } from './NotificationGroup';
  7. import type { NotificationGroupConfig } from './types';
  8. const systemGroup: NotificationGroupConfig = {
  9. icon: <DashboardOutlined />,
  10. title: 'eventGroupSystem',
  11. events: [
  12. {
  13. key: 'cpu.high',
  14. label: 'eventCPUHigh',
  15. settingKey: 'tgCpu',
  16. extra: ({ value, onChange, ariaLabel }) => (
  17. <InputNumber size="small" min={0} max={100} value={value} onChange={onChange} aria-label={ariaLabel} style={{ width: 80 }} />
  18. ),
  19. },
  20. {
  21. key: 'memory.high',
  22. label: 'eventMemoryHigh',
  23. settingKey: 'tgMemory',
  24. extra: ({ value, onChange, ariaLabel }) => (
  25. <InputNumber size="small" min={0} max={100} value={value} onChange={onChange} aria-label={ariaLabel} style={{ width: 80 }} />
  26. ),
  27. },
  28. ],
  29. };
  30. const outboundGroup: NotificationGroupConfig = {
  31. icon: <CloudServerOutlined />,
  32. title: 'eventGroupOutbound',
  33. events: [
  34. { key: 'outbound.down', label: 'eventOutboundDown', settingKey: '' },
  35. { key: 'outbound.up', label: 'eventOutboundUp', settingKey: '' },
  36. ],
  37. };
  38. const meta = {
  39. title: 'UI/Notifications/NotificationGroup',
  40. component: NotificationGroup,
  41. tags: ['autodocs'],
  42. parameters: {
  43. layout: 'padded',
  44. docs: {
  45. description: {
  46. component:
  47. '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.',
  48. },
  49. },
  50. },
  51. argTypes: {
  52. config: { description: 'Group definition: icon, `pages.settings` title key, and the event rows to render.' },
  53. selected: { description: 'Enabled event keys; drives each checkbox and the header count.' },
  54. onToggle: { description: 'Called with the event key when a single checkbox is clicked.' },
  55. onToggleAll: { description: 'Called with every event key in the group when the master checkbox is clicked.' },
  56. allSetting: { description: 'Panel settings snapshot; threshold values such as `tgCpu` are read from it.' },
  57. updateSetting: { description: 'Called with a partial settings patch when a threshold input changes.' },
  58. },
  59. } satisfies Meta<typeof NotificationGroup>;
  60. export default meta;
  61. type Story = StoryObj<typeof meta>;
  62. function Demo() {
  63. const [selected, setSelected] = useState<string[]>(['cpu.high']);
  64. const [settings, setSettings] = useState(new AllSetting({ tgCpu: 85, tgMemory: 90 }));
  65. return (
  66. <NotificationGroup
  67. config={systemGroup}
  68. selected={selected}
  69. onToggle={(key) =>
  70. setSelected((prev) => (prev.includes(key) ? prev.filter((k) => k !== key) : [...prev, key]))
  71. }
  72. onToggleAll={(keys) =>
  73. setSelected((prev) => (keys.every((k) => prev.includes(k)) ? prev.filter((k) => !keys.includes(k)) : [...new Set([...prev, ...keys])]))
  74. }
  75. allSetting={settings}
  76. updateSetting={(patch) => setSettings((prev) => new AllSetting({ ...prev, ...patch }))}
  77. />
  78. );
  79. }
  80. export const AllSelected: Story = {
  81. args: {
  82. config: systemGroup,
  83. selected: ['cpu.high', 'memory.high'],
  84. onToggle: () => undefined,
  85. onToggleAll: () => undefined,
  86. allSetting: new AllSetting({ tgCpu: 85, tgMemory: 90 }),
  87. updateSetting: () => undefined,
  88. },
  89. };
  90. export const PartiallySelected: Story = {
  91. args: {
  92. config: systemGroup,
  93. selected: ['cpu.high'],
  94. onToggle: () => undefined,
  95. onToggleAll: () => undefined,
  96. allSetting: new AllSetting(),
  97. updateSetting: () => undefined,
  98. },
  99. };
  100. export const NoneSelected: Story = {
  101. args: {
  102. config: outboundGroup,
  103. selected: [],
  104. onToggle: () => undefined,
  105. onToggleAll: () => undefined,
  106. allSetting: new AllSetting(),
  107. updateSetting: () => undefined,
  108. },
  109. };
  110. export const Interactive: Story = {
  111. args: {
  112. config: systemGroup,
  113. selected: [],
  114. onToggle: () => undefined,
  115. onToggleAll: () => undefined,
  116. allSetting: new AllSetting(),
  117. updateSetting: () => undefined,
  118. },
  119. render: () => <Demo />,
  120. };