feat: notification form and modal

and global scrollbar
This commit is contained in:
moonrailgun 2023-09-27 16:57:46 +08:00
parent b6a26d8777
commit 53c0fd563d
4 changed files with 135 additions and 40 deletions

View File

@ -1,19 +1,40 @@
import { Form, Input, Modal, ModalProps, Select } from 'antd';
import {
Button,
Form,
FormProps,
Input,
Modal,
ModalProps,
Select,
} from 'antd';
import React, { useMemo, useState } from 'react';
import { request } from '../../../api/request';
import { useEvent } from '../../../hooks/useEvent';
import { notificationStrategies } from './strategies';
export interface NotificationFormValues {
name: string;
type: string;
payload: Record<string, any>;
}
const defaultValues: Omit<NotificationFormValues, 'payload'> = {
name: 'New Notification',
type: notificationStrategies[0].name,
};
interface NotificationInfoModalProps
extends Pick<ModalProps, 'open' | 'onOk' | 'onCancel'> {}
extends Pick<ModalProps, 'open' | 'onCancel'>,
Pick<FormProps, 'initialValues'> {
onSubmit: (values: NotificationFormValues) => void;
}
export const NotificationInfoModal: React.FC<NotificationInfoModalProps> =
React.memo((props) => {
const [notificationType, setNotificationType] = useState(
notificationStrategies[0].name
);
const [form] = Form.useForm();
const typeValue = Form.useWatch('type', form);
const form = useMemo(() => {
const strategy = notificationStrategies.find(
(s) => s.name === notificationType
);
const formEl = useMemo(() => {
const strategy = notificationStrategies.find((s) => s.name === typeValue);
if (!strategy) {
return null;
@ -22,23 +43,57 @@ export const NotificationInfoModal: React.FC<NotificationInfoModalProps> =
const Component = strategy.form;
return <Component />;
}, [notificationType]);
}, [typeValue]);
const handleSave = useEvent(async () => {
await form.validateFields();
const values = form.getFieldsValue();
const { name, type, ...payload } = values;
props.onSubmit({
name,
type,
payload,
});
});
const handleTest = useEvent(async () => {
await form.validateFields();
const values = form.getFieldsValue();
const { name, type, ...payload } = values;
console.log('TODO', { name, type, payload });
});
return (
<Modal
title="Notification"
destroyOnClose={true}
maskClosable={false}
centered={true}
open={props.open}
onOk={props.onOk}
onCancel={props.onCancel}
footer={
<div>
<Button onClick={handleTest}>Test</Button>
<Button type="primary" onClick={handleSave}>
Save
</Button>
</div>
}
>
<Form layout="vertical">
<Form.Item label="Notification Type">
<Select
value={notificationType}
onChange={(val) => setNotificationType(val)}
<div className="overflow-y-auto max-h-[80vh]">
<Form
form={form}
layout="vertical"
initialValues={props.initialValues ?? defaultValues}
>
<Form.Item label="Notification Type" name="type">
<Select>
{notificationStrategies.map((s) => (
<Select.Option value={s.name}>{s.label}</Select.Option>
<Select.Option key={s.name} value={s.name}>
{s.label}
</Select.Option>
))}
</Select>
</Form.Item>
@ -47,8 +102,9 @@ export const NotificationInfoModal: React.FC<NotificationInfoModalProps> =
<Input />
</Form.Item>
{form}
<Form.Item name="payload">{formEl}</Form.Item>
</Form>
</div>
</Modal>
);
});

View File

@ -4,31 +4,35 @@ import React from 'react';
export const NotificationSMTP: React.FC = React.memo(() => {
return (
<>
<Form.Item label="Host" name="hostname">
<Form.Item label="Host" name="hostname" rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item label="Port" name="port">
<Form.Item
label="Port"
name="port"
rules={[{ required: true }, { type: 'number', min: 0, max: 65535 }]}
>
<InputNumber max={65535} min={1} />
</Form.Item>
<Form.Item label="Security" name="security">
<Form.Item label="Security" name="security" initialValue={false}>
<Select>
<Select.Option value={false}>None / STARTTLS (25, 587)</Select.Option>
<Select.Option value={true}>TLS (465)</Select.Option>
</Select>
</Form.Item>
<Form name="ignoreTLS">
<Form.Item name="ignoreTLS">
<Checkbox>Ignore TLS Error</Checkbox>
</Form>
<Form.Item label="Username" name="username">
</Form.Item>
<Form.Item label="Username" name="username" rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item label="Password" name="password">
<Form.Item label="Password" name="password" rules={[{ required: true }]}>
<Input.Password />
</Form.Item>
<Form.Item label="From Email" name="from">
<Form.Item label="From Email" name="from" rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item label="To Email" name="to">
<Form.Item label="To Email" name="to" rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item label="CC" name="cc">

View File

@ -23,6 +23,38 @@ a {
height: 100%;
}
/* 滚动条 */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-corner {
background-color: transparent;
}
::-webkit-scrollbar-thumb {
@apply bg-black bg-opacity-10;
border-color: transparent;
background-clip: padding-box;
border-width: 2px;
border-style: solid;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
@apply bg-black bg-opacity-20;
}
::-webkit-scrollbar-track {
@apply bg-black bg-opacity-5;
border-color: transparent;
background-clip: padding-box;
border-width: 2px;
border-style: solid;
border-radius: 4px;
}
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@ -1,15 +1,18 @@
import { PlusOutlined } from '@ant-design/icons';
import { Button, List } from 'antd';
import React, { useState } from 'react';
import { NotificationInfoModal } from '../../components/modals/NotificationInfo';
import {
NotificationFormValues,
NotificationInfoModal,
} from '../../components/modals/NotificationInfo';
import { PageHeader } from '../../components/PageHeader';
import { useEvent } from '../../hooks/useEvent';
export const NotificationList: React.FC = React.memo(() => {
const [open, setOpen] = useState(false);
const handleOk = useEvent(() => {
console.log('ok');
const handleSubmit = useEvent((values: NotificationFormValues) => {
console.log('ok', values);
setOpen(false);
});
@ -47,7 +50,7 @@ export const NotificationList: React.FC = React.memo(() => {
<NotificationInfoModal
open={open}
onOk={handleOk}
onSubmit={handleSubmit}
onCancel={() => setOpen(false)}
/>
</div>