This is an automated email from the ASF dual-hosted git repository.

mchades pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new 2784c6da2f [#11637] web-v2(UI): support create role for hierarchical 
schema in the role edit page (#11711)
2784c6da2f is described below

commit 2784c6da2f5ad70ba03eeec74af1db8a664fbe73
Author: Qian Xia <[email protected]>
AuthorDate: Wed Jun 17 17:09:25 2026 +0800

    [#11637] web-v2(UI): support create role for hierarchical schema in the 
role edit page (#11711)
    
    ### What changes were proposed in this pull request?
    <img width="2320" height="1702" alt="image"
    
src="https://github.com/user-attachments/assets/c90fe4bb-f8b6-424a-a40b-5d4f8b89f2ce";
    />
    
    
    ### Why are the changes needed?
    
    Fix: #11637
    
    ### Does this PR introduce _any_ user-facing change?
    N/A
    
    ### How was this patch tested?
    
    1. create a role
    2. fullname schema item enter subschema name
---
 .../src/components/SecurableObjectFormFields.js    | 86 ++++++++++++++++++++--
 1 file changed, 79 insertions(+), 7 deletions(-)

diff --git a/web-v2/web/src/components/SecurableObjectFormFields.js 
b/web-v2/web/src/components/SecurableObjectFormFields.js
index 3060b030c5..5d2c869ddf 100644
--- a/web-v2/web/src/components/SecurableObjectFormFields.js
+++ b/web-v2/web/src/components/SecurableObjectFormFields.js
@@ -33,6 +33,7 @@ import {
 import { fetchTags } from '@/lib/store/tags'
 import { fetchPolicies } from '@/lib/store/policies'
 import { fetchJobTemplates } from '@/lib/store/jobs'
+import { getSchemasApi } from '@/lib/api/schemas'
 import { privilegeTypes, privilegeOptions } from '@/config/security'
 
 export default function SecurableObjectFormFields({ fieldName, fieldKey, 
metalake }) {
@@ -47,6 +48,8 @@ export default function SecurableObjectFormFields({ 
fieldName, fieldKey, metalak
   const displayValue = currentFull
   const dispatch = useAppDispatch()
   const store = useAppSelector(state => state.metalakes)
+  const { systemConfig } = useAppSelector(state => state.auth) || {}
+  const separator = (systemConfig && 
systemConfig['gravitino.schema.separator']) || ':'
 
   const parts = String(currentFull || '')
     .split('.')
@@ -73,6 +76,7 @@ export default function SecurableObjectFormFields({ 
fieldName, fieldKey, metalak
   const [localRemoteLoading, setLocalRemoteLoading] = useState({})
   const catalogOptions = localRemoteOptions['catalog'] || []
   const rootRef = useRef(null)
+  const schemaSearchTimerRef = useRef(null)
 
   const isElementVisibleInViewport = el => {
     if (!el) return true
@@ -103,6 +107,15 @@ export default function SecurableObjectFormFields({ 
fieldName, fieldKey, metalak
     }
   }, [])
 
+  useEffect(() => {
+    return () => {
+      if (schemaSearchTimerRef.current) {
+        clearTimeout(schemaSearchTimerRef.current)
+        schemaSearchTimerRef.current = null
+      }
+    }
+  }, [])
+
   const loadOptionsForType = async type => {
     if (!metalake) return
     const t = String(type || '').toLowerCase()
@@ -443,6 +456,40 @@ export default function SecurableObjectFormFields({ 
fieldName, fieldKey, metalak
     }
   }
 
+  const searchSchemas = async (catalog, searchText) => {
+    if (!catalog) return
+    setSchemasLoading(true)
+    try {
+      const parts = String(searchText || '').split(separator)
+      const filterText = parts.pop() || ''
+      const parentSchema = parts.length > 0 ? parts.join(separator) : undefined
+
+      const res = await getSchemasApi({ metalake, catalog, parentSchema })
+      const schemas = res?.identifiers || []
+
+      const options = schemas
+        .map(s => {
+          const fullName = s.name
+
+          return { label: fullName, value: fullName }
+        })
+        .filter(o => !filterText || 
o.label.toLowerCase().includes(filterText.toLowerCase()))
+
+      setSchemasOptions(options)
+    } catch (e) {
+      setSchemasOptions([])
+    } finally {
+      setSchemasLoading(false)
+    }
+  }
+
+  const debouncedSearchSchemas = (catalog, searchText) => {
+    if (schemaSearchTimerRef.current) 
clearTimeout(schemaSearchTimerRef.current)
+    schemaSearchTimerRef.current = setTimeout(() => {
+      searchSchemas(catalog, searchText)
+    }, 300)
+  }
+
   const loadResourcesForSchema = async (catalog, schema, type) => {
     if (!catalog || !schema) return
     setResourcesLoading(true)
@@ -618,6 +665,10 @@ export default function SecurableObjectFormFields({ 
fieldName, fieldKey, metalak
                       setTimeout(() => setFieldValue(['securableObjects', 
fieldName, 'allowPrivileges'], []), 0)
                       setTimeout(() => setFieldValue(['securableObjects', 
fieldName, 'denyPrivileges'], []), 0)
 
+                      if (schemaSearchTimerRef.current) {
+                        clearTimeout(schemaSearchTimerRef.current)
+                        schemaSearchTimerRef.current = null
+                      }
                       loadSchemasForCatalog(v)
                       loadPrivilegeGroupsForField(fieldName, currentType, v)
                     }}
@@ -631,13 +682,21 @@ export default function SecurableObjectFormFields({ 
fieldName, fieldKey, metalak
                   </Select>
                   <Select
                     showSearch
-                    filterOption={(input, option) =>
-                      
String(option.label).toLowerCase().includes(String(input).toLowerCase())
-                    }
+                    filterOption={false}
                     placeholder={'Please search or select schema name'}
                     loading={schemasLoading}
                     value={localSchemaVal}
-                    onSearch={() => {}}
+                    onSearch={val => {
+                      if (val) {
+                        debouncedSearchSchemas(localCatalogVal, val)
+                      } else if (localCatalogVal) {
+                        if (schemaSearchTimerRef.current) {
+                          clearTimeout(schemaSearchTimerRef.current)
+                          schemaSearchTimerRef.current = null
+                        }
+                        loadSchemasForCatalog(localCatalogVal)
+                      }
+                    }}
                     onFocus={() => {
                       if (!schemasOptions.length && localCatalogVal) {
                         loadSchemasForCatalog(localCatalogVal)
@@ -705,6 +764,10 @@ export default function SecurableObjectFormFields({ 
fieldName, fieldKey, metalak
                       setTimeout(() => setFieldValue(['securableObjects', 
fieldName, 'allowPrivileges'], []), 0)
                       setTimeout(() => setFieldValue(['securableObjects', 
fieldName, 'denyPrivileges'], []), 0)
 
+                      if (schemaSearchTimerRef.current) {
+                        clearTimeout(schemaSearchTimerRef.current)
+                        schemaSearchTimerRef.current = null
+                      }
                       loadSchemasForCatalog(v)
                       loadPrivilegeGroupsForField(fieldName, currentType, v)
                     }}
@@ -718,12 +781,21 @@ export default function SecurableObjectFormFields({ 
fieldName, fieldKey, metalak
                   </Select>
                   <Select
                     showSearch
-                    filterOption={(input, option) =>
-                      
String(option.label).toLowerCase().includes(String(input).toLowerCase())
-                    }
+                    filterOption={false}
                     placeholder={`Please search or select schema name`}
                     loading={schemasLoading}
                     value={localSchemaVal}
+                    onSearch={val => {
+                      if (val) {
+                        debouncedSearchSchemas(localCatalogVal, val)
+                      } else if (localCatalogVal) {
+                        if (schemaSearchTimerRef.current) {
+                          clearTimeout(schemaSearchTimerRef.current)
+                          schemaSearchTimerRef.current = null
+                        }
+                        loadSchemasForCatalog(localCatalogVal)
+                      }
+                    }}
                     onFocus={() => {
                       if (!schemasOptions.length && localCatalogVal) {
                         loadSchemasForCatalog(localCatalogVal)

Reply via email to