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

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


The following commit(s) were added to refs/heads/branch-1.3 by this push:
     new 42f4e01a75 [Cherry-pick to branch-1.3] [#11637] web-v2(UI): support 
create role for hierarchical schema in the role edit page (#11711) (#11714)
42f4e01a75 is described below

commit 42f4e01a75e3a9b5014b4eabb955fd2721f15a86
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Wed Jun 17 19:14:58 2026 +0800

    [Cherry-pick to branch-1.3] [#11637] web-v2(UI): support create role for 
hierarchical schema in the role edit page (#11711) (#11714)
    
    **Cherry-pick Information:**
    - Original commit: 2784c6da2f5ad70ba03eeec74af1db8a664fbe73
    - Target branch: `branch-1.3`
    - Status: ✅ Clean cherry-pick (no conflicts)
    
    Co-authored-by: Qian Xia <[email protected]>
---
 .../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