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}

Reply via email to