From 7452675116570a9f4ee339b4bd93c31d19234959 Mon Sep 17 00:00:00 2001 From: ssongliu Date: Thu, 11 Jun 2026 16:35:10 +0800 Subject: [PATCH] fix: correct node administrator permissions --- frontend/src/api/modules/setting.ts | 4 -- .../src/components/complex-table/index.vue | 5 +- .../src/components/fu/FuTableOperations.vue | 5 +- frontend/src/components/fu/shared.ts | 1 + frontend/src/directives/index.ts | 3 +- frontend/src/directives/modules/permission.ts | 22 +++++- frontend/src/utils/node.ts | 12 +--- frontend/src/utils/permission.ts | 20 ++++-- frontend/src/views/cronjob/cronjob/index.vue | 25 +++++-- .../views/cronjob/cronjob/record/index.vue | 12 +++- frontend/src/views/cronjob/library/index.vue | 25 +++++-- .../disk-management/components/disk-card.vue | 14 +++- .../host/disk-management/partition/index.vue | 13 ++-- .../code-editor/history/index.vue | 10 ++- .../file-management/code-editor/index.vue | 6 +- .../host/file-management/favorite/index.vue | 1 + .../src/views/host/file-management/index.vue | 41 +++++++++-- .../file-management/recycle-bin/index.vue | 25 ++++++- .../host/file-management/share-list/index.vue | 1 + .../host/file-management/share/index.vue | 4 +- .../src/views/host/firewall/advance/index.vue | 16 +++-- .../src/views/host/firewall/forward/index.vue | 16 +++-- frontend/src/views/host/firewall/ip/index.vue | 19 +++-- .../src/views/host/firewall/port/index.vue | 19 +++-- .../src/views/host/firewall/status/index.vue | 27 ++++++-- .../src/views/host/monitor/setting/index.vue | 11 +-- frontend/src/views/host/ssh/log/log.vue | 4 +- frontend/src/views/host/ssh/session/index.vue | 1 + .../host/ssh/ssh/certification/index.vue | 8 ++- frontend/src/views/host/ssh/ssh/index.vue | 43 +++++++++--- frontend/src/views/toolbox/clam/index.vue | 13 +++- .../src/views/toolbox/clam/operate/index.vue | 10 ++- .../src/views/toolbox/clam/record/index.vue | 17 ++++- .../src/views/toolbox/clam/setting/index.vue | 2 +- .../src/views/toolbox/clam/status/index.vue | 22 +++++- frontend/src/views/toolbox/clean/index.vue | 3 +- .../src/views/toolbox/device/dns/index.vue | 2 +- .../views/toolbox/device/hostname/index.vue | 8 ++- .../src/views/toolbox/device/hosts/index.vue | 4 +- frontend/src/views/toolbox/device/index.vue | 22 +++--- .../src/views/toolbox/device/ntp/index.vue | 29 ++++++-- .../src/views/toolbox/device/passwd/index.vue | 8 ++- .../src/views/toolbox/device/swap/index.vue | 2 +- .../toolbox/fail2ban/ban-action/index.vue | 2 +- .../views/toolbox/fail2ban/ban-time/index.vue | 2 +- .../toolbox/fail2ban/find-time/index.vue | 2 +- frontend/src/views/toolbox/fail2ban/index.vue | 69 ++++++++++++++++--- .../src/views/toolbox/fail2ban/ips/index.vue | 2 +- .../views/toolbox/fail2ban/log-path/index.vue | 4 +- .../toolbox/fail2ban/max-retry/index.vue | 2 +- .../src/views/toolbox/fail2ban/port/index.vue | 2 +- frontend/src/views/toolbox/ftp/index.vue | 29 ++++++-- .../src/views/toolbox/ftp/operate/index.vue | 11 ++- frontend/src/views/toolbox/index.vue | 4 +- .../toolbox/supervisor/config/basic/index.vue | 2 +- .../supervisor/config/source/index.vue | 2 +- .../views/toolbox/supervisor/create/index.vue | 9 ++- .../views/toolbox/supervisor/file/index.vue | 2 +- .../src/views/toolbox/supervisor/index.vue | 16 ++++- .../views/toolbox/supervisor/log/index.vue | 8 ++- .../views/toolbox/supervisor/status/index.vue | 8 ++- .../toolbox/supervisor/status/init/index.vue | 2 +- 62 files changed, 563 insertions(+), 170 deletions(-) diff --git a/frontend/src/api/modules/setting.ts b/frontend/src/api/modules/setting.ts index ca4cbbffba61..7541b81d2702 100644 --- a/frontend/src/api/modules/setting.ts +++ b/frontend/src/api/modules/setting.ts @@ -56,10 +56,6 @@ export const listAppNodes = () => { return http.get>(`/core/xpack/nodes/apps/update`, {}, { timeout: TimeoutEnum.T_60S }); }; -// enterprise -export const loadNodeByUser = () => { - return http.get>(`/core/enterprise/users/nodes`); -}; export const uploadEnterpriseLicense = (params: FormData) => { return http.upload('/core/enterprise/licenses/upload', params); }; diff --git a/frontend/src/components/complex-table/index.vue b/frontend/src/components/complex-table/index.vue index 7e849cf81674..dfd5bc232c1c 100644 --- a/frontend/src/components/complex-table/index.vue +++ b/frontend/src/components/complex-table/index.vue @@ -171,10 +171,11 @@ const closeRightClick = () => { const disabled = computed(() => { return function (btn: any) { let permissionDisabled = false; + const permissionOptions = { nodeAdmin: btn.nodeAdmin === true }; if (btn.permission === true) { - permissionDisabled = !hasManagePermissionAccess(); + permissionDisabled = !hasManagePermissionAccess(undefined, permissionOptions); } else if (btn.permission !== undefined) { - permissionDisabled = !hasPermissionAccess(btn.permission); + permissionDisabled = !hasPermissionAccess(btn.permission, permissionOptions); } const buttonDisabled = typeof btn.disabled === 'function' ? btn.disabled(rightClick.value.currentRow) : btn.disabled; diff --git a/frontend/src/components/fu/FuTableOperations.vue b/frontend/src/components/fu/FuTableOperations.vue index 5e1252104a42..9602d1c9891e 100644 --- a/frontend/src/components/fu/FuTableOperations.vue +++ b/frontend/src/components/fu/FuTableOperations.vue @@ -206,10 +206,11 @@ const getMoreButtons = (row: any) => { const isButtonDisabled = (button: FuTableOperationButton, row: any) => { let permissionDisabled = false; + const permissionOptions = { nodeAdmin: button.nodeAdmin === true }; if (button.permission === true) { - permissionDisabled = !hasManagePermissionAccess(); + permissionDisabled = !hasManagePermissionAccess(undefined, permissionOptions); } else if (button.permission !== undefined) { - permissionDisabled = !hasPermissionAccess(button.permission); + permissionDisabled = !hasPermissionAccess(button.permission, permissionOptions); } return permissionDisabled || Boolean(resolveMaybeFn(button.disabled ?? false, row)); }; diff --git a/frontend/src/components/fu/shared.ts b/frontend/src/components/fu/shared.ts index c063d3ec014f..44d079fffbcd 100644 --- a/frontend/src/components/fu/shared.ts +++ b/frontend/src/components/fu/shared.ts @@ -14,6 +14,7 @@ export interface FuTableOperationButton { click?: (row: any) => void; disabled?: boolean | ((row: any) => boolean); permission?: true | PermissionBindingValue; + nodeAdmin?: boolean; show?: boolean | ((row: any) => boolean); type?: string; icon?: any; diff --git a/frontend/src/directives/index.ts b/frontend/src/directives/index.ts index 9038cfa4a0b9..e290808aa07c 100644 --- a/frontend/src/directives/index.ts +++ b/frontend/src/directives/index.ts @@ -1,9 +1,10 @@ import { App, Directive } from 'vue'; import integerInput from './modules/integer'; -import permission from './modules/permission'; +import permission, { nodeAdminDirective } from './modules/permission'; const directivesList: { [key: string]: Directive } = { 'integer-input': integerInput, + 'node-admin': nodeAdminDirective, permission, }; diff --git a/frontend/src/directives/modules/permission.ts b/frontend/src/directives/modules/permission.ts index 586e4b88bc5d..cbb6211bd17f 100644 --- a/frontend/src/directives/modules/permission.ts +++ b/frontend/src/directives/modules/permission.ts @@ -14,6 +14,7 @@ const PERMISSION_DISABLED_ATTR = 'data-permission-disabled'; const PERMISSION_POINTER_EVENTS_ATTR = 'data-permission-pointer-events'; const PERMISSION_NATIVE_DISABLED_ATTR = 'data-permission-native-disabled'; const PERMISSION_TABINDEX_ATTR = 'data-permission-tabindex'; +const NODE_ADMIN_PERMISSION_ATTR = 'data-node-admin-permission'; const getDisableTargets = (el: HTMLElement) => { const targets = [el, ...Array.from(el.querySelectorAll('button, input, select, textarea'))]; @@ -102,11 +103,16 @@ const getPermissionMode = (binding: DirectiveBinding): P return binding.arg === 'view' ? 'view' : 'manage'; }; +const hasNodeAdminDirective = (el: HTMLElement, vnode: VNode) => { + return el.hasAttribute(NODE_ADMIN_PERMISSION_ATTR) || !!vnode.dirs?.some((item) => item.dir === nodeAdminDirective); +}; + const applyPermission = (el: HTMLElement, binding: DirectiveBinding, vnode: VNode) => { + const options = { nodeAdmin: hasNodeAdminDirective(el, vnode) }; const disabled = getPermissionMode(binding) === 'view' - ? !hasPermissionAccess(binding.value) - : !hasManagePermissionAccess(binding.value); + ? !hasPermissionAccess(binding.value, options) + : !hasManagePermissionAccess(binding.value, options); const controller = getComponentPermissionController(vnode); if (controller?.setPermissionDisabled) { @@ -130,4 +136,16 @@ const permissionDirective: Directive = { }, }; +export const nodeAdminDirective: Directive = { + mounted(el) { + el.setAttribute(NODE_ADMIN_PERMISSION_ATTR, 'true'); + }, + updated(el) { + el.setAttribute(NODE_ADMIN_PERMISSION_ATTR, 'true'); + }, + unmounted(el) { + el.removeAttribute(NODE_ADMIN_PERMISSION_ATTR); + }, +}; + export default permissionDirective; diff --git a/frontend/src/utils/node.ts b/frontend/src/utils/node.ts index 03c7e7ec5b06..12faa21ce9d4 100644 --- a/frontend/src/utils/node.ts +++ b/frontend/src/utils/node.ts @@ -1,5 +1,5 @@ import { Setting } from '@/api/interface/setting'; -import { listNodeOptions, loadNodeByUser } from '@/api/modules/setting'; +import { listNodeOptions } from '@/api/modules/setting'; import { GlobalStore } from '@/store'; export const changeToLocal = async () => { @@ -23,15 +23,9 @@ export const changeToLocal = async () => { }; export async function listNodes(type: string): Promise> { - const globalStore = GlobalStore(); try { - if (globalStore.isAdmin) { - const res = await listNodeOptions(type); - return res.data || []; - } else { - const res = await loadNodeByUser(); - return res.data || []; - } + const res = await listNodeOptions(type); + return res.data || []; } catch (error) { return []; } diff --git a/frontend/src/utils/permission.ts b/frontend/src/utils/permission.ts index 76a715e91ae3..102355118d14 100644 --- a/frontend/src/utils/permission.ts +++ b/frontend/src/utils/permission.ts @@ -4,6 +4,9 @@ import { normalizeToManageCode } from '@/utils/permission-codes'; export type PermissionBindingValue = string | string[] | undefined; export type PermissionMode = 'manage' | 'view'; +export type PermissionAccessOptions = { + nodeAdmin?: boolean; +}; const getRoutePermission = (): PermissionBindingValue => { const route = router.currentRoute.value; @@ -46,8 +49,15 @@ export const toPermissionList = (value: PermissionBindingValue) => { return routePermission ? [routePermission] : []; }; -const hasPermissionAccessByMode = (mode: PermissionMode, value?: PermissionBindingValue) => { +const hasPermissionAccessByMode = ( + mode: PermissionMode, + value?: PermissionBindingValue, + options: PermissionAccessOptions = {}, +) => { const globalStore = GlobalStore(); + if (options.nodeAdmin && globalStore.isNodeAdmin) { + return true; + } const permissions = toPermissionList(value); const normalizedPermissions = mode === 'manage' ? permissions.map(toManagePermission).filter(Boolean) : permissions; if (normalizedPermissions.length === 0) { @@ -56,10 +66,10 @@ const hasPermissionAccessByMode = (mode: PermissionMode, value?: PermissionBindi return normalizedPermissions.some((permission) => globalStore.hasPermission(permission)); }; -export const hasManagePermissionAccess = (value?: PermissionBindingValue) => { - return hasPermissionAccessByMode('manage', value); +export const hasManagePermissionAccess = (value?: PermissionBindingValue, options?: PermissionAccessOptions) => { + return hasPermissionAccessByMode('manage', value, options); }; -export const hasPermissionAccess = (value?: PermissionBindingValue) => { - return hasPermissionAccessByMode('view', value); +export const hasPermissionAccess = (value?: PermissionBindingValue, options?: PermissionAccessOptions) => { + return hasPermissionAccessByMode('view', value, options); }; diff --git a/frontend/src/views/cronjob/cronjob/index.vue b/frontend/src/views/cronjob/cronjob/index.vue index 7830b88172d0..84987cfb6de1 100644 --- a/frontend/src/views/cronjob/cronjob/index.vue +++ b/frontend/src/views/cronjob/cronjob/index.vue @@ -2,15 +2,16 @@
@@ -184,6 +191,7 @@ {{ $t('commons.button.reset') }} - + {{ $t('commons.button.save') }} @@ -127,11 +127,11 @@
- + {{ $t('file.aiSearch') }} @@ -246,11 +253,11 @@