This is an automated email from the ASF dual-hosted git repository. nicholasjiang pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/paimon-webui.git
commit 4e0f9bf61f5a3cb6c5950b09d93417e8dce179db Author: s7monk <34889415+s7m...@users.noreply.github.com> AuthorDate: Wed Jul 10 11:34:25 2024 +0800 [Improvement] Support indeterminate keys for permission configuration of role creation (#489) --- paimon-web-ui/src/api/models/role/types.ts | 1 + .../system/role/components/role-form/index.tsx | 11 +++- paimon-web-ui/src/views/system/role/index.tsx | 59 ++++++++++++++++++++-- 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/paimon-web-ui/src/api/models/role/types.ts b/paimon-web-ui/src/api/models/role/types.ts index 828ef7b9..693196fe 100644 --- a/paimon-web-ui/src/api/models/role/types.ts +++ b/paimon-web-ui/src/api/models/role/types.ts @@ -55,4 +55,5 @@ export interface RoleDTO { enabled: boolean remark?: string menuIds: number[] + indeterminateKeys?: number[] } diff --git a/paimon-web-ui/src/views/system/role/components/role-form/index.tsx b/paimon-web-ui/src/views/system/role/components/role-form/index.tsx index 41eab85e..95a93e65 100644 --- a/paimon-web-ui/src/views/system/role/components/role-form/index.tsx +++ b/paimon-web-ui/src/views/system/role/components/role-form/index.tsx @@ -41,6 +41,7 @@ const props = { enabled: true, remark: '', menuIds: [], + indeterminateKeys: [], }), }, 'onUpdate:formValue': [Function, Object] as PropType<((value: RoleDTO) => void) | undefined>, @@ -95,6 +96,10 @@ export default defineComponent({ props.formValue.menuIds = checkIds } + const onUpdateIndeterminateKeys = (indeterminateKeys: Array<number>) => { + props.formValue.indeterminateKeys = indeterminateKeys + } + const handleConfirm = async () => { await formRef.value.validate() props && props.onConfirm && props.onConfirm() @@ -109,6 +114,7 @@ export default defineComponent({ enabled: true, remark: '', menuIds: [], + indeterminateKeys: [], }) } @@ -120,6 +126,7 @@ export default defineComponent({ handleCloseModal, renderLabel, onUpdateMenuIds, + onUpdateIndeterminateKeys, handleConfirm, t, } @@ -160,11 +167,13 @@ export default defineComponent({ <n-form-item label={this.t('system.role.permission_setting')} path="menuIds"> <n-tree key-field="id" - default-expand-all + cascade block-line renderLabel={this.renderLabel} onUpdate:checkedKeys={this.onUpdateMenuIds} + onUpdate:indeterminateKeys={this.onUpdateIndeterminateKeys} checkedKeys={this.formValue.menuIds} + indeterminateKeys={this.formValue.indeterminateKeys} data={this.permissionTree} expand-on-click checkable diff --git a/paimon-web-ui/src/views/system/role/index.tsx b/paimon-web-ui/src/views/system/role/index.tsx index b502d519..d3d1f30e 100644 --- a/paimon-web-ui/src/views/system/role/index.tsx +++ b/paimon-web-ui/src/views/system/role/index.tsx @@ -17,13 +17,14 @@ under the License. */ import dayjs from 'dayjs' import { EditOutlined } from '@vicons/antd' +import { Add } from '@vicons/ionicons5' import styles from './index.module.scss' import { useTable } from './use-table' import RoleForm from './components/role-form' import RoleDetail from './components/role-detail' import RoleDelete from './components/role-delete' import { createRole, getPermissionByRoleId, updateRole } from '@/api/models/role' -import type { Role, RoleDTO } from '@/api/models/role/types' +import type { Role, RoleDTO, RoleMenu } from '@/api/models/role/types' export default defineComponent({ name: 'RolePage', @@ -109,17 +110,64 @@ export default defineComponent({ enabled: true, remark: '', menuIds: [], + indeterminateKeys: [], }) + function inferIndeterminateKeys(checkedKeys: number[], allNodes: RoleMenu[]): { updatedCheckedKeys: number[], indeterminateKeys: number[] } { + const indeterminateKeys = new Set<number>() + const updatedCheckedKeys = new Set<number>(checkedKeys) + + function checkNode(node: RoleMenu): boolean { + let childCheckedCount = 0 + const childCount = node.children ? node.children.length : 0 + + if (childCount > 0) { + let allChildrenChecked = true + + node.children.forEach((child) => { + const childIsChecked = checkNode(child) + if (childIsChecked) { + childCheckedCount++ + } + else { + allChildrenChecked = false + } + }) + + if (childCheckedCount > 0 && childCheckedCount < childCount) { + indeterminateKeys.add(node.id) + updatedCheckedKeys.delete(node.id) + } + + return allChildrenChecked + } + + return checkedKeys.includes(node.id) + } + + allNodes.forEach((node) => { + if (checkNode(node) && !checkedKeys.includes(node.id)) { + indeterminateKeys.add(node.id) + } + }) + + return { + updatedCheckedKeys: Array.from(updatedCheckedKeys), + indeterminateKeys: Array.from(indeterminateKeys), + } + } + async function getDetail(role: Role) { const res = await getPermissionByRoleId(role.id) + const { updatedCheckedKeys, indeterminateKeys } = inferIndeterminateKeys(res?.data?.checkedKeys, res?.data?.menus) formValue.value = { id: role.id, roleName: role.roleName, roleKey: role.roleKey, enabled: role.enabled, remark: role.remark, - menuIds: res?.data?.checkedKeys, + menuIds: updatedCheckedKeys, + indeterminateKeys, } } @@ -175,7 +223,12 @@ export default defineComponent({ <n-space vertical> <n-space justify="space-between"> <n-space> - <n-button onClick={this.handleCreateModal} type="primary">{this.t('system.user.add')}</n-button> + <n-button onClick={this.handleCreateModal} type="primary"> + {{ + icon: () => <n-icon component={Add} />, + default: () => this.t('system.role.create'), + }} + </n-button> </n-space> <n-space> <></>