Browse Source

[Feature][UI Next] Add alarm instance manage (#8208)

3.0.0/version-upgrade
Amy0104 3 years ago committed by GitHub
parent
commit
767c03551b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 54
      dolphinscheduler-ui-next/src/components/form/fields.ts
  2. 60
      dolphinscheduler-ui-next/src/components/form/get-elements-by-json.ts
  3. 71
      dolphinscheduler-ui-next/src/components/form/index.tsx
  4. 68
      dolphinscheduler-ui-next/src/components/form/types.ts
  5. 45
      dolphinscheduler-ui-next/src/components/form/use-form.ts
  6. 37
      dolphinscheduler-ui-next/src/components/form/utils.ts
  7. 55
      dolphinscheduler-ui-next/src/locales/modules/en_US.ts
  8. 55
      dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
  9. 9
      dolphinscheduler-ui-next/src/router/modules/security.ts
  10. 7
      dolphinscheduler-ui-next/src/service/modules/alert-plugin/index.ts
  11. 6
      dolphinscheduler-ui-next/src/service/modules/alert-plugin/types.ts
  12. 4
      dolphinscheduler-ui-next/src/service/modules/ui-plugins/index.ts
  13. 6
      dolphinscheduler-ui-next/src/service/modules/ui-plugins/types.ts
  14. 196
      dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/detail.tsx
  15. 32
      dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/index.module.scss
  16. 170
      dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/index.tsx
  17. 51
      dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/types.ts
  18. 100
      dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/use-columns.ts
  19. 78
      dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/use-detail.ts
  20. 131
      dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/use-form.ts
  21. 95
      dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/use-table.ts
  22. 28
      dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/use-userinfo.ts

54
dolphinscheduler-ui-next/src/components/form/fields.ts

@ -0,0 +1,54 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { h } from 'vue'
import { NInput, NRadio, NRadioGroup, NSpace } from 'naive-ui'
import type { IFieldParams } from './types'
// TODO Support other widgets later
// Input
export function renderInput(params: IFieldParams) {
const { props, fields, field } = params
return h(NInput, {
...props,
value: fields[field],
onUpdateValue: (value) => void (fields[field] = value)
})
}
// Radio && RadioGroup
export function renderRadio(params: IFieldParams) {
const { props, fields, field, options } = params
if (!options || options.length === 0) {
return h(NRadio, {
...props,
value: fields[field],
onUpdateChecked: (checked) => void (fields[field] = checked)
})
}
return h(
NRadioGroup,
{
value: fields[field],
onUpdateValue: (value) => void (fields[field] = value)
},
() =>
h(NSpace, null, () =>
options.map((option) => h(NRadio, option, () => option.label))
)
)
}

60
dolphinscheduler-ui-next/src/components/form/get-elements-by-json.ts

@ -0,0 +1,60 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as Field from './fields'
import { formatValidate } from './utils'
import type { FormRules } from 'naive-ui'
import type { IJsonItem } from './types'
export default function getElementByJson(
json: IJsonItem[],
fields: { [field: string]: any },
t: Function,
prefix: string
) {
const rules: FormRules = {}
const initialValues: { [field: string]: any } = {}
const elements = []
const getElement = (item: IJsonItem) => {
const { type, props = {}, field, options } = item
// TODO Support other widgets later
if (type === 'radio') {
return Field.renderRadio({
field,
fields,
props,
options
})
}
return Field.renderInput({ field, fields, props })
}
for (let item of json) {
fields[item.field] = item.value
initialValues[item.field] = item.value
if (item.validate) rules[item.field] = formatValidate(item.validate)
elements.push({
label: t(prefix + '.' + item.field),
path: item.field,
widget: () => getElement(item)
})
}
return { rules, elements, initialValues }
}

71
dolphinscheduler-ui-next/src/components/form/index.tsx

@ -0,0 +1,71 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { defineComponent, PropType, toRefs, h } from 'vue'
import { NSpin, NGrid, NForm, NFormItemGi } from 'naive-ui'
import { useForm } from './use-form'
import type { GridProps, IMeta } from './types'
const props = {
meta: {
type: Object as PropType<IMeta>,
default: {},
required: true
},
layout: {
type: Object as PropType<GridProps>
},
loading: {
type: Boolean as PropType<boolean>,
default: false
}
}
const Form = defineComponent({
name: 'Form',
props,
setup(props, { expose }) {
const { state, ...rest } = useForm()
expose({
...rest
})
return { ...toRefs(state) }
},
render(props: { meta: IMeta; layout?: GridProps; loading?: boolean }) {
const { loading, layout, meta } = props
const { elements, ...restFormProps } = meta
return (
<NSpin show={loading}>
<NForm {...restFormProps} ref='formRef'>
<NGrid {...layout}>
{elements &&
elements.map((element) => {
const { span = 24, path, widget, ...formItemProps } = element
return (
<NFormItemGi {...formItemProps} span={span} path={path}>
{h(widget)}
</NFormItemGi>
)
})}
</NGrid>
</NForm>
</NSpin>
)
}
})
export default Form

68
dolphinscheduler-ui-next/src/components/form/types.ts

@ -0,0 +1,68 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type {
GridProps,
FormProps,
FormItemGiProps,
FormItemRule,
FormRules,
SelectOption
} from 'naive-ui'
type IType = 'input' | 'radio'
type IOption = SelectOption
interface IFormItem extends FormItemGiProps {
widget: any
}
interface IMeta extends Omit<FormProps, 'model'> {
elements?: IFormItem[]
model: object
}
interface IFieldParams {
field: string
props: object
fields: { [field: string]: any }
options?: IOption[]
}
interface IJsonItem {
field: string
name?: string
props?: object
title?: string
type?: IType
validate?: FormItemRule
value?: any
options?: IOption[]
}
export {
IMeta,
IType,
IJsonItem,
IOption,
FormItemRule,
FormRules,
IFormItem,
GridProps,
IFieldParams
}

45
dolphinscheduler-ui-next/src/components/form/use-form.ts

@ -0,0 +1,45 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { reactive, ref } from 'vue'
export function useForm() {
const state = reactive({
formRef: ref()
})
const validate = () => {
state.formRef.validate()
}
const setValues = (initialValues: { [field: string]: any }) => {
for (let [key, value] of Object.entries(initialValues)) {
state.formRef.model[key] = value
}
}
const restoreValidation = () => {
state.formRef.restoreValidation()
}
return {
state,
validate,
setValues,
restoreValidation
}
}

37
dolphinscheduler-ui-next/src/components/form/utils.ts

@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { FormRules, FormItemRule } from './types'
export function formatLabel(label?: string): string {
if (!label) return ''
const match = label.match(/^\$t\('(\S*)'\)/)
return match ? match[1] : label
}
export function formatValidate(
validate?: FormItemRule | FormRules
): FormItemRule {
if (!validate) return {}
if (Array.isArray(validate)) {
validate.map((item: FormItemRule) => {
if (!item?.message) delete item.message
return item
})
}
if (!validate.message) delete validate.message
return validate
}

55
dolphinscheduler-ui-next/src/locales/modules/en_US.ts

@ -482,6 +482,61 @@ const security = {
delete: 'Delete', delete: 'Delete',
save_error_msg: 'Failed to save, please retry', save_error_msg: 'Failed to save, please retry',
delete_error_msg: 'Failed to delete, please retry' delete_error_msg: 'Failed to delete, please retry'
},
alarm_instance: {
search_input_tips: 'Please input the keywords',
alarm_instance_manage: 'Alarm instance manage',
alarm_instance: 'Alarm Instance',
serial_number: '#',
alarm_instance_name: 'Alarm instance name',
alarm_instance_name_tips: 'Please enter alarm plugin instance name',
alarm_plugin_name: 'Alarm plugin name',
create_time: 'Create Time',
update_time: 'Update Time',
operation: 'Operation',
edit: 'Edit',
delete: 'Delete',
confirm: 'Confirm',
cancel: 'Cancel',
submit: 'Submit',
create: 'Create',
select_plugin: 'Select plugin',
select_plugin_tips: 'Select Alarm plugin',
instance_parameter_exception: 'Instance parameter exception',
WebHook: 'WebHook',
webHook: 'WebHook',
IsEnableProxy: 'Enable Proxy',
Proxy: 'Proxy',
Port: 'Port',
User: 'User',
corpId: 'CorpId',
secret: 'Secret',
Secret: 'Secret',
users: 'Users',
userSendMsg: 'UserSendMsg',
agentId: 'AgentId',
showType: 'Show Type',
receivers: 'Receivers',
receiverCcs: 'ReceiverCcs',
serverHost: 'SMTP Host',
serverPort: 'SMTP Port',
sender: 'Sender',
enableSmtpAuth: 'SMTP Auth',
Password: 'Password',
starttlsEnable: 'SMTP STARTTLS Enable',
sslEnable: 'SMTP SSL Enable',
smtpSslTrust: 'SMTP SSL Trust',
url: 'URL',
requestType: 'Request Type',
headerParams: 'Headers',
bodyParams: 'Body',
contentField: 'Content Field',
Keyword: 'Keyword',
userParams: 'User Params',
path: 'Script Path',
type: 'Type',
sendType: 'Send Type',
username: 'Username'
} }
} }

55
dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts

@ -479,6 +479,61 @@ const security = {
delete: '删除', delete: '删除',
save_error_msg: '保存失败,请重试', save_error_msg: '保存失败,请重试',
delete_error_msg: '删除失败,请重试' delete_error_msg: '删除失败,请重试'
},
alarm_instance: {
search_input_tips: '请输入关键字',
alarm_instance_manage: '告警实例管理',
alarm_instance: '告警实例',
serial_number: '编号',
alarm_instance_name: '告警实例名称',
alarm_instance_name_tips: '请输入告警实例名称',
alarm_plugin_name: '告警插件名称',
create_time: '创建时间',
update_time: '更新时间',
operation: '操作',
edit: '编辑',
delete: '删除',
confirm: '确定',
cancel: '取消',
submit: '提交',
create: '创建',
select_plugin: '选择插件',
select_plugin_tips: '请选择告警插件',
instance_parameter_exception: '实例参数异常',
WebHook: 'Web钩子',
webHook: 'Web钩子',
IsEnableProxy: '启用代理',
Proxy: '代理',
Port: '端口',
User: '用户',
corpId: '企业ID',
secret: '密钥',
Secret: '密钥',
users: '群员',
userSendMsg: '群员信息',
agentId: '应用ID',
showType: '内容展示类型',
receivers: '收件人',
receiverCcs: '抄送人',
serverHost: 'SMTP服务器',
serverPort: 'SMTP端口',
sender: '发件人',
enableSmtpAuth: '请求认证',
Password: '密码',
starttlsEnable: 'STARTTLS连接',
sslEnable: 'SSL连接',
smtpSslTrust: 'SSL证书信任',
url: 'URL',
requestType: '请求方式',
headerParams: '请求头',
bodyParams: '请求体',
contentField: '内容字段',
Keyword: '关键词',
userParams: '自定义参数',
path: '脚本路径',
type: '类型',
sendType: '发送类型',
username: '用户名'
} }
} }

9
dolphinscheduler-ui-next/src/router/modules/security.ts

@ -91,6 +91,15 @@ export default {
title: '令牌管理管理', title: '令牌管理管理',
showSide: true showSide: true
} }
},
{
path: '/security/alarm-instance-manage',
name: 'alarm-instance-manage',
component: components['security-alarm-instance-manage'],
meta: {
title: '告警实例管理',
showSide: true
}
} }
] ]
} }

7
dolphinscheduler-ui-next/src/service/modules/alert-plugin/index.ts

@ -40,13 +40,6 @@ export function createAlertPluginInstance(data: PluginInstanceReq): any {
}) })
} }
export function queryAlertPluginInstanceList(): any {
return axios({
url: '/alert-plugin-instances/list',
method: 'get'
})
}
export function verifyAlertInstanceName(params: InstanceNameReq): any { export function verifyAlertInstanceName(params: InstanceNameReq): any {
return axios({ return axios({
url: '/alert-plugin-instances/verify-name', url: '/alert-plugin-instances/verify-name',

6
dolphinscheduler-ui-next/src/service/modules/alert-plugin/types.ts

@ -31,10 +31,6 @@ interface InstanceNameReq {
alertInstanceName: string alertInstanceName: string
} }
interface IdReq {
id: number
}
interface UpdatePluginInstanceReq { interface UpdatePluginInstanceReq {
alertPluginInstanceId: number alertPluginInstanceId: number
instanceName: string instanceName: string
@ -51,6 +47,8 @@ interface AlertPluginItem {
alertPluginName: string alertPluginName: string
} }
type IdReq = number
export { export {
ListReq, ListReq,
PluginInstanceReq, PluginInstanceReq,

4
dolphinscheduler-ui-next/src/service/modules/ui-plugins/index.ts

@ -16,7 +16,7 @@
*/ */
import { axios } from '@/service/service' import { axios } from '@/service/service'
import { PluginTypeReq, IdReq } from './types' import { PluginTypeReq, IPluginId } from './types'
export function queryUiPluginsByType(params: PluginTypeReq): any { export function queryUiPluginsByType(params: PluginTypeReq): any {
return axios({ return axios({
@ -26,7 +26,7 @@ export function queryUiPluginsByType(params: PluginTypeReq): any {
}) })
} }
export function queryUiPluginDetailById(id: IdReq): any { export function queryUiPluginDetailById(id: IPluginId): any {
return axios({ return axios({
url: `/ui-plugins/${id}`, url: `/ui-plugins/${id}`,
method: 'get' method: 'get'

6
dolphinscheduler-ui-next/src/service/modules/ui-plugins/types.ts

@ -19,8 +19,6 @@ interface PluginTypeReq {
pluginType: 'ALERT' | 'REGISTER' | 'TASK' pluginType: 'ALERT' | 'REGISTER' | 'TASK'
} }
interface IdReq { type IPluginId = number
id: number
}
export { PluginTypeReq, IdReq } export { PluginTypeReq, IPluginId }

196
dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/detail.tsx

@ -0,0 +1,196 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { defineComponent, PropType, toRefs, watch, onMounted, ref } from 'vue'
import { NSelect, NInput } from 'naive-ui'
import Modal from '@/components/modal'
import Form from '@/components/form'
import { useI18n } from 'vue-i18n'
import { useForm } from './use-form'
import { useDetail } from './use-detail'
import getElementByJson from '@/components/form/get-elements-by-json'
import type { IRecord, FormRules, IFormItem } from './types'
const props = {
show: {
type: Boolean as PropType<boolean>,
default: false
},
currentRecord: {
type: Object as PropType<IRecord>,
default: {}
}
}
const DetailModal = defineComponent({
name: 'DetailModal',
props,
emits: ['cancel', 'update'],
setup(props, ctx) {
const { t } = useI18n()
const rules = ref<FormRules>({})
const elements = ref<IFormItem[]>([])
const {
meta,
state,
setDetail,
initForm,
resetForm,
getFormValues,
changePlugin
} = useForm()
const { status, createOrUpdate } = useDetail(getFormValues)
const onCancel = () => {
resetForm()
ctx.emit('cancel')
}
const onSubmit = async () => {
await state.detailFormRef.validate()
const res = await createOrUpdate(props.currentRecord, state.json)
if (res) {
onCancel()
ctx.emit('update')
}
}
const onChangePlugin = changePlugin
watch(
() => props.show,
async () => {
props.show && props.currentRecord && setDetail(props.currentRecord)
}
)
watch(
() => state.json,
() => {
const { rules: fieldsRules, elements: fieldsElements } =
getElementByJson(
state.json,
state.detailForm,
t,
'security.alarm_instance'
)
rules.value = fieldsRules
elements.value = fieldsElements
}
)
onMounted(() => {
initForm()
})
return {
t,
...toRefs(state),
...toRefs(status),
meta,
rules,
elements,
onChangePlugin,
onSubmit,
onCancel
}
},
render(props: { currentRecord: IRecord }) {
const {
show,
t,
meta,
rules,
elements,
detailForm,
uiPlugins,
pluginsLoading,
loading,
saving,
onChangePlugin,
onCancel,
onSubmit
} = this
const { currentRecord } = props
return (
<Modal
show={show}
title={`${t(
currentRecord?.id
? 'security.alarm_instance.edit'
: 'security.alarm_instance.create'
)} ${t('security.alarm_instance.alarm_instance')}`}
onConfirm={onSubmit}
confirmLoading={saving || loading}
onCancel={() => void onCancel()}
>
{{
default: () => (
<Form
ref='detailFormRef'
loading={loading || pluginsLoading}
meta={{
...meta,
rules: {
...meta.rules,
...rules
},
elements: [
{
path: 'instanceName',
label: t('security.alarm_instance.alarm_instance_name'),
widget: (
<NInput
v-model={[detailForm.instanceName, 'value']}
placeholder={t(
'security.alarm_instance.alarm_instance_name_tips'
)}
/>
)
},
{
path: 'pluginDefineId',
label: t('security.alarm_instance.select_plugin'),
widget: (
<NSelect
v-model={[detailForm.pluginDefineId, 'value']}
options={uiPlugins}
disabled={!!currentRecord?.id}
placeholder={t(
'security.alarm_instance.select_plugin_tips'
)}
on-update:value={onChangePlugin}
/>
)
},
...elements
]
}}
layout={{
cols: 24
}}
/>
)
}}
</Modal>
)
}
})
export default DetailModal

32
dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/index.module.scss

@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.conditions {
display: flex;
justify-content: space-between;
align-items: center;
}
.conditions-search-input {
width: 250px;
}
.pagination {
margin-top: 20px;
justify-content: center;
}
.mt-8 {
margin-top: 8px;
}

170
dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/index.tsx

@ -0,0 +1,170 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { defineComponent, onMounted, ref, toRefs } from 'vue'
import {
NButton,
NInput,
NIcon,
NDataTable,
NPagination,
NSpace
} from 'naive-ui'
import Card from '@/components/card'
import DetailModal from './detail'
import { SearchOutlined } from '@vicons/antd'
import { useI18n } from 'vue-i18n'
import { useUserInfo } from './use-userinfo'
import { useColumns } from './use-columns'
import { useTable } from './use-table'
import styles from './index.module.scss'
import type { IRecord } from './types'
const AlarmInstanceManage = defineComponent({
name: 'alarm-instance-manage',
setup() {
const { t } = useI18n()
const showDetailModal = ref(false)
const currentRecord = ref()
const { IS_ADMIN } = useUserInfo()
const { columnsRef } = useColumns(
(record: IRecord, type: 'edit' | 'delete') => {
if (type === 'edit') {
showDetailModal.value = true
currentRecord.value = record
} else {
deleteRecord(record.id)
}
}
)
const { data, changePage, changePageSize, deleteRecord, updateList } =
useTable()
const onCreate = () => {
currentRecord.value = null
showDetailModal.value = true
}
const onCloseModal = () => {
showDetailModal.value = false
currentRecord.value = {}
}
onMounted(() => {
changePage(1)
})
return {
t,
IS_ADMIN,
showDetailModal,
currentRecord: currentRecord,
columnsRef,
...toRefs(data),
changePage,
changePageSize,
onCreate,
onCloseModal,
onUpdatedList: updateList
}
},
render() {
const {
t,
IS_ADMIN,
currentRecord,
showDetailModal,
columnsRef,
list,
page,
pageSize,
itemCount,
loading,
changePage,
changePageSize,
onCreate,
onUpdatedList,
onCloseModal
} = this
return (
<>
<Card title=''>
{{
default: () => (
<div class={styles['conditions']}>
{IS_ADMIN && (
<NButton onClick={onCreate} type='primary'>{`${t(
'security.alarm_instance.create'
)} ${t('security.alarm_instance.alarm_instance')}`}</NButton>
)}
<NSpace
class={styles['conditions-search']}
justify='end'
wrap={false}
>
<div class={styles['conditions-search-input']}>
<NInput
v-model={[this.searchVal, 'value']}
placeholder={`${t(
'security.alarm_instance.search_input_tips'
)}`}
/>
</div>
<NButton type='primary' onClick={onUpdatedList}>
<NIcon>
<SearchOutlined />
</NIcon>
</NButton>
</NSpace>
</div>
)
}}
</Card>
<Card title='' class={styles['mt-8']}>
<NDataTable
columns={columnsRef}
data={list}
loading={loading}
striped
/>
<NPagination
page={page}
page-size={pageSize}
item-count={itemCount}
show-quick-jumper
class={styles['pagination']}
on-update:page={changePage}
on-update:page-size={changePageSize}
/>
</Card>
{IS_ADMIN && (
<DetailModal
show={showDetailModal}
currentRecord={currentRecord}
onCancel={onCloseModal}
onUpdate={onUpdatedList}
/>
)}
</>
)
}
})
export default AlarmInstanceManage

51
dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/types.ts

@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { IPluginId } from '@/service/modules/ui-plugins/types'
import type { TableColumns } from 'naive-ui/es/data-table/src/interface'
import type { IMeta, IJsonItem, IFormItem } from '@/components/form/types'
import type { FormRules } from 'naive-ui'
interface IRecord {
alertPluginName?: string
createTime?: string
id: number
instanceName: string
pluginDefineId: number
pluginInstanceParams?: string
updateTime?: string
}
interface IPlugin {
id: number
pluginName: string
pluginParams?: string
pluginType?: string
createTime?: string
updateTime?: string
}
export {
IPluginId,
IRecord,
IPlugin,
IJsonItem,
IMeta,
IFormItem,
TableColumns,
FormRules
}

100
dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/use-columns.ts

@ -0,0 +1,100 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { h } from 'vue'
import { useI18n } from 'vue-i18n'
import { NButton, NIcon, NPopconfirm, NSpace } from 'naive-ui'
import { EditOutlined, DeleteOutlined } from '@vicons/antd'
import { TableColumns } from './types'
export function useColumns(onCallback: Function) {
const { t } = useI18n()
const columnsRef: TableColumns = [
{
title: t('security.alarm_instance.serial_number'),
key: 'index',
render: (rowData, rowIndex) => rowIndex + 1
},
{
title: t('security.alarm_instance.alarm_instance_name'),
key: 'instanceName'
},
{
title: t('security.alarm_instance.alarm_plugin_name'),
key: 'alertPluginName'
},
{
title: t('security.alarm_instance.create_time'),
key: 'createTime'
},
{
title: t('security.alarm_instance.update_time'),
key: 'updateTime'
},
{
title: t('security.alarm_instance.operation'),
key: 'operation',
width: 150,
render: (rowData, rowIndex) => {
return h(NSpace, null, {
default: () => [
h(
NButton,
{
circle: true,
type: 'info',
onClick: () => void onCallback(rowData, 'edit')
},
{
default: () =>
h(NIcon, null, { default: () => h(EditOutlined) })
}
),
h(
NPopconfirm,
{
onPositiveClick: () => void onCallback(rowData, 'delete'),
negativeText: t('security.alarm_instance.cancel'),
positiveText: t('security.alarm_instance.confirm')
},
{
trigger: () =>
h(
NButton,
{
circle: true,
type: 'error'
},
{
default: () =>
h(NIcon, null, { default: () => h(DeleteOutlined) })
}
),
default: () => t('security.alarm_instance.delete')
}
)
]
})
}
}
]
return {
columnsRef
}
}

78
dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/use-detail.ts

@ -0,0 +1,78 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { reactive } from 'vue'
import {
createAlertPluginInstance,
updateAlertPluginInstance,
verifyAlertInstanceName
} from '@/service/modules/alert-plugin'
import type { IJsonItem, IRecord } from './types'
export function useDetail(getFormValues: Function) {
const status = reactive({
saving: false,
loading: false
})
const formatParams = (
json?: IJsonItem[],
values: { [field: string]: any } = {}
): string => {
json?.forEach((item) => {
item.value = values[item.field]
})
return JSON.stringify(json)
}
const createOrUpdate = async (currentRecord: IRecord, json?: IJsonItem[]) => {
const values = getFormValues()
if (status.saving) return false
status.saving = true
try {
if (currentRecord?.instanceName !== values.instanceName) {
await verifyAlertInstanceName({
alertInstanceName: values.instanceName
})
}
currentRecord?.id
? await updateAlertPluginInstance(
{
alertPluginInstanceId: values.pluginDefineId,
instanceName: values.instanceName,
pluginInstanceParams: formatParams(json, values)
},
currentRecord.id
)
: await createAlertPluginInstance({
instanceName: values.instanceName,
pluginDefineId: values.pluginDefineId,
pluginInstanceParams: formatParams(json, values)
})
status.saving = false
return true
} catch (e) {
window.$message.error((e as Error).message)
status.saving = false
return false
}
}
return { status, createOrUpdate }
}

131
dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/use-form.ts

@ -0,0 +1,131 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { reactive, ref, Ref } from 'vue'
import { useI18n } from 'vue-i18n'
import {
queryUiPluginsByType,
queryUiPluginDetailById
} from '@/service/modules/ui-plugins'
import type {
IPluginId,
IPlugin,
FormRules,
IMeta,
IJsonItem,
IRecord
} from './types'
export function useForm() {
const { t } = useI18n()
const initialValues = {
instanceName: '',
pluginDefineId: null
}
const state = reactive({
detailFormRef: ref(),
detailForm: { ...initialValues },
uiPlugins: [],
pluginsLoading: false,
json: []
} as { detailFormRef: Ref; json: IJsonItem[]; detailForm: { instanceName: string; pluginDefineId: number | null }; pluginsLoading: boolean; uiPlugins: [] })
const meta = {
model: state.detailForm,
requireMarkPlacement: 'left',
labelPlacement: 'left',
labelWidth: 180,
rules: {
instanceName: {
trigger: 'input',
required: true,
message: t('security.alarm_instance.alarm_instance_name_tips')
},
pluginDefineId: {
trigger: ['blur', 'change'],
required: true,
validator(validte, value) {
if (!value && value !== 0) {
return new Error(t('security.alarm_instance.select_plugin_tips'))
}
}
}
} as FormRules
} as IMeta
const getUiPluginsByType = async () => {
if (state.pluginsLoading) return
state.pluginsLoading = true
try {
const plugins = await queryUiPluginsByType({ pluginType: 'ALERT' })
state.uiPlugins = plugins.map((plugin: IPlugin) => ({
label: plugin.pluginName,
value: plugin.id
}))
state.pluginsLoading = false
} catch (err) {
state.uiPlugins = []
state.pluginsLoading = false
}
}
const changePlugin = async (pluginId: IPluginId) => {
if (state.pluginsLoading) return
state.pluginsLoading = true
state.detailForm.pluginDefineId = pluginId
try {
const { pluginParams } = await queryUiPluginDetailById(pluginId)
if (pluginParams) {
state.json = JSON.parse(pluginParams)
}
state.pluginsLoading = false
} catch (e) {
window.$message.error((e as Error).message)
state.pluginsLoading = false
}
}
const initForm = () => {
getUiPluginsByType()
}
const resetForm = () => {
state.detailFormRef.setValues({ ...initialValues })
state.json = []
}
const getFormValues = () => state.detailForm
const setDetail = (record: IRecord) => {
state.detailForm.instanceName = record.instanceName
state.detailForm.pluginDefineId = record.pluginDefineId
if (record.pluginInstanceParams)
state.json = JSON.parse(record.pluginInstanceParams)
}
return {
meta,
state,
setDetail,
initForm,
resetForm,
getFormValues,
changePlugin
}
}

95
dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/use-table.ts

@ -0,0 +1,95 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { reactive } from 'vue'
import {
queryAlertPluginInstanceListPaging,
deleteAlertPluginInstance
} from '@/service/modules/alert-plugin'
import { format } from 'date-fns'
import type { IRecord } from './types'
export function useTable() {
const data = reactive({
page: 1,
pageSize: 10,
itemCount: 0,
searchVal: '',
list: [],
loading: false
})
const getList = async () => {
if (data.loading) return
data.loading = true
try {
const { totalList, total } = await queryAlertPluginInstanceListPaging({
pageNo: data.page,
pageSize: data.pageSize,
searchVal: data.searchVal
})
data.loading = false
if (!totalList) throw Error()
data.list = totalList.map((record: IRecord) => {
record.createTime = record.createTime
? format(new Date(record.createTime), 'yyyy-MM-dd HH:mm:ss')
: ''
record.updateTime = record.updateTime
? format(new Date(record.updateTime), 'yyyy-MM-dd HH:mm:ss')
: ''
return record
})
data.itemCount = total
} catch (e) {
if ((e as Error).message) window.$message.error((e as Error).message)
data.loading = false
data.list = []
data.itemCount = 0
}
}
const updateList = () => {
if (data.list.length === 1 && data.page > 1) {
--data.page
}
getList()
}
const deleteRecord = async (id: number) => {
try {
const res = await deleteAlertPluginInstance(id)
updateList()
} catch (e) {
window.$message.error((e as Error).message)
}
}
const changePage = (page: number) => {
data.page = page
getList()
}
const changePageSize = (pageSize: number) => {
data.page = 1
data.pageSize = pageSize
getList()
}
return { data, changePage, changePageSize, deleteRecord, updateList }
}

28
dolphinscheduler-ui-next/src/views/security/alarm-instance-manage/use-userinfo.ts

@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { useUserStore } from '@/store/user/user'
import type { UserInfoRes } from '@/service/modules/users/types'
export function useUserInfo() {
const userStore = useUserStore()
const userInfo = userStore.getUserInfo as UserInfoRes
const IS_ADMIN = userInfo.userType === 'ADMIN_USER'
return { IS_ADMIN }
}
Loading…
Cancel
Save