This is an automated email from the ASF dual-hosted git repository.
lauraxia pushed a commit to branch antdUI-gravitino-base1.1.0
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/antdUI-gravitino-base1.1.0 by
this push:
new 2352e5b978 [#9613][#9614][#9611] fix policies issue and add select all
option for privileges
2352e5b978 is described below
commit 2352e5b978625e69cc0caf3c12a247e2616f1b40
Author: Qian Xia <[email protected]>
AuthorDate: Mon Jan 5 16:29:07 2026 +0800
[#9613][#9614][#9611] fix policies issue and add select all option for
privileges
---
web/web/src/app/access/roles/CreateRoleDialog.js | 3 +-
.../entitiesContent/TableDetailsPage.js | 2 +-
web/web/src/components/PolicyTag.js | 2 +-
.../src/components/SecurableObjectFormFields.js | 87 ++++++++++++++++++++--
4 files changed, 83 insertions(+), 11 deletions(-)
diff --git a/web/web/src/app/access/roles/CreateRoleDialog.js
b/web/web/src/app/access/roles/CreateRoleDialog.js
index 772a1b2040..8847793ff7 100644
--- a/web/web/src/app/access/roles/CreateRoleDialog.js
+++ b/web/web/src/app/access/roles/CreateRoleDialog.js
@@ -32,6 +32,7 @@ import { cn } from '@/lib/utils/tailwind'
import { createRole, getRoleDetails, updateRolePrivileges } from
'@/lib/store/roles'
import { to } from '@/lib/utils'
import { useAppDispatch } from '@/lib/hooks/useStore'
+import { isArray } from '@/lib/utils/is'
const { Paragraph } = Typography
@@ -215,7 +216,7 @@ export default function CreateRoleDialog({ ...props }) {
// Lightweight internal check: avoid emitting debug logs in production
const titleValue = form.getFieldValue(['securableObjects', fname,
'fullName'])
- const fullNameStr = titleValue || ''
+ const fullNameStr = isArray(titleValue) ? titleValue.join('.') :
titleValue
const indexLabel = Number(fname) + 1
const title = fullNameStr ? `Securable Object - ${fullNameStr}` :
`Securable Object - ${indexLabel}`
diff --git
a/web/web/src/app/catalogs/rightContent/entitiesContent/TableDetailsPage.js
b/web/web/src/app/catalogs/rightContent/entitiesContent/TableDetailsPage.js
index cec2730066..843e1513ad 100644
--- a/web/web/src/app/catalogs/rightContent/entitiesContent/TableDetailsPage.js
+++ b/web/web/src/app/catalogs/rightContent/entitiesContent/TableDetailsPage.js
@@ -452,7 +452,7 @@ export default function TableDetailsPage({ ...props }) {
) : null
}
],
- [currentMetalake, catalog, schema, table, store.activatedDetails]
+ [currentMetalake, store.activatedDetails]
)
const { resizableColumns, components, tableWidth } = useAntdColumnResize(()
=> {
diff --git a/web/web/src/components/PolicyTag.js
b/web/web/src/components/PolicyTag.js
index eccb64667c..88dd97b7ca 100644
--- a/web/web/src/components/PolicyTag.js
+++ b/web/web/src/components/PolicyTag.js
@@ -165,7 +165,7 @@ export default function PolicyTag({ ...props }) {
policyElem
)
})}
- {policiesForEntity?.length === 0 && <span>No policies</span>}
+ {policiesForEntity?.length === 0 && <span>No Policies</span>}
{inputVisible && !readOnly && (
<Select
size='small'
diff --git a/web/web/src/components/SecurableObjectFormFields.js
b/web/web/src/components/SecurableObjectFormFields.js
index fec94741d5..e54ef241c6 100644
--- a/web/web/src/components/SecurableObjectFormFields.js
+++ b/web/web/src/components/SecurableObjectFormFields.js
@@ -438,6 +438,32 @@ export default function SecurableObjectFormFields({
fieldName, fieldKey, metalak
return selectedItems?.length && selectedItems.length < groupValues.length
}
+ const getAllOptionValues = item => {
+ const groups = item === 'allowPrivileges' ? allowFilteredGroups :
denyFilteredGroups
+
+return (groups || []).flatMap(g => (g.options || []).map(o => o.value))
+ }
+
+ const handleSelectAll = (checked, item) => {
+ const allValues = getAllOptionValues(item)
+ setFieldValue(['securableObjects', fieldName, item], checked ? allValues :
[])
+ }
+
+ const handleSelectAllChecked = item => {
+ const allValues = getAllOptionValues(item)
+ const selectedItems = getFieldValue(['securableObjects', fieldName, item])
|| []
+
+return allValues.length > 0 && allValues.every(v => selectedItems?.includes(v))
+ }
+
+ const handleSelectAllIndeterminate = item => {
+ const allValues = getAllOptionValues(item)
+ const selectedItems = getFieldValue(['securableObjects', fieldName, item])
|| []
+ const selectedInAll = (selectedItems || []).filter(v =>
allValues.includes(v))
+
+return selectedInAll.length > 0 && selectedInAll.length < allValues.length
+ }
+
const allowSelected = getFieldValue(['securableObjects', fieldName,
'allowPrivileges']) || []
const denySelected = getFieldValue(['securableObjects', fieldName,
'denyPrivileges']) || []
const groupedPrivilegeOptions = privilegeGroupsMap[fieldName] || []
@@ -456,6 +482,9 @@ export default function SecurableObjectFormFields({
fieldName, fieldKey, metalak
}))
.filter(group => group.options.length > 0)
+ const allowAllOptionValues = getAllOptionValues('allowPrivileges')
+ const denyAllOptionValues = getAllOptionValues('denyPrivileges')
+
return (
<div className='flex flex-col gap-2'>
<div>
@@ -689,14 +718,12 @@ export default function SecurableObjectFormFields({
fieldName, fieldKey, metalak
const searchText = searchTextMap[fieldName] || ''
const displayedOptions = searchText
- ? optionsAll
- .filter(o =>
- String(o.label || '')
- .toLowerCase()
- .includes(String(searchText).toLowerCase())
- )
- .slice(0, 10)
- : optionsAll.slice(0, 10)
+ ? optionsAll.filter(o =>
+ String(o.label || '')
+ .toLowerCase()
+ .includes(String(searchText).toLowerCase())
+ )
+ : optionsAll
return (
<Select
@@ -765,6 +792,28 @@ export default function SecurableObjectFormFields({
fieldName, fieldKey, metalak
style={{ width: '100%' }}
loading={!!privilegeGroupsLoading[fieldName]}
>
+ {allowAllOptionValues.length > 0 && (
+ <OptGroup
+ key='__select_all_allow__'
+ label={
+ <Checkbox
+ className='text-base font-medium text-black'
+ checked={handleSelectAllChecked('allowPrivileges')}
+
indeterminate={handleSelectAllIndeterminate('allowPrivileges')}
+ onChange={e => handleSelectAll(e.target.checked,
'allowPrivileges')}
+ >
+ <span className='ant-select-item-group text-base
font-semibold text-black'>Select All</span>
+ </Checkbox>
+ }
+ >
+ <Option
+ key='__select_all_allow_placeholder__'
+ value='__select_all_allow_placeholder__'
+ disabled
+ style={{ height: 0, padding: 0, margin: 0, lineHeight: 0,
display: 'none' }}
+ />
+ </OptGroup>
+ )}
{allowFilteredGroups.map(group => (
<OptGroup
key={group.label}
@@ -794,6 +843,28 @@ export default function SecurableObjectFormFields({
fieldName, fieldKey, metalak
style={{ width: '100%' }}
loading={!!privilegeGroupsLoading[fieldName]}
>
+ {denyAllOptionValues.length > 0 && (
+ <OptGroup
+ key='__select_all_deny__'
+ label={
+ <Checkbox
+ className='text-base font-medium text-black'
+ checked={handleSelectAllChecked('denyPrivileges')}
+
indeterminate={handleSelectAllIndeterminate('denyPrivileges')}
+ onChange={e => handleSelectAll(e.target.checked,
'denyPrivileges')}
+ >
+ <span className='ant-select-item-group text-base
font-semibold text-black'>Select All</span>
+ </Checkbox>
+ }
+ >
+ <Option
+ key='__select_all_deny_placeholder__'
+ value='__select_all_deny_placeholder__'
+ disabled
+ style={{ height: 0, padding: 0, margin: 0, lineHeight: 0,
display: 'none' }}
+ />
+ </OptGroup>
+ )}
{denyFilteredGroups.map(group => (
<OptGroup
key={group.label}