Browse Source

[Feature][UI Next] Add security environment manage. (#8057)

3.0.0/version-upgrade
songjianet 3 years ago committed by GitHub
parent
commit
f8a719c6ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts
  2. 21
      dolphinscheduler-ui-next/src/locales/modules/en_US.ts
  3. 23
      dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts
  4. 8
      dolphinscheduler-ui-next/src/router/modules/security.ts
  5. 25
      dolphinscheduler-ui-next/src/service/modules/environment/types.ts
  6. 187
      dolphinscheduler-ui-next/src/views/security/environment-manage/components/environment-modal.tsx
  7. 141
      dolphinscheduler-ui-next/src/views/security/environment-manage/components/use-modal.ts
  8. 43
      dolphinscheduler-ui-next/src/views/security/environment-manage/index.module.scss
  9. 158
      dolphinscheduler-ui-next/src/views/security/environment-manage/index.tsx
  10. 204
      dolphinscheduler-ui-next/src/views/security/environment-manage/use-table.ts

4
dolphinscheduler-ui-next/src/layouts/content/use-dataList.ts

@ -230,8 +230,8 @@ export function useDataList() {
icon: renderIcon(SlackOutlined)
},
{
label: t('menu.environmental_manage'),
key: 'environmental-manage',
label: t('menu.environment_manage'),
key: 'environment-manage',
icon: renderIcon(EnvironmentOutlined)
},
{

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

@ -70,7 +70,7 @@ const menu = {
alarm_instance_manage: 'Alarm Instance Manage',
worker_group_manage: 'Worker Group Manage',
yarn_queue_manage: 'Yarn Queue Manage',
environmental_manage: 'Environmental Manage',
environment_manage: 'Environment Manage',
token_manage: 'Token Manage'
}
@ -246,6 +246,25 @@ const security = {
edit: 'Edit',
queue_name_tips: 'Please enter your queue name',
queue_value_tips: 'Please enter your queue value'
},
environment: {
create_environment: 'Create Environment',
edit_environment: 'Edit Environment',
search_tips: 'Please enter keywords',
edit: 'Edit',
delete: 'Delete',
environment_name: 'Environment Name',
environment_config: 'Environment Config',
environment_desc: 'Environment Desc',
worker_groups: 'Worker Groups',
create_time: 'Create Time',
update_time: 'Update Time',
operation: 'Operation',
delete_confirm: 'Delete?',
environment_name_tips: 'Please enter your environment name',
environment_config_tips: 'Please enter your environment config',
environment_description_tips: 'Please enter your environment description',
worker_group_tips: 'Please select worker group'
}
}

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

@ -70,7 +70,7 @@ const menu = {
alarm_instance_manage: '告警实例管理',
worker_group_manage: 'Worker分组管理',
yarn_queue_manage: 'Yarn队列管理',
environmental_manage: '环境管理',
environment_manage: '环境管理',
token_manage: '令牌管理'
}
@ -243,8 +243,27 @@ const security = {
update_time: '更新时间',
operation: '操作',
edit: '编辑',
queue_name_tips: '请输入队列名',
queue_name_tips: '请输入队列名',
queue_value_tips: '请输入队列值'
},
environment: {
create_environment: '创建环境',
edit_environment: '编辑环境',
search_tips: '请输入关键词',
edit: '编辑',
delete: '删除',
environment_name: '环境名称',
environment_config: '环境配置',
environment_desc: '环境描述',
worker_groups: 'Worker分组',
create_time: '创建时间',
update_time: '更新时间',
operation: '操作',
delete_confirm: '确定删除吗?',
environment_name_tips: '请输入环境名',
environment_config_tips: '请输入环境配置',
environment_description_tips: '请输入环境描述',
worker_group_tips: '请选择Worker分组'
}
}

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

@ -52,6 +52,14 @@ export default {
meta: {
title: 'Yarn队列管理'
}
},
{
path: '/security/environment-manage',
name: 'environment-manage',
component: components['environment-manage'],
meta: {
title: '环境管理'
}
}
]
}

25
dolphinscheduler-ui-next/src/service/modules/environment/types.ts

@ -40,10 +40,33 @@ interface CodeReq {
code: number
}
interface EnvironmentItem {
id: number
code: any
name: string
config: string
description: string
workerGroups: string[]
operator: number
createTime: string
updateTime: string
}
interface EnvironmentRes {
totalList: EnvironmentItem[]
total: number
totalPage: number
pageSize: number
currentPage: number
start: number
}
export {
EnvironmentReq,
EnvironmentCodeReq,
EnvironmentNameReq,
ListReq,
CodeReq
CodeReq,
EnvironmentItem,
EnvironmentRes
}

187
dolphinscheduler-ui-next/src/views/security/environment-manage/components/environment-modal.tsx

@ -0,0 +1,187 @@
/*
* 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 } from 'vue'
import Modal from '@/components/modal'
import { NForm, NFormItem, NInput, NSelect } from 'naive-ui'
import { useModal } from './use-modal'
import { useI18n } from 'vue-i18n'
const envConfigPlaceholder =
'export HADOOP_HOME=/opt/hadoop-2.6.5\n' +
'export HADOOP_CONF_DIR=/etc/hadoop/conf\n' +
'export SPARK_HOME=/opt/soft/spark\n' +
'export PYTHON_HOME=/opt/soft/python\n' +
'export JAVA_HOME=/opt/java/jdk1.8.0_181-amd64\n' +
'export HIVE_HOME=/opt/soft/hive\n' +
'export FLINK_HOME=/opt/soft/flink\n' +
'export DATAX_HOME=/opt/soft/datax\n' +
'export YARN_CONF_DIR=/etc/hadoop/conf\n' +
'export PATH=$HADOOP_HOME/bin:$SPARK_HOME/bin:$PYTHON_HOME/bin:$JAVA_HOME/bin:$HIVE_HOME/bin:$FLINK_HOME/bin:$DATAX_HOME/bin:$PATH\n' +
'export HADOOP_CLASSPATH=`hadoop classpath`\n'
const EnvironmentModal = defineComponent({
name: 'YarnQueueModal',
props: {
showModalRef: {
type: Boolean as PropType<boolean>,
default: false
},
statusRef: {
type: Number as PropType<number>,
default: 0
},
row: {
type: Object as PropType<any>,
default: {}
}
},
emits: ['cancelModal', 'confirmModal'],
setup(props, ctx) {
const { variables, handleValidate, getListData } = useModal(props, ctx)
const { t } = useI18n()
const cancelModal = () => {
if (props.statusRef === 0) {
variables.model.name = ''
variables.model.config = ''
variables.model.description = ''
variables.model.workerGroups = []
}
ctx.emit('cancelModal', props.showModalRef)
}
const confirmModal = () => {
handleValidate(props.statusRef)
}
watch(
() => props.showModalRef,
() => {
props.showModalRef && getListData()
}
)
watch(
() => props.statusRef,
() => {
if (props.statusRef === 0) {
variables.model.name = ''
variables.model.config = ''
variables.model.description = ''
variables.model.workerGroups = []
} else {
variables.model.code = props.row.code
variables.model.name = props.row.name
variables.model.config = props.row.config
variables.model.description = props.row.description
variables.model.workerGroups = props.row.workerGroups
}
}
)
watch(
() => props.row,
() => {
variables.model.code = props.row.code
variables.model.name = props.row.name
variables.model.config = props.row.config
variables.model.description = props.row.description
variables.model.workerGroups = props.row.workerGroups
}
)
return { t, ...toRefs(variables), cancelModal, confirmModal }
},
render() {
const { t } = this
return (
<div>
<Modal
title={
this.statusRef === 0
? t('security.environment.create_environment')
: t('security.environment.edit_environment')
}
show={this.showModalRef}
onCancel={this.cancelModal}
onConfirm={this.confirmModal}
confirmDisabled={
!this.model.name || !this.model.config || !this.model.description
}
>
{{
default: () => (
<NForm
model={this.model}
rules={this.rules}
ref='environmentFormRef'
>
<NFormItem
label={t('security.environment.environment_name')}
path='name'
>
<NInput
placeholder={t(
'security.environment.environment_name_tips'
)}
v-model={[this.model.name, 'value']}
/>
</NFormItem>
<NFormItem
label={t('security.environment.environment_config')}
path='config'
>
<NInput
placeholder={envConfigPlaceholder}
type='textarea'
autosize={{ minRows: 16 }}
v-model={[this.model.config, 'value']}
/>
</NFormItem>
<NFormItem
label={t('security.environment.environment_desc')}
path='description'
>
<NInput
placeholder={t(
'security.environment.environment_description_tips'
)}
v-model={[this.model.description, 'value']}
/>
</NFormItem>
<NFormItem
label={t('security.environment.worker_groups')}
path='workerGroups'
>
<NSelect
multiple
placeholder={t('security.environment.worker_group_tips')}
options={this.model.generalOptions}
v-model={[this.model.workerGroups, 'value']}
/>
</NFormItem>
</NForm>
)
}}
</Modal>
</div>
)
}
})
export default EnvironmentModal

141
dolphinscheduler-ui-next/src/views/security/environment-manage/components/use-modal.ts

@ -0,0 +1,141 @@
/*
* 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, SetupContext } from 'vue'
import { useI18n } from 'vue-i18n'
import { useAsyncState } from '@vueuse/core'
import { queryAllWorkerGroups } from '@/service/modules/worker-groups'
import {
verifyEnvironment,
createEnvironment,
updateEnvironment
} from '@/service/modules/environment'
export function useModal(
props: any,
ctx: SetupContext<('cancelModal' | 'confirmModal')[]>
) {
const { t } = useI18n()
const variables = reactive({
environmentFormRef: ref(),
model: {
code: ref<number>(-1),
name: ref(''),
config: ref(''),
description: ref(''),
workerGroups: ref<Array<string>>([]),
generalOptions: []
},
rules: {
name: {
required: true,
trigger: ['input', 'blur'],
validator() {
if (variables.model.name === '') {
return new Error(t('security.environment.environment_name_tips'))
}
}
},
config: {
required: true,
trigger: ['input', 'blur'],
validator() {
if (variables.model.config === '') {
return new Error(t('security.environment.environment_config_tips'))
}
}
},
description: {
required: true,
trigger: ['input', 'blur'],
validator() {
if (variables.model.description === '') {
return new Error(
t('security.environment.environment_description_tips')
)
}
}
}
}
})
const getListData = () => {
const { state } = useAsyncState(
queryAllWorkerGroups().then((res: any) => {
variables.model.generalOptions = res.map((item: any) => {
return {
label: item,
value: item
}
})
}),
{}
)
return state
}
const handleValidate = (statusRef: number) => {
variables.environmentFormRef.validate((errors: any) => {
if (!errors) {
statusRef === 0 ? submitEnvironmentModal() : updateEnvironmentModal()
} else {
return
}
})
}
const submitEnvironmentModal = () => {
verifyEnvironment({ environmentName: variables.model.name }).then(() => {
const data = {
name: variables.model.name,
config: variables.model.config,
description: variables.model.description,
workerGroups: JSON.stringify(variables.model.workerGroups)
}
createEnvironment(data).then(() => {
variables.model.name = ''
variables.model.config = ''
variables.model.description = ''
variables.model.workerGroups = []
ctx.emit('confirmModal', props.showModalRef)
})
})
}
const updateEnvironmentModal = () => {
const data = {
code: variables.model.code,
name: variables.model.name,
config: variables.model.config,
description: variables.model.description,
workerGroups: JSON.stringify(variables.model.workerGroups)
}
updateEnvironment(data).then(() => {
ctx.emit('confirmModal', props.showModalRef)
})
}
return {
variables,
handleValidate,
getListData
}
}

43
dolphinscheduler-ui-next/src/views/security/environment-manage/index.module.scss

@ -0,0 +1,43 @@
/*
* 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.
*/
.search-card {
display: flex;
justify-content: space-between;
align-items: center;
.box {
display: flex;
justify-content: flex-end;
align-items: center;
width: 300px;
button {
margin-left: 10px;
}
}
}
.table-card {
margin-top: 8px;
.pagination {
margin-top: 20px;
display: flex;
justify-content: center;
}
}

158
dolphinscheduler-ui-next/src/views/security/environment-manage/index.tsx

@ -0,0 +1,158 @@
/*
* 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, toRefs, watch } from 'vue'
import {
NButton,
NCard,
NDataTable,
NIcon,
NInput,
NPagination
} from 'naive-ui'
import { SearchOutlined } from '@vicons/antd'
import { useI18n } from 'vue-i18n'
import { useTable } from './use-table'
import Card from '@/components/card'
import EnvironmentModal from './components/environment-modal'
import styles from './index.module.scss'
const environmentManage = defineComponent({
name: 'environment-manage',
setup() {
const { t } = useI18n()
const { variables, getTableData, createColumns } = useTable()
const requestData = () => {
getTableData({
pageSize: variables.pageSize,
pageNo: variables.page,
searchVal: variables.searchVal
})
}
const onUpdatePageSize = () => {
variables.page = 1
requestData()
}
const onSearch = () => {
variables.page = 1
requestData()
}
const handleModalChange = () => {
variables.showModalRef = true
variables.statusRef = 0
}
const onCancelModal = () => {
variables.showModalRef = false
}
const onConfirmModal = () => {
variables.showModalRef = false
requestData()
}
onMounted(() => {
createColumns(variables)
requestData()
})
watch(useI18n().locale, () => {
createColumns(variables)
})
return {
t,
...toRefs(variables),
requestData,
onCancelModal,
onConfirmModal,
onUpdatePageSize,
handleModalChange,
onSearch
}
},
render() {
const {
t,
requestData,
onUpdatePageSize,
onCancelModal,
onConfirmModal,
handleModalChange,
onSearch
} = this
return (
<div>
<NCard>
<div class={styles['search-card']}>
<div>
<NButton size='small' type='primary' onClick={handleModalChange}>
{t('security.environment.create_environment')}
</NButton>
</div>
<div class={styles.box}>
<NInput
size='small'
clearable
v-model={[this.searchVal, 'value']}
placeholder={t('security.environment.search_tips')}
/>
<NButton size='small' type='primary' onClick={onSearch}>
{{
icon: () => (
<NIcon>
<SearchOutlined />
</NIcon>
)
}}
</NButton>
</div>
</div>
</NCard>
<Card class={styles['table-card']}>
<NDataTable columns={this.columns} data={this.tableData} />
<div class={styles.pagination}>
<NPagination
v-model:page={this.page}
v-model:page-size={this.pageSize}
page-count={this.totalPage}
show-size-picker
page-sizes={[10, 30, 50]}
show-quick-jumper
onUpdatePage={requestData}
onUpdatePageSize={onUpdatePageSize}
/>
</div>
</Card>
<EnvironmentModal
showModalRef={this.showModalRef}
statusRef={this.statusRef}
row={this.row}
onCancelModal={onCancelModal}
onConfirmModal={onConfirmModal}
/>
</div>
)
}
})
export default environmentManage

204
dolphinscheduler-ui-next/src/views/security/environment-manage/use-table.ts

@ -0,0 +1,204 @@
/*
* 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 { useAsyncState } from '@vueuse/core'
import { reactive, h, ref } from 'vue'
import { format } from 'date-fns'
import { NButton, NPopconfirm, NSpace, NTooltip, NTag } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import {
queryEnvironmentListPaging,
deleteEnvironmentByCode
} from '@/service/modules/environment'
import { DeleteOutlined, EditOutlined } from '@vicons/antd'
import type {
EnvironmentRes,
EnvironmentItem
} from '@/service/modules/environment/types'
export function useTable() {
const { t } = useI18n()
const handleEdit = (row: any) => {
variables.showModalRef = true
variables.statusRef = 1
variables.row = row
}
const createColumns = (variables: any) => {
variables.columns = [
{
title: '#',
key: 'index'
},
{
title: t('security.environment.environment_name'),
key: 'name'
},
{
title: t('security.environment.environment_config'),
key: 'config'
},
{
title: t('security.environment.environment_desc'),
key: 'description'
},
{
title: t('security.environment.worker_groups'),
key: 'workerGroups',
render: (row: EnvironmentItem) =>
h(NSpace, null, {
default: () =>
row.workerGroups.map((item: any) =>
h(
NTag,
{ type: 'success', size: 'small' },
{ default: () => item }
)
)
})
},
{
title: t('security.environment.create_time'),
key: 'createTime'
},
{
title: t('security.environment.update_time'),
key: 'updateTime'
},
{
title: t('security.environment.operation'),
key: 'operation',
render(row: any) {
return h(NSpace, null, {
default: () => [
h(
NTooltip,
{},
{
trigger: () =>
h(
NButton,
{
circle: true,
type: 'info',
size: 'small',
onClick: () => {
handleEdit(row)
}
},
{
icon: () => h(EditOutlined)
}
),
default: () => t('security.environment.edit')
}
),
h(
NPopconfirm,
{
onPositiveClick: () => {
handleDelete(row)
}
},
{
trigger: () =>
h(
NTooltip,
{},
{
trigger: () =>
h(
NButton,
{
circle: true,
type: 'error',
size: 'small'
},
{
icon: () => h(DeleteOutlined)
}
),
default: () => t('security.environment.delete')
}
),
default: () => t('security.environment.delete_confirm')
}
)
]
})
}
}
]
}
const variables = reactive({
columns: [],
tableData: [],
page: ref(1),
pageSize: ref(10),
searchVal: ref(null),
totalPage: ref(1),
showModalRef: ref(false),
statusRef: ref(0),
row: {}
})
const handleDelete = (row: any) => {
deleteEnvironmentByCode({ environmentCode: row.code }).then(() => {
getTableData({
pageSize: variables.pageSize,
pageNo:
variables.tableData.length === 1 && variables.page > 1
? variables.page - 1
: variables.page,
searchVal: variables.searchVal
})
})
}
const getTableData = (params: any) => {
const { state } = useAsyncState(
queryEnvironmentListPaging({ ...params }).then((res: EnvironmentRes) => {
variables.tableData = res.totalList.map((item, index) => {
item.createTime = format(
new Date(item.createTime),
'yyyy-MM-dd HH:mm:ss'
)
item.updateTime = format(
new Date(item.updateTime),
'yyyy-MM-dd HH:mm:ss'
)
return {
index: index + 1,
...item
}
}) as any
variables.totalPage = res.totalPage
}),
{}
)
return state
}
return {
variables,
getTableData,
createColumns
}
}
Loading…
Cancel
Save