@ant-design/icons#QuestionCircleFilled TypeScript Examples
The following examples show how to use
@ant-design/icons#QuestionCircleFilled.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: FormSubheader.tsx From condo with MIT License | 6 votes |
FormSubheader: React.FC<IFormSubheaderProps> = ({ title, hint }) => {
return (
<Typography.Title level={2} style={{ fontSize: fontSizes.content }}>
{title}
{hint && (
<>
<Tooltip title={hint}>
<QuestionCircleFilled style={{ color: grey[0] }}/>
</Tooltip>
</>
)}
</Typography.Title>
)
}
Example #2
Source File: index.tsx From nanolooker with MIT License | 6 votes |
QuestionCircle = React.forwardRef((props: any, ref) => {
const { theme } = React.useContext(PreferencesContext);
return theme === Theme.DARK ? (
<QuestionCircleFilled
style={{ color: Colors.PENDING }}
ref={ref}
{...props}
/>
) : (
<QuestionCircleTwoTone ref={ref} {...props} />
);
})
Example #3
Source File: operateForm.tsx From fe-v5 with Apache License 2.0 | 4 votes |
OperateForm: React.FC<Props> = ({ detail = {}, type, tagsObj = {} }) => {
const btimeDefault = new Date().getTime();
const etimeDefault = new Date().getTime() + 1 * 60 * 60 * 1000; // 默认时长1h
const { t, i18n } = useTranslation();
const { clusters: clusterList } = useSelector<RootState, CommonStoreState>((state) => state.common);
const layout = {
labelCol: {
span: 24,
},
wrapperCol: {
span: 24,
},
};
const tailLayout = {
labelCol: {
span: 0,
},
wrapperCol: {
span: 24,
},
};
const [form] = Form.useForm(null as any);
const history = useHistory();
const [btnLoading, setBtnLoading] = useState<boolean>(false);
const [timeLen, setTimeLen] = useState('1h');
const { curBusiItem, busiGroups } = useSelector<RootState, CommonStoreState>((state) => state.common);
useEffect(() => {
const btime = form.getFieldValue('btime');
const etime = form.getFieldValue('etime');
if (!!etime && !!btime) {
const d = moment.duration(etime - btime).days();
const h = moment.duration(etime - btime).hours();
const m = moment.duration(etime - btime).minutes();
const s = moment.duration(etime - btime).seconds();
}
if (curBusiItem) {
form.setFieldsValue({ busiGroup: curBusiItem.id });
} else if (busiGroups.length > 0) {
form.setFieldsValue({ busiGroup: busiGroups[0].id });
} else {
message.warning('无可用业务组');
history.push('/alert-mutes');
}
return () => {};
}, [form]);
useEffect(() => {
// 只有add 的时候才传入tagsObj
if (tagsObj?.tags && tagsObj?.tags.length > 0) {
const tags = tagsObj?.tags?.map((item) => {
return {
...item,
value: item.func === 'in' ? item.value.split(' ') : item.value,
};
});
form.setFieldsValue({
tags: tags || [{}],
cluster: tagsObj.cluster,
});
}
}, [tagsObj]);
const timeChange = () => {
const btime = form.getFieldValue('btime');
const etime = form.getFieldValue('etime');
if (!!etime && !!btime) {
const d = Math.floor(moment.duration(etime - btime).asDays());
const h = Math.floor(moment.duration(etime - btime).hours());
const m = Math.floor(moment.duration(etime - btime).minutes());
const s = Math.floor(moment.duration(etime - btime).seconds());
const timeLen = `${d ? `${d}d ` : ''}${h ? `${h}h ` : ''}${m ? `${m}m ` : ''}${s ? `${s}s` : ''}`;
setTimeLen(timeLen);
}
};
const onFinish = (values) => {
setBtnLoading(true);
const tags = values?.tags?.map((item) => {
return {
...item,
value: Array.isArray(item.value) ? item.value.join(' ') : item.value,
};
});
const params = {
...values,
btime: moment(values.btime).unix(),
etime: moment(values.etime).unix(),
tags,
};
const curBusiItemId = form.getFieldValue('busiGroup');
addShield(params, curBusiItemId)
.then((_) => {
message.success(t('新建告警屏蔽成功'));
history.push('/alert-mutes');
})
.finally(() => {
setBtnLoading(false);
});
};
const onFinishFailed = () => {
setBtnLoading(false);
};
const timeLenChange = (val: string) => {
setTimeLen(val);
const time = new Date().getTime();
if (val === 'forever') {
const longTime = 7 * 24 * 3600 * 1000 * 10000;
form.setFieldsValue({
btime: moment(time),
etime: moment(time).add({
seconds: longTime,
}),
});
return;
}
const unit = val.charAt(val.length - 1);
const num = val.substr(0, val.length - 1);
form.setFieldsValue({
btime: moment(time),
etime: moment(time).add({
[unit]: num,
}),
});
};
const content = (
<Form
form={form}
{...layout}
layout='vertical'
className='operate-form'
onFinish={onFinish}
onFinishFailed={onFinishFailed}
initialValues={{
...detail,
btime: detail?.btime ? moment(detail.btime * 1000) : moment(btimeDefault),
etime: detail?.etime ? moment(detail.etime * 1000) : moment(etimeDefault),
cluster: clusterList[0] || 'Default',
}}
>
<Card>
<Form.Item label={t('业务组:')} name='busiGroup'>
<Select suffixIcon={<CaretDownOutlined />}>
{busiGroups?.map((item) => (
<Option value={item.id} key={item.id}>
{item.name}
</Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t('生效集群:')}
name='cluster'
rules={[
{
required: true,
message: t('生效集群不能为空'),
},
]}
>
<Select suffixIcon={<CaretDownOutlined />}>
{clusterList?.map((item) => (
<Option value={item} key={item}>
{item}
</Option>
))}
</Select>
</Form.Item>
<Row gutter={10}>
<Col span={8}>
<Form.Item label={t('屏蔽开始时间:')} name='btime'>
<DatePicker showTime onChange={timeChange} />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label={t('屏蔽时长:')}>
<Select suffixIcon={<CaretDownOutlined />} placeholder={t('请选择屏蔽时长')} onChange={timeLenChange} value={timeLen}>
{timeLensDefault.map((item: any, index: number) => (
<Option key={index} value={item.value}>
{item.value}
</Option>
))}
</Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label={t('屏蔽结束时间:')} name='etime'>
<DatePicker showTime onChange={timeChange} />
</Form.Item>
</Col>
</Row>
<Row gutter={[10, 10]} style={{ marginBottom: '8px' }}>
<Col span={5}>
{t('屏蔽事件标签Key:')}
<Tooltip title={t(`这里的标签是指告警事件的标签,通过如下标签匹配规则过滤告警事件`)}>
<QuestionCircleFilled />
</Tooltip>
</Col>
<Col span={3}>{t('运算符:')}</Col>
<Col span={16}>{t('标签Value:')}</Col>
</Row>
<Form.List name='tags' initialValue={[{}]}>
{(fields, { add, remove }) => (
<>
{fields.map((field, index) => (
<TagItem field={field} key={index} remove={remove} form={form} />
))}
<Form.Item>
<PlusCircleOutlined className='control-icon-normal' onClick={() => add()} />
</Form.Item>
</>
)}
</Form.List>
{/* <Form.Item label={t('屏蔽时间')} name='time'>
<RangeDatePicker />
</Form.Item> */}
<Form.Item
label={t('屏蔽原因')}
name='cause'
rules={[
{
required: true,
message: t('请填写屏蔽原因'),
},
]}
>
<TextArea rows={3} />
</Form.Item>
<Form.Item {...tailLayout}>
<Row gutter={[10, 10]}>
<Col span={1}>
<Button type='primary' htmlType='submit'>
{type === 2 ? t('克隆') : t('创建')}
</Button>
</Col>
<Col
span={1}
style={{
marginLeft: 40,
}}
>
<Button onClick={() => window.history.back()}>{t('取消')}</Button>
</Col>
</Row>
</Form.Item>
</Card>
</Form>
);
return <div className='operate-form-index'>{content}</div>;
}
Example #4
Source File: editModal.tsx From fe-v5 with Apache License 2.0 | 4 votes |
editModal: React.FC<Props> = ({ isModalVisible, editModalFinish }) => {
const { t, i18n } = useTranslation();
const [form] = Form.useForm();
const { clusters: clusterList } = useSelector<RootState, CommonStoreState>((state) => state.common);
const [contactList, setInitContactList] = useState([]);
const [notifyGroups, setNotifyGroups] = useState([]);
const [field, setField] = useState<string>('cluster');
const [refresh, setRefresh] = useState(true);
useEffect(() => {
getNotifyChannel();
getGroups('');
return () => {};
}, []);
const enableDaysOfWeekOptions = [t('周日'), t('周一'), t('周二'), t('周三'), t('周四'), t('周五'), t('周六')].map((v, i) => {
return <Option value={String(i)} key={i}>{`${v}`}</Option>;
});
const contactListCheckboxes = contactList.map((c: { key: string; label: string }) => (
<Checkbox value={c.key} key={c.label}>
{c.label}
</Checkbox>
));
const notifyGroupsOptions = notifyGroups.map((ng: any) => (
<Option value={ng.id} key={ng.id}>
{ng.name}
</Option>
));
const getNotifyChannel = async () => {
const res = await getNotifiesList();
let contactList = res || [];
setInitContactList(contactList);
};
const getGroups = async (str) => {
const res = await getTeamInfoList({ query: str });
const data = res.dat || res;
setNotifyGroups(data || []);
};
const debounceFetcher = useCallback(debounce(getGroups, 800), []);
const modelOk = () => {
form.validateFields().then(async (values) => {
const data = { ...values };
switch (values.field) {
case 'enable_time':
data.enable_stime = values.enable_time[0].format('HH:mm');
data.enable_etime = values.enable_time[1].format('HH:mm');
delete data.enable_time;
break;
case 'disabled':
data.disabled = !values.enable_status ? 1 : 0;
delete data.enable_status;
break;
case 'enable_in_bg':
data.enable_in_bg = values.enable_in_bg ? 1 : 0;
break;
case 'callbacks':
data.callbacks = values.callbacks.map((item) => item.url);
break;
case 'notify_recovered':
data.notify_recovered = values.notify_recovered ? 1 : 0;
break;
default:
break;
}
delete data.field;
Object.keys(data).forEach((key) => {
// 因为功能上有清除备注的需求,需要支持传空
if (data[key] === undefined) {
data[key] = '';
}
if (Array.isArray(data[key])) {
data[key] = data[key].join(' ');
}
});
editModalFinish(true, data);
});
};
const editModalClose = () => {
editModalFinish(false);
};
const fieldChange = (val) => {
setField(val);
};
return (
<>
<Modal
title={t('批量更新')}
visible={isModalVisible}
onOk={modelOk}
onCancel={() => {
editModalClose();
}}
>
<Form
{...layout}
form={form}
className='strategy-form'
layout={refresh ? 'horizontal' : 'horizontal'}
initialValues={{
prom_eval_interval: 15,
disabled: 0, // 0:立即启用 1:禁用
enable_status: true, // true:立即启用 false:禁用
notify_recovered: 1, // 1:启用
enable_time: [moment('00:00', 'HH:mm'), moment('23:59', 'HH:mm')],
cluster: clusterList[0] || 'Default', // 生效集群
enable_days_of_week: ['1', '2', '3', '4', '5', '6', '0'],
field: 'cluster',
}}
>
<Form.Item
label={t('字段:')}
name='field'
rules={[
{
required: false,
},
]}
>
<Select suffixIcon={<CaretDownOutlined />} style={{ width: '100%' }} onChange={fieldChange}>
{fields.map((item) => (
<Option key={item.id} value={item.field}>
{item.name}
</Option>
))}
</Select>
</Form.Item>
{(() => {
switch (field) {
case 'note':
return (
<>
<Form.Item
label={t('改为:')}
name='note'
rules={[
{
required: false,
},
]}
>
<Input placeholder={t('请输入规则备注')} />
</Form.Item>
</>
);
case 'runbook_url':
return (
<>
<Form.Item label={t('改为:')} name='runbook_url'>
<Input />
</Form.Item>
</>
);
case 'cluster':
return (
<>
<Form.Item
label={t('改为:')}
name='cluster'
rules={[
{
required: false,
message: t('生效集群不能为空'),
},
]}
>
<Select suffixIcon={<CaretDownOutlined />}>
{clusterList?.map((item) => (
<Option value={item} key={item}>
{item}
</Option>
))}
</Select>
</Form.Item>
</>
);
case 'severity':
return (
<>
<Form.Item
label={t('改为:')}
name='severity'
initialValue={2}
rules={[
{
required: false,
message: t('告警级别不能为空'),
},
]}
>
<Radio.Group>
<Radio value={1}>{t('一级报警')}</Radio>
<Radio value={2}>{t('二级报警')}</Radio>
<Radio value={3}>{t('三级报警')}</Radio>
</Radio.Group>
</Form.Item>
</>
);
case 'disabled':
return (
<>
<Form.Item
label={t('改为:')}
name='enable_status'
rules={[
{
required: false,
message: t('立即启用不能为空'),
},
]}
valuePropName='checked'
>
<Switch />
</Form.Item>
</>
);
case 'enable_in_bg':
return (
<>
<Form.Item label={t('改为:')} name='enable_in_bg' valuePropName='checked'>
<SwitchWithLabel label='根据告警事件中的ident归属关系判断' />
</Form.Item>
</>
);
case 'prom_eval_interval':
return (
<>
<Form.Item
label={t('改为:')}
rules={[
{
required: false,
message: t('执行频率不能为空'),
},
]}
>
<Space>
<Form.Item style={{ marginBottom: 0 }} name='prom_eval_interval' initialValue={15} wrapperCol={{ span: 10 }}>
<InputNumber
min={1}
onChange={(val) => {
setRefresh(!refresh);
}}
/>
</Form.Item>
秒
<Tooltip title={t(`每隔${form.getFieldValue('prom_eval_interval')}秒,把PromQL作为查询条件,去查询后端存储,如果查到了数据就表示当次有监控数据触发了规则`)}>
<QuestionCircleFilled />
</Tooltip>
</Space>
</Form.Item>
</>
);
case 'prom_for_duration':
return (
<>
<Form.Item
label={t('改为:')}
rules={[
{
required: false,
message: t('持续时长不能为空'),
},
]}
>
<Space>
<Form.Item style={{ marginBottom: 0 }} name='prom_for_duration' initialValue={60} wrapperCol={{ span: 10 }}>
<InputNumber min={0} />
</Form.Item>
秒
<Tooltip
title={t(
`通常持续时长大于执行频率,在持续时长内按照执行频率多次执行PromQL查询,每次都触发才生成告警;如果持续时长置为0,表示只要有一次PromQL查询触发阈值,就生成告警`,
)}
>
<QuestionCircleFilled />
</Tooltip>
</Space>
</Form.Item>
</>
);
case 'notify_channels':
return (
<>
<Form.Item label={t('改为:')} name='notify_channels'>
<Checkbox.Group>{contactListCheckboxes}</Checkbox.Group>
</Form.Item>
</>
);
case 'notify_groups':
return (
<>
<Form.Item label={t('改为:')} name='notify_groups'>
<Select mode='multiple' showSearch optionFilterProp='children' filterOption={false} onSearch={(e) => debounceFetcher(e)} onBlur={() => getGroups('')}>
{notifyGroupsOptions}
</Select>
</Form.Item>
</>
);
case 'notify_recovered':
return (
<>
<Form.Item label={t('改为:')} name='notify_recovered' valuePropName='checked'>
<Switch />
</Form.Item>
</>
);
case 'recover_duration':
return (
<>
<Form.Item label={t('改为:')}>
<Space>
<Form.Item
style={{ marginBottom: 0 }}
name='recover_duration'
initialValue={0}
wrapperCol={{ span: 10 }}
rules={[
{
required: false,
message: t('留观时长不能为空'),
},
]}
>
<InputNumber
min={0}
onChange={(val) => {
setRefresh(!refresh);
}}
/>
</Form.Item>
秒
<Tooltip title={t(`持续${form.getFieldValue('recover_duration') || 0}秒没有再次触发阈值才发送恢复通知`)}>
<QuestionCircleFilled />
</Tooltip>
</Space>
</Form.Item>
</>
);
case 'notify_repeat_step':
return (
<>
<Form.Item label={t('改为:')}>
<Space>
<Form.Item
style={{ marginBottom: 0 }}
name='notify_repeat_step'
initialValue={60}
wrapperCol={{ span: 10 }}
rules={[
{
required: false,
message: t('重复发送频率不能为空'),
},
]}
>
<InputNumber
min={0}
onChange={(val) => {
setRefresh(!refresh);
}}
/>
</Form.Item>
分钟
<Tooltip title={t(`如果告警持续未恢复,间隔${form.getFieldValue('notify_repeat_step')}分钟之后重复提醒告警接收组的成员`)}>
<QuestionCircleFilled />
</Tooltip>
</Space>
</Form.Item>
</>
);
case 'callbacks':
return (
<>
<Form.Item label={t('改为:')}>
<Form.List name='callbacks' initialValue={[{}]}>
{(fields, { add, remove }, { errors }) => (
<>
{fields.map((field, index) => (
<Row gutter={[10, 0]} key={field.key}>
<Col span={22}>
<Form.Item name={[field.name, 'url']}>
<Input />
</Form.Item>
</Col>
<Col span={1}>
<MinusCircleOutlined className='control-icon-normal' onClick={() => remove(field.name)} />
</Col>
</Row>
))}
<PlusCircleOutlined className='control-icon-normal' onClick={() => add()} />
</>
)}
</Form.List>
</Form.Item>
</>
);
case 'append_tags':
return (
<>
<Form.Item label='附加标签' name='append_tags' rules={[{ required: false, message: '请填写至少一项标签!' }, isValidFormat]}>
<Select mode='tags' tokenSeparators={[' ']} open={false} placeholder={'标签格式为 key=value ,使用回车或空格分隔'} tagRender={tagRender} />
</Form.Item>
</>
);
case 'enable_time':
return (
<>
<Form.Item
label={t('改为:')}
name='enable_days_of_week'
rules={[
{
required: false,
message: t('生效时间不能为空'),
},
]}
>
<Select mode='tags'>{enableDaysOfWeekOptions}</Select>
</Form.Item>
<Form.Item
name='enable_time'
{...tailLayout}
rules={[
{
required: false,
message: t('生效时间不能为空'),
},
]}
>
<TimePicker.RangePicker
format='HH:mm'
onChange={(val, val2) => {
form.setFieldsValue({
enable_stime: val2[0],
enable_etime: val2[1],
});
}}
/>
</Form.Item>
</>
);
default:
return null;
}
})()}
</Form>
</Modal>
</>
);
}
Example #5
Source File: operateForm.tsx From fe-v5 with Apache License 2.0 | 4 votes |
operateForm: React.FC<Props> = ({ type, detail = {} }) => {
const { t, i18n } = useTranslation();
const history = useHistory(); // 创建的时候默认选中的值
const [form] = Form.useForm();
const { clusters: clusterList } = useSelector<RootState, CommonStoreState>((state) => state.common);
const { curBusiItem } = useSelector<RootState, CommonStoreState>((state) => state.common);
const [contactList, setInitContactList] = useState([]);
const [notifyGroups, setNotifyGroups] = useState<any[]>([]);
const [initVal, setInitVal] = useState<any>({});
const [refresh, setRefresh] = useState(true);
useEffect(() => {
getNotifyChannel();
getGroups('');
return () => {};
}, []);
useEffect(() => {
const data = {
...detail,
enable_time: detail?.enable_stime ? [detail.enable_stime, detail.enable_etime] : [],
enable_status: detail?.disabled === undefined ? true : !detail?.disabled,
};
setInitVal(data);
if (type == 1) {
const groups = (detail.notify_groups_obj ? detail.notify_groups_obj.filter((item) => !notifyGroups.find((i) => item.id === i.id)) : []).concat(notifyGroups);
setNotifyGroups(groups);
}
}, [JSON.stringify(detail)]);
const enableDaysOfWeekOptions = [t('周日'), t('周一'), t('周二'), t('周三'), t('周四'), t('周五'), t('周六')].map((v, i) => {
return <Option value={String(i)} key={i}>{`${v}`}</Option>;
});
const contactListCheckboxes = contactList.map((c: { key: string; label: string }) => (
<Checkbox value={c.key} key={c.label}>
{c.label}
</Checkbox>
));
const notifyGroupsOptions = notifyGroups.map((ng: any) => (
<Option value={String(ng.id)} key={ng.id}>
{ng.name}
</Option>
));
const getNotifyChannel = async () => {
const res = await getNotifiesList();
let contactList = res || [];
setInitContactList(contactList);
};
const getGroups = async (str) => {
const res = await getTeamInfoList({ query: str });
const data = res.dat || res;
const combineData = (detail.notify_groups_obj ? detail.notify_groups_obj.filter((item) => !data.find((i) => item.id === i.id)) : []).concat(data);
setNotifyGroups(combineData || []);
};
const addSubmit = () => {
form.validateFields().then(async (values) => {
const res = await prometheusQuery({ query: values.prom_ql }, values.cluster);
if (res.error) {
notification.error({
message: res.error,
});
return false;
}
const callbacks = values.callbacks.map((item) => item.url);
const data = {
...values,
enable_stime: values.enable_time[0].format('HH:mm'),
enable_etime: values.enable_time[1].format('HH:mm'),
disabled: !values.enable_status ? 1 : 0,
notify_recovered: values.notify_recovered ? 1 : 0,
enable_in_bg: values.enable_in_bg ? 1 : 0,
callbacks,
};
let reqBody,
method = 'Post';
if (type === 1) {
reqBody = data;
method = 'Put';
const res = await EditStrategy(reqBody, curBusiItem.id, detail.id);
if (res.err) {
message.error(res.error);
} else {
message.success(t('编辑成功!'));
history.push('/alert-rules');
}
} else {
reqBody = [data];
const { dat } = await addOrEditStrategy(reqBody, curBusiItem.id, method);
let errorNum = 0;
const msg = Object.keys(dat).map((key) => {
dat[key] && errorNum++;
return dat[key];
});
if (!errorNum) {
message.success(`${type === 2 ? t('告警规则克隆成功') : t('告警规则创建成功')}`);
history.push('/alert-rules');
} else {
message.error(t(msg));
}
}
});
};
const debounceFetcher = useCallback(debounce(getGroups, 800), []);
return (
<div className='operate_con'>
<Form
{...layout}
form={form}
className='strategy-form'
layout={refresh ? 'horizontal' : 'horizontal'}
initialValues={{
prom_eval_interval: 15,
prom_for_duration: 60,
severity: 2,
disabled: 0, // 0:立即启用 1:禁用 待修改
// notify_recovered: 1, // 1:启用
cluster: clusterList[0] || 'Default', // 生效集群
enable_days_of_week: ['1', '2', '3', '4', '5', '6', '0'],
...detail,
enable_in_bg: detail?.enable_in_bg === 1,
enable_time: detail?.enable_stime ? [moment(detail.enable_stime, 'HH:mm'), moment(detail.enable_etime, 'HH:mm')] : [moment('00:00', 'HH:mm'), moment('23:59', 'HH:mm')],
enable_status: detail?.disabled === undefined ? true : !detail?.disabled,
notify_recovered: detail?.notify_recovered === 1 || detail?.notify_recovered === undefined ? true : false, // 1:启用 0:禁用
recover_duration: detail?.recover_duration || 0,
callbacks: !!detail?.callbacks
? detail.callbacks.map((item) => ({
url: item,
}))
: [{}],
}}
>
<Space direction='vertical' style={{ width: '100%' }}>
<Card title={t('基本配置')}>
<Form.Item
label={t('规则标题:')}
name='name'
rules={[
{
required: true,
message: t('规则标题不能为空'),
},
]}
>
<Input placeholder={t('请输入规则标题')} />
</Form.Item>
<Form.Item
label={t('规则备注:')}
name='note'
rules={[
{
required: false,
},
]}
>
<Input placeholder={t('请输入规则备注')} />
</Form.Item>
<Form.Item
label={t('告警级别')}
name='severity'
rules={[
{
required: true,
message: t('告警级别不能为空'),
},
]}
>
<Radio.Group>
<Radio value={1}>{t('一级报警')}</Radio>
<Radio value={2}>{t('二级报警')}</Radio>
<Radio value={3}>{t('三级报警')}</Radio>
</Radio.Group>
</Form.Item>
<Form.Item
label={t('生效集群')}
name='cluster'
rules={[
{
required: true,
message: t('生效集群不能为空'),
},
]}
>
<Select suffixIcon={<CaretDownOutlined />}>
{clusterList?.map((item) => (
<Option value={item} key={item}>
{item}
</Option>
))}
</Select>
</Form.Item>
<AdvancedWrap>
<AbnormalDetection form={form} />
</AdvancedWrap>
<Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.cluster !== curValues.cluster}>
{() => {
return (
<Form.Item label='PromQL' className={'Promeql-content'} required>
<Form.Item name='prom_ql' validateTrigger={['onBlur']} trigger='onChange' rules={[{ required: true, message: t('请输入PromQL') }]}>
<PromQLInput
url='/api/n9e/prometheus'
headers={{
'X-Cluster': form.getFieldValue('cluster'),
Authorization: `Bearer ${localStorage.getItem('access_token') || ''}`,
}}
/>
</Form.Item>
</Form.Item>
);
}}
</Form.Item>
<Form.Item required label={t('执行频率')}>
<Space>
<Form.Item
style={{ marginBottom: 0 }}
name='prom_eval_interval'
initialValue={15}
wrapperCol={{ span: 10 }}
rules={[
{
required: true,
message: t('执行频率不能为空'),
},
]}
>
<InputNumber
min={1}
onChange={(val) => {
setRefresh(!refresh);
}}
/>
</Form.Item>
秒
<Tooltip title={t(`每隔${form.getFieldValue('prom_eval_interval')}秒,把PromQL作为查询条件,去查询后端存储,如果查到了数据就表示当次有监控数据触发了规则`)}>
<QuestionCircleFilled />
</Tooltip>
</Space>
</Form.Item>
<Form.Item
required
label={t('持续时长')}
rules={[
{
required: true,
message: t('持续时长不能为空'),
},
]}
>
<Space>
<Form.Item style={{ marginBottom: 0 }} name='prom_for_duration' wrapperCol={{ span: 10 }}>
<InputNumber min={0} />
</Form.Item>
秒
<Tooltip
title={t(
`通常持续时长大于执行频率,在持续时长内按照执行频率多次执行PromQL查询,每次都触发才生成告警;如果持续时长置为0,表示只要有一次PromQL查询触发阈值,就生成告警`,
)}
>
<QuestionCircleFilled />
</Tooltip>
</Space>
</Form.Item>
<Form.Item label='附加标签' name='append_tags' rules={[{ required: false, message: '请填写至少一项标签!' }, isValidFormat]}>
<Select mode='tags' tokenSeparators={[' ']} open={false} placeholder={'标签格式为 key=value ,使用回车或空格分隔'} tagRender={tagRender} />
</Form.Item>
<Form.Item label={t('预案链接')} name='runbook_url'>
<Input />
</Form.Item>
</Card>
<Card title={t('生效配置')}>
<Form.Item
label={t('立即启用')}
name='enable_status'
rules={[
{
required: true,
message: t('立即启用不能为空'),
},
]}
valuePropName='checked'
>
<Switch />
</Form.Item>
<Form.Item
label={t('生效时间')}
name='enable_days_of_week'
rules={[
{
required: true,
message: t('生效时间不能为空'),
},
]}
>
<Select mode='tags'>{enableDaysOfWeekOptions}</Select>
</Form.Item>
<Form.Item
name='enable_time'
{...tailLayout}
rules={[
{
required: true,
message: t('生效时间不能为空'),
},
]}
>
<TimePicker.RangePicker
format='HH:mm'
onChange={(val, val2) => {
form.setFieldsValue({
enable_stime: val2[0],
enable_etime: val2[1],
});
}}
/>
</Form.Item>
<Form.Item label={t('仅在本业务组生效')} name='enable_in_bg' valuePropName='checked'>
<SwitchWithLabel label='根据告警事件中的ident归属关系判断' />
</Form.Item>
</Card>
<Card title={t('通知配置')}>
<Form.Item label={t('通知媒介')} name='notify_channels'>
<Checkbox.Group>{contactListCheckboxes}</Checkbox.Group>
</Form.Item>
<Form.Item label={t('告警接收组')} name='notify_groups'>
<Select mode='multiple' showSearch optionFilterProp='children' filterOption={false} onSearch={(e) => debounceFetcher(e)} onBlur={() => getGroups('')}>
{notifyGroupsOptions}
</Select>
</Form.Item>
<Form.Item label={t('启用恢复通知')}>
<Space>
<Form.Item name='notify_recovered' valuePropName='checked' style={{ marginBottom: 0 }}>
<Switch />
</Form.Item>
<Tooltip title={t(`告警恢复时也发送通知`)}>
<QuestionCircleFilled />
</Tooltip>
</Space>
</Form.Item>
<Form.Item label={t('留观时长')} required>
<Space>
<Form.Item style={{ marginBottom: 0 }} name='recover_duration' initialValue={0} wrapperCol={{ span: 10 }}>
<InputNumber
min={0}
onChange={(val) => {
setRefresh(!refresh);
}}
/>
</Form.Item>
秒
<Tooltip title={t(`持续${form.getFieldValue('recover_duration')}秒没有再次触发阈值才发送恢复通知`)}>
<QuestionCircleFilled />
</Tooltip>
</Space>
</Form.Item>
<Form.Item label={t('重复发送频率')} required>
<Space>
<Form.Item
style={{ marginBottom: 0 }}
name='notify_repeat_step'
initialValue={60}
wrapperCol={{ span: 10 }}
rules={[
{
required: true,
message: t('重复发送频率不能为空'),
},
]}
>
<InputNumber
min={0}
onChange={(val) => {
setRefresh(!refresh);
}}
/>
</Form.Item>
分钟
<Tooltip title={t(`如果告警持续未恢复,间隔${form.getFieldValue('notify_repeat_step')}分钟之后重复提醒告警接收组的成员`)}>
<QuestionCircleFilled />
</Tooltip>
</Space>
</Form.Item>
<Form.Item label={t('回调地址')}>
<Form.List name='callbacks' initialValue={[{}]}>
{(fields, { add, remove }) => (
<>
{fields.map((field) => (
<Row gutter={[10, 0]} key={field.key}>
<Col span={22}>
<Form.Item name={[field.name, 'url']} fieldKey={[field.fieldKey, 'url']}>
<Input />
</Form.Item>
</Col>
<Col span={1}>
<MinusCircleOutlined className='control-icon-normal' onClick={() => remove(field.name)} />
</Col>
</Row>
))}
<PlusCircleOutlined className='control-icon-normal' onClick={() => add()} />
</>
)}
</Form.List>
</Form.Item>
</Card>
<Form.Item
// {...tailLayout}
style={{
marginTop: 20,
}}
>
<Button type='primary' onClick={addSubmit} style={{ marginRight: '8px' }}>
{type === 1 ? t('编辑') : type === 2 ? t('克隆') : t('创建')}
</Button>
{type === 1 && (
<Button
danger
style={{ marginRight: '8px' }}
onClick={() => {
Modal.confirm({
title: t('是否删除该告警规则?'),
onOk: () => {
deleteStrategy([detail.id], curBusiItem.id).then(() => {
message.success(t('删除成功'));
history.push('/alert-rules');
});
},
onCancel() {},
});
}}
>
{t('删除')}
</Button>
)}
<Button
onClick={() => {
history.push('/alert-rules');
}}
>
{t('取消')}
</Button>
</Form.Item>
</Space>
</Form>
</div>
);
}
Example #6
Source File: operateForm.tsx From fe-v5 with Apache License 2.0 | 4 votes |
OperateForm: React.FC<Props> = ({ detail = {}, type }) => {
const { t, i18n } = useTranslation();
const { clusters: clusterList } = useSelector<RootState, CommonStoreState>((state) => state.common);
const layout = {
labelCol: {
span: 24,
},
wrapperCol: {
span: 24,
},
};
const tailLayout = {
labelCol: {
span: 24,
},
wrapperCol: {
span: 24,
},
};
const [form] = Form.useForm(null as any);
const history = useHistory();
const { curBusiItem } = useSelector<RootState, CommonStoreState>((state) => state.common);
const [btnLoading, setBtnLoading] = useState<boolean>(false);
const [ruleModalShow, setRuleModalShow] = useState<boolean>(false);
const [ruleCur, setRuleCur] = useState<any>();
const [contactList, setInitContactList] = useState([]);
const [littleAffect, setLittleAffect] = useState(true);
const [notifyGroups, setNotifyGroups] = useState<any[]>([]);
useEffect(() => {
getNotifyChannel();
getGroups('');
}, []);
useEffect(() => {
setRuleCur({
id: detail.rule_id || 0,
name: detail.rule_name,
});
}, [detail.rule_id]);
const notifyGroupsOptions = (detail.user_groups ? detail.user_groups.filter((item) => !notifyGroups.find((i) => item.id === i.id)) : []).concat(notifyGroups).map((ng: any) => (
<Option value={String(ng.id)} key={ng.id}>
{ng.name}
</Option>
));
const getNotifyChannel = async () => {
const res = await getNotifiesList();
let contactList = res || [];
setInitContactList(contactList);
};
const getGroups = async (str) => {
const res = await getTeamInfoList({ query: str });
const data = res.dat || res;
setNotifyGroups(data || []);
};
const debounceFetcher = useCallback(_.debounce(getGroups, 800), []);
const onFinish = (values) => {
setBtnLoading(true);
const tags = values?.tags?.map((item) => {
return {
...item,
value: Array.isArray(item.value) ? item.value.join(' ') : item.value,
};
});
const params = {
...values,
tags,
redefine_severity: values.redefine_severity ? 1 : 0,
redefine_channels: values.redefine_channels ? 1 : 0,
rule_id: ruleCur.id,
user_group_ids: values.user_group_ids ? values.user_group_ids.join(' ') : '',
new_channels: values.new_channels ? values.new_channels.join(' ') : '',
};
if (type === 1) {
editSubscribe([{ ...params, id: detail.id }], curBusiItem.id)
.then((_) => {
message.success(t('编辑订阅规则成功'));
history.push('/alert-subscribes');
})
.finally(() => {
setBtnLoading(false);
});
} else {
addSubscribe(params, curBusiItem.id)
.then((_) => {
message.success(t('新建订阅规则成功'));
history.push('/alert-subscribes');
})
.finally(() => {
setBtnLoading(false);
});
}
};
const onFinishFailed = () => {
setBtnLoading(false);
};
const chooseRule = () => {
setRuleModalShow(true);
};
const subscribeRule = (val) => {
setRuleModalShow(false);
setRuleCur(val);
form.setFieldsValue({
rile_id: val.id || 0,
});
};
return (
<>
<div className='operate-form-index' id={littleAffect ? 'littleAffect' : ''}>
<Form
form={form}
{...layout}
layout='vertical'
className='operate-form'
onFinish={onFinish}
onFinishFailed={onFinishFailed}
initialValues={{
...detail,
cluster: clusterList[0] || 'Default',
redefine_severity: detail?.redefine_severity ? true : false,
redefine_channels: detail?.redefine_channels ? true : false,
user_group_ids: detail?.user_group_ids ? detail?.user_group_ids?.split(' ') : [],
new_channels: detail?.new_channels?.split(' '),
}}
>
<Card>
<Form.Item
label={t('生效集群:')}
name='cluster'
rules={[
{
required: true,
message: t('生效集群不能为空'),
},
]}
>
<Select suffixIcon={<CaretDownOutlined />}>
{clusterList?.map((item, index) => (
<Option value={item} key={index}>
{item}
</Option>
))}
</Select>
</Form.Item>
<Form.Item label={t('订阅告警规则:')}>
{!!ruleCur?.id && (
<Button
type='primary'
ghost
style={{ marginRight: '8px' }}
onClick={() => {
ruleCur?.id && history.push(`/alert-rules/edit/${ruleCur?.id}`);
}}
>
{ruleCur?.name}
</Button>
)}
<EditOutlined style={{ cursor: 'pointer', fontSize: '18px' }} onClick={chooseRule} />
{!!ruleCur?.id && <DeleteOutlined style={{ cursor: 'pointer', fontSize: '18px', marginLeft: 5 }} onClick={() => subscribeRule({})} />}
</Form.Item>
<Row gutter={[10, 10]} style={{ marginBottom: '8px' }}>
<Col span={5}>
{t('订阅事件标签Key:')}
<Tooltip title={t(`这里的标签是指告警事件的标签,通过如下标签匹配规则过滤告警事件`)}>
<QuestionCircleFilled />
</Tooltip>
</Col>
<Col span={3}>{t('运算符:')}</Col>
<Col span={16}>{t('标签Value:')}</Col>
</Row>
<Form.List name='tags' initialValue={[{}]}>
{(fields, { add, remove }) => (
<>
{fields.map((field, index) => (
<TagItem field={field} fields={fields} key={index} remove={remove} add={add} form={form} />
))}
<Form.Item>
<PlusCircleOutlined className='control-icon-normal' onClick={() => add()} />
</Form.Item>
</>
)}
</Form.List>
<Form.Item label={t('告警级别:')} name='redefine_severity' valuePropName='checked'>
<Checkbox
value={1}
style={{ lineHeight: '32px' }}
onChange={(e) => {
form.setFieldsValue({
redefine_severity: e.target.checked ? 1 : 0,
});
setLittleAffect(!littleAffect);
}}
>
{t('重新定义')}
</Checkbox>
</Form.Item>
<Form.Item label={t('新的告警级别:')} name='new_severity' initialValue={2} style={{ display: form.getFieldValue('redefine_severity') ? 'block' : 'none' }}>
<Radio.Group>
<Radio key={1} value={1}>
{t('一级报警')}
</Radio>
<Radio key={2} value={2}>
{t('二级报警')}
</Radio>
<Radio key={3} value={3}>
{t('三级报警')}
</Radio>
</Radio.Group>
</Form.Item>
<Form.Item label={t('通知媒介:')} name='redefine_channels' valuePropName='checked'>
<Checkbox
value={1}
style={{ lineHeight: '32px' }}
onChange={(e) => {
form.setFieldsValue({
redefine_channels: e.target.checked ? 1 : 0,
});
setLittleAffect(!littleAffect);
}}
>
{t('重新定义')}
</Checkbox>
</Form.Item>
<Form.Item label={t('新的通知媒介:')} name='new_channels' style={{ display: form.getFieldValue('redefine_channels') ? 'block' : 'none' }}>
<Checkbox.Group>
{contactList.map((c: { key: string; label: string }) => (
<Checkbox value={c.key} key={c.label}>
{c.label}
</Checkbox>
))}
</Checkbox.Group>
</Form.Item>
<Form.Item label={t('订阅告警接收组:')} name='user_group_ids' rules={[{ required: true, message: t('告警接收组不能为空') }]}>
<Select mode='multiple' showSearch optionFilterProp='children' filterOption={false} onSearch={(e) => debounceFetcher(e)} onBlur={() => getGroups('')}>
{notifyGroupsOptions}
</Select>
</Form.Item>
<Form.Item {...tailLayout}>
<Button type='primary' htmlType='submit' style={{ marginRight: '8px' }}>
{type === 1 ? t('编辑') : type === 2 ? t('克隆') : t('创建')}
</Button>
{type === 1 && (
<Button
danger
style={{ marginRight: '8px' }}
onClick={() => {
Modal.confirm({
title: t('是否删除该告警规则?'),
onOk: () => {
detail?.id &&
deleteSubscribes({ ids: [detail.id] }, curBusiItem.id).then(() => {
message.success(t('删除成功'));
history.push('/alert-subscribes');
});
},
onCancel() {},
});
}}
>
{t('删除')}
</Button>
)}
<Button onClick={() => window.history.back()}>{t('取消')}</Button>
</Form.Item>
</Card>
</Form>
<RuleModal
visible={ruleModalShow}
ruleModalClose={() => {
setRuleModalShow(false);
}}
subscribe={subscribeRule}
/>
</div>
</>
);
}