Browse Source

[Refactor][UI Next][V1.0.0-Alpha] Refactor the list of projects under the project module (#8738)

3.0.0/version-upgrade
labbomb 2 years ago committed by GitHub
parent
commit
a6bfb5847e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 89
      dolphinscheduler-ui-next/src/views/projects/list/components/project-modal.tsx
  2. 121
      dolphinscheduler-ui-next/src/views/projects/list/components/table-action.tsx
  3. 40
      dolphinscheduler-ui-next/src/views/projects/list/components/use-form.ts
  4. 176
      dolphinscheduler-ui-next/src/views/projects/list/index.tsx
  5. 201
      dolphinscheduler-ui-next/src/views/projects/list/use-table.ts

89
dolphinscheduler-ui-next/src/views/projects/list/components/project-modal.tsx

@ -15,84 +15,95 @@
* limitations under the License. * limitations under the License.
*/ */
import { defineComponent, PropType, toRefs, onMounted } from 'vue' import { defineComponent, PropType, toRefs, onMounted, watch } from 'vue'
import { NForm, NFormItem, NInput } from 'naive-ui' import { NForm, NFormItem, NInput } from 'naive-ui'
import { useForm } from '../use-form' import { useForm } from './use-form'
import Modal from '@/components/modal' import Modal from '@/components/modal'
import { createProject, updateProject } from '@/service/modules/projects'
const props = { const props = {
show: { showModalRef: {
type: Boolean as PropType<boolean>, type: Boolean as PropType<boolean>,
default: false default: false
}, },
data: { statusRef: {
type: Object as PropType<any>
},
status: {
type: Number as PropType<number>, type: Number as PropType<number>,
default: 0 default: 0
},
row: {
type: Object as PropType<any>,
default: {}
} }
} }
const ProjectModal = defineComponent({ const ProjectModal = defineComponent({
name: 'ProjectModal', name: 'ProjectModal',
props, props,
emits: ['confirm', 'cancel'], emits: ['cancelModal', 'confirmModal'],
setup(props, { emit }) { setup(props, ctx) {
const { state, t } = useForm() const { variables, t, handleValidate } = useForm(props, ctx)
onMounted(() => { const cancelModal = () => {
if (props.status === 1) { if (props.statusRef === 0) {
state.projectForm.projectName = props.data.projectName variables.model.projectName = ''
state.projectForm.description = props.data.description variables.model.description = ''
} }
}) ctx.emit('cancelModal', props.showModalRef)
const onConfirm = () => {
;(props.status === 1
? updateProject(state.projectForm, props.data.code)
: createProject(state.projectForm)
).then(() => {
emit('confirm')
})
} }
const onCancel = () => { const confirmModal = () => {
state.projectForm.projectName = '' handleValidate(props.statusRef)
state.projectForm.description = ''
state.projectForm.userName = ''
emit('cancel')
} }
return { ...toRefs(state), t, onConfirm, onCancel } watch(
() => props.statusRef,
() => {
if (props.statusRef === 0) {
variables.model.projectName = ''
variables.model.description = ''
} else {
variables.model.projectName = props.row.name
variables.model.description = props.row.description
}
}
)
watch(
() => props.row,
() => {
variables.model.projectName = props.row.name
variables.model.description = props.row.description
}
)
return { ...toRefs(variables), t, cancelModal, confirmModal }
}, },
render() { render() {
const { t, onConfirm, onCancel, show, status } = this const { t } = this
return ( return (
<Modal <Modal
title={ title={
status === 0 this.statusRef === 0
? t('project.list.create_project') ? t('project.list.create_project')
: t('project.list.edit_project') : t('project.list.edit_project')
} }
show={show} show={this.showModalRef}
onConfirm={onConfirm} onConfirm={this.confirmModal}
onCancel={onCancel} onCancel={this.cancelModal}
confirmDisabled={ confirmDisabled={
!this.projectForm.projectName || !this.projectForm.userName !this.model.projectName || !this.model.userName
} }
> >
<NForm rules={this.rules} ref='projectFormRef'> <NForm rules={this.rules} ref='projectFormRef'>
<NFormItem label={t('project.list.project_name')} path='projectName'> <NFormItem label={t('project.list.project_name')} path='projectName'>
<NInput <NInput
v-model={[this.projectForm.projectName, 'value']} v-model={[this.model.projectName, 'value']}
placeholder={t('project.list.project_tips')} placeholder={t('project.list.project_tips')}
/> />
</NFormItem> </NFormItem>
<NFormItem label={t('project.list.owned_users')} path='userName'> <NFormItem label={t('project.list.owned_users')} path='userName'>
<NInput <NInput
v-model={[this.projectForm.userName, 'value']} disabled={this.statusRef === 0}
v-model={[this.model.userName, 'value']}
placeholder={t('project.list.username_tips')} placeholder={t('project.list.username_tips')}
/> />
</NFormItem> </NFormItem>
@ -101,7 +112,7 @@ const ProjectModal = defineComponent({
path='description' path='description'
> >
<NInput <NInput
v-model={[this.projectForm.description, 'value']} v-model={[this.model.description, 'value']}
type='textarea' type='textarea'
placeholder={t('project.list.description_tips')} placeholder={t('project.list.description_tips')}
/> />

121
dolphinscheduler-ui-next/src/views/projects/list/components/table-action.tsx

@ -1,121 +0,0 @@
/*
* 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 } from 'vue'
import { useI18n } from 'vue-i18n'
import { NSpace, NTooltip, NButton, NIcon, NPopconfirm } from 'naive-ui'
import { DeleteOutlined, EditOutlined, InfoCircleFilled } from '@vicons/antd'
import { deleteProject } from '@/service/modules/projects'
import type { ProjectList } from '@/service/modules/projects/types'
interface ProjectRow extends ProjectList {
index: number
}
const props = {
row: {
type: Object as PropType<ProjectRow>,
default: {}
}
}
const TableAction = defineComponent({
name: 'TableAction',
props,
emits: ['resetTableData', 'updateProjectItem'],
setup(props, { emit }) {
const { t } = useI18n()
const handleEditProject = (
code: number,
projectName: string,
description: string
) => {
emit('updateProjectItem', code, projectName, description)
}
const handleDeleteProject = (code: number) => {
deleteProject(code).then(() => {
emit('resetTableData')
})
}
return { t, handleEditProject, handleDeleteProject }
},
render() {
const { t, handleEditProject, handleDeleteProject } = this
return (
<NSpace>
<NTooltip trigger={'hover'}>
{{
default: () => t('project.list.edit'),
trigger: () => (
<NButton
size='small'
type='info'
tag='div'
onClick={() =>
handleEditProject(
this.row.code,
this.row.name,
this.row.description
)
}
circle
>
<NIcon>
<EditOutlined />
</NIcon>
</NButton>
)
}}
</NTooltip>
<NTooltip trigger={'hover'}>
{{
default: () => t('project.list.delete'),
trigger: () => (
<NButton size='small' type='error' circle>
<NPopconfirm
positive-text={t('project.list.confirm')}
negative-text={t('project.list.cancel')}
onPositiveClick={() => handleDeleteProject(this.row.code)}
>
{{
default: () => t('project.list.delete_confirm'),
icon: () => (
<NIcon>
<InfoCircleFilled />
</NIcon>
),
trigger: () => (
<NIcon>
<DeleteOutlined />
</NIcon>
)
}}
</NPopconfirm>
</NButton>
)
}}
</NTooltip>
</NSpace>
)
}
})
export default TableAction

40
dolphinscheduler-ui-next/src/views/projects/list/use-form.ts → dolphinscheduler-ui-next/src/views/projects/list/components/use-form.ts

@ -16,18 +16,22 @@
*/ */
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { reactive, ref } from 'vue' import { reactive, ref, SetupContext } from 'vue'
import { useUserStore } from '@/store/user/user' import { useUserStore } from '@/store/user/user'
import type { FormRules } from 'naive-ui' import type { FormRules } from 'naive-ui'
import type { UserInfoRes } from '@/service/modules/users/types' import type { UserInfoRes } from '@/service/modules/users/types'
import { createProject, updateProject } from '@/service/modules/projects'
export function useForm() { export function useForm(
props: any,
ctx: SetupContext<('cancelModal' | 'confirmModal')[]>
) {
const { t } = useI18n() const { t } = useI18n()
const userStore = useUserStore() const userStore = useUserStore()
const state = reactive({ const variables = reactive({
projectFormRef: ref(), projectFormRef: ref(),
projectForm: { model: {
projectName: '', projectName: '',
description: '', description: '',
userName: (userStore.getUserInfo as UserInfoRes).userName userName: (userStore.getUserInfo as UserInfoRes).userName
@ -37,7 +41,7 @@ export function useForm() {
required: true, required: true,
trigger: ['input', 'blur'], trigger: ['input', 'blur'],
validator() { validator() {
if (state.projectForm.projectName === '') { if (variables.model.projectName === '') {
return new Error(t('project.list.project_tips')) return new Error(t('project.list.project_tips'))
} }
} }
@ -46,7 +50,7 @@ export function useForm() {
required: true, required: true,
trigger: ['input', 'blur'], trigger: ['input', 'blur'],
validator() { validator() {
if (state.projectForm.userName === '') { if (variables.model.userName === '') {
return new Error(t('project.list.username_tips')) return new Error(t('project.list.username_tips'))
} }
} }
@ -54,5 +58,27 @@ export function useForm() {
} as FormRules } as FormRules
}) })
return { state, t } const handleValidate = (statusRef: number) => {
variables.projectFormRef.validate((errors: any) => {
if (!errors) {
statusRef === 0 ? submitProjectModal() : updateProjectModal()
} else {
return
}
})
}
const submitProjectModal = () => {
createProject(variables.model).then(() => {
ctx.emit('confirmModal', props.showModalRef)
})
}
const updateProjectModal = () => {
updateProject(variables.model, props.row.code).then(() => {
ctx.emit('confirmModal', props.showModalRef)
})
}
return { variables, t, handleValidate }
} }

176
dolphinscheduler-ui-next/src/views/projects/list/index.tsx

@ -15,34 +15,21 @@
* limitations under the License. * limitations under the License.
*/ */
import { defineComponent, onMounted, ref, toRefs, reactive } from 'vue'
import { import Card from '@/components/card'
NCard,
NButton,
NInput,
NIcon,
NDataTable,
NPagination
} from 'naive-ui'
import { SearchOutlined } from '@vicons/antd' import { SearchOutlined } from '@vicons/antd'
import { NButton, NCard, NDataTable, NIcon, NInput, NPagination, NSpace } from 'naive-ui'
import { defineComponent, onMounted, ref, toRefs, reactive, watch } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { useTable } from './use-table'
import styles from './index.module.scss'
import Card from '@/components/card'
import ProjectModal from './components/project-modal' import ProjectModal from './components/project-modal'
import styles from './index.module.scss'
import { useTable } from './use-table'
const list = defineComponent({ const list = defineComponent({
name: 'list', name: 'list',
setup() { setup() {
const showModalRef = ref(false)
const modelStatusRef = ref(0)
const { t } = useI18n() const { t } = useI18n()
const { variables, getTableData } = useTable() const { variables, getTableData, createColumns } = useTable()
let updateProjectData = reactive({
code: 0,
projectName: '',
description: ''
})
const requestData = () => { const requestData = () => {
getTableData({ getTableData({
@ -52,120 +39,68 @@ const list = defineComponent({
}) })
} }
const onCancel = () => { const handleModalChange = () => {
showModalRef.value = false variables.showModalRef = true
variables.statusRef = 0
} }
const onConfirm = () => { const handleSearch = () => {
showModalRef.value = false variables.page = 1
updateProjectData = { requestData()
code: 0,
projectName: '',
description: ''
}
resetTableData()
}
const onOpen = () => {
modelStatusRef.value = 0
showModalRef.value = true
} }
const resetTableData = () => { const onCancelModal = () => {
getTableData({ variables.showModalRef = false
pageSize: variables.pageSize,
pageNo: variables.page,
searchVal: variables.searchVal
})
} }
const onSearch = () => { const onConfirmModal = () => {
variables.page = 1 variables.showModalRef = false
getTableData({ requestData()
pageSize: variables.pageSize,
pageNo: variables.page,
searchVal: variables.searchVal
})
} }
const onUpdatePageSize = () => { const handleChangePageSize = () => {
variables.page = 1 variables.page = 1
resetTableData() requestData()
}
const updateProjectItem = (
code: number,
projectName: string,
description: string
) => {
modelStatusRef.value = 1
showModalRef.value = true
updateProjectData.code = code
updateProjectData.projectName = projectName
updateProjectData.description = description
} }
onMounted(() => { onMounted(() => {
createColumns(variables)
requestData() requestData()
}) })
return { watch(useI18n().locale, () => {
t, createColumns(variables)
showModalRef, })
...toRefs(variables),
onCancel, return { t, ...toRefs(variables), requestData, handleModalChange, handleSearch, onCancelModal, onConfirmModal, handleChangePageSize }
onConfirm,
onOpen,
updateProjectItem,
resetTableData,
onUpdatePageSize,
onSearch,
updateProjectData,
modelStatusRef
}
}, },
render() { render() {
const { const { t } = this
t,
showModalRef,
onCancel,
onConfirm,
onOpen,
updateProjectItem,
resetTableData,
onUpdatePageSize,
onSearch,
updateProjectData,
modelStatusRef
} = this
const { columns } = useTable(updateProjectItem, resetTableData)
return ( return (
<div> <div>
<NCard> <NCard>
<div class={styles['search-card']}> <div class={styles['search-card']}>
<div> <NButton
<NButton size='small' type='primary' onClick={onOpen}> size='small'
{t('project.list.create_project')} onClick={this.handleModalChange}
</NButton> type='primary'
</div> class='btn-create-tenant'
<div class={styles.box}> >
{t('project.list.create_project')}
</NButton>
<NSpace>
<NInput <NInput
size='small' size='small'
v-model:value={this.searchVal} v-model={[this.searchVal, 'value']}
placeholder={t('project.list.project_tips')} placeholder={t('project.list.project_tips')}
clearable clearable
/> />
<NButton size='small' type='primary' onClick={onSearch}> <NButton size='small' type='primary' onClick={this.handleSearch}>
{{ <NIcon>
icon: () => ( <SearchOutlined />
<NIcon> </NIcon>
<SearchOutlined />
</NIcon>
)
}}
</NButton> </NButton>
</div> </NSpace>
</div> </div>
</NCard> </NCard>
<Card <Card
@ -173,10 +108,9 @@ const list = defineComponent({
class={styles['table-card']} class={styles['table-card']}
> >
<NDataTable <NDataTable
columns={columns} columns={this.columns}
size={'small'}
data={this.tableData} data={this.tableData}
striped row-class-name='items'
/> />
<div class={styles.pagination}> <div class={styles.pagination}>
<NPagination <NPagination
@ -186,23 +120,21 @@ const list = defineComponent({
show-size-picker show-size-picker
page-sizes={[10, 30, 50]} page-sizes={[10, 30, 50]}
show-quick-jumper show-quick-jumper
onUpdatePage={resetTableData} onUpdatePage={this.requestData}
onUpdatePageSize={onUpdatePageSize} onUpdatePageSize={this.handleChangePageSize}
/> />
</div> </div>
</Card> </Card>
{showModalRef && ( <ProjectModal
<ProjectModal showModalRef={this.showModalRef}
show={showModalRef} statusRef={this.statusRef}
onCancel={onCancel} row={this.row}
onConfirm={onConfirm} onCancelModal={this.onCancelModal}
data={updateProjectData} onConfirmModal={this.onConfirmModal}
status={modelStatusRef} />
/>
)}
</div> </div>
) )
} }
}) })
export default list export default list

201
dolphinscheduler-ui-next/src/views/projects/list/use-table.ts

@ -19,90 +19,161 @@ import { h, reactive, ref } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { useAsyncState } from '@vueuse/core' import { useAsyncState } from '@vueuse/core'
import { queryProjectListPaging } from '@/service/modules/projects' import { queryProjectListPaging } from '@/service/modules/projects'
import { parseTime } from '@/utils/common'
import { deleteProject } from '@/service/modules/projects'
import { format } from 'date-fns' import { format } from 'date-fns'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useMenuStore } from '@/store/menu/menu' import { useMenuStore } from '@/store/menu/menu'
import { NEllipsis } from 'naive-ui' import { NButton, NEllipsis, NIcon, NPopconfirm, NSpace, NTooltip } from 'naive-ui'
import TableAction from './components/table-action'
import { parseTime } from '@/utils/common'
import type { Router } from 'vue-router' import type { Router } from 'vue-router'
import type { TableColumns } from 'naive-ui/es/data-table/src/interface'
import type { ProjectRes } from '@/service/modules/projects/types' import type { ProjectRes } from '@/service/modules/projects/types'
import { DeleteOutlined, EditOutlined } from '@vicons/antd'
export function useTable( export function useTable() {
updateProjectItem = (
unusedCode: number,
unusedName: string,
unusedDescription: string
): void => {},
resetTableData = () => {}
) {
const { t } = useI18n() const { t } = useI18n()
const router: Router = useRouter() const router: Router = useRouter()
const menuStore = useMenuStore() const menuStore = useMenuStore()
const columns: TableColumns<any> = [ const handleEdit = (row: any) => {
{ title: '#', key: 'index', render: (row, index) => index + 1 }, variables.showModalRef = true
{ variables.statusRef = 1
title: t('project.list.project_name'), variables.row = row
key: 'name', }
render: (row) =>
h( const handleDelete = (row: any) => {
NEllipsis, deleteProject(row.code).then(() => {
{ style: 'max-width: 200px; color: #2080f0' }, getTableData({
{ pageSize: variables.pageSize,
default: () => pageNo:
variables.tableData.length === 1 && variables.page > 1
? variables.page - 1
: variables.page,
searchVal: variables.searchVal
})
})
}
const createColumns = (variables: any) => {
variables.columns = [
{ title: '#', key: 'index', render: (row: any, index: number) => index + 1 },
{
title: t('project.list.project_name'),
key: 'name',
render: (row: { code: string; name: any }) =>
h(
NEllipsis,
{ style: 'max-width: 200px; color: #2080f0' },
{
default: () =>
h(
'a',
{
onClick: () => {
menuStore.setProjectCode(row.code)
router.push({ path: `/projects/${row.code}` })
}
},
{
default: () => {
return row.name
}
}
),
tooltip: () => row.name
}
)
},
{ title: t('project.list.owned_users'), key: 'userName' },
{ title: t('project.list.workflow_define_count'), key: 'defCount' },
{
title: t('project.list.process_instance_running_count'),
key: 'instRunningCount'
},
{ title: t('project.list.description'), key: 'description' },
{ title: t('project.list.create_time'), key: 'createTime' },
{ title: t('project.list.update_time'), key: 'updateTime' },
{
title: t('project.list.operation'),
key: 'actions',
render(row: any) {
return h(NSpace, null, {
default: () => [
h( h(
'a', NTooltip,
{},
{ {
onClick: () => { trigger: () =>
menuStore.setProjectCode(row.code) h(
router.push({ path: `/projects/${row.code}` }) NButton,
{
circle: true,
type: 'info',
size: 'small',
class: 'edit',
onClick: () => {
handleEdit(row)
}
},
{
icon: () =>
h(NIcon, null, { default: () => h(EditOutlined) })
}
),
default: () => t('project.list.edit')
}
),
h(
NPopconfirm,
{
onPositiveClick: () => {
handleDelete(row)
} }
}, },
{ {
default: () => { trigger: () =>
return row.name h(
} NTooltip,
{},
{
trigger: () =>
h(
NButton,
{
circle: true,
type: 'error',
size: 'small',
class: 'delete'
},
{
icon: () =>
h(NIcon, null, {
default: () => h(DeleteOutlined)
})
}
),
default: () => t('project.list.delete')
}
),
default: () => t('project.list.delete_confirm')
} }
), )
tooltip: () => row.name ]
} })
) }
}, }
{ title: t('project.list.owned_users'), key: 'userName' }, ]
{ title: t('project.list.workflow_define_count'), key: 'defCount' }, }
{
title: t('project.list.process_instance_running_count'),
key: 'instRunningCount'
},
{ title: t('project.list.description'), key: 'description' },
{ title: t('project.list.create_time'), key: 'createTime' },
{ title: t('project.list.update_time'), key: 'updateTime' },
{
title: t('project.list.operation'),
key: 'actions',
render: (row: any) =>
h(TableAction, {
row,
onResetTableData: () => {
if (variables.page > 1 && variables.tableData.length === 1) {
variables.page -= 1
}
resetTableData()
},
onUpdateProjectItem: (code, name, description) =>
updateProjectItem(code, name, description)
})
}
]
const variables = reactive({ const variables = reactive({
columns: [],
tableData: [], tableData: [],
page: ref(1), page: ref(1),
pageSize: ref(10), pageSize: ref(10),
searchVal: ref(null), searchVal: ref(null),
totalPage: ref(1) totalPage: ref(1),
showModalRef: ref(false),
statusRef: ref(0),
row: {}
}) })
const getTableData = (params: any) => { const getTableData = (params: any) => {
@ -128,5 +199,9 @@ export function useTable(
return state return state
} }
return { getTableData, variables, columns } return {
variables,
getTableData,
createColumns
}
} }

Loading…
Cancel
Save