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)