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

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

commit b9486dbf8258ad9f44a048fa94198ef39ef944cc
Author: Qian Xia <[email protected]>
AuthorDate: Mon Jan 12 21:17:35 2026 +0800

    [#95] web(UI): spport bigquery UI (#106)
    
    * [#95] web(UI): spport bigquery UI
    
    * Update web/web/src/app/metalakes/metalake/rightContent/MetalakePath.js
    
    Co-authored-by: Copilot <[email protected]>
    
    * Update web/web/src/app/metalakes/metalake/rightContent/MetalakePath.js
    
    Co-authored-by: Copilot <[email protected]>
    
    * improve checkCatalogIcon func
    
    ---------
    
    Co-authored-by: Copilot <[email protected]>
---
 web/web/src/app/metalakes/metalake/MetalakeTree.js | 39 +------------
 .../metalake/rightContent/CreateCatalogDialog.js   | 16 +++++-
 .../metalake/rightContent/MetalakePath.js          | 10 +++-
 web/web/src/lib/utils/catalogIcons.js              | 58 +++++++++++++++++++
 web/web/src/lib/utils/initial.js                   | 66 ++++++++++++++++++++++
 5 files changed, 147 insertions(+), 42 deletions(-)

diff --git a/web/web/src/app/metalakes/metalake/MetalakeTree.js 
b/web/web/src/app/metalakes/metalake/MetalakeTree.js
index 661c04bf18..89f75000db 100644
--- a/web/web/src/app/metalakes/metalake/MetalakeTree.js
+++ b/web/web/src/app/metalakes/metalake/MetalakeTree.js
@@ -30,6 +30,7 @@ import Icon from '@/components/Icon'
 import clsx from 'clsx'
 
 import { useAppDispatch, useAppSelector } from '@/lib/hooks/useStore'
+import { checkCatalogIcon } from '@/lib/utils/catalogIcons'
 import {
   setExpandedNodes,
   setIntoTreeNodeWithFetch,
@@ -57,44 +58,6 @@ const MetalakeTree = props => {
   const dispatch = useAppDispatch()
   const store = useAppSelector(state => state.metalakes)
 
-  const checkCatalogIcon = ({ type, provider }) => {
-    switch (type) {
-      case 'relational':
-        switch (provider) {
-          case 'hive':
-            return 'custom-icons-hive'
-          case 'lakehouse-iceberg':
-            return 'openmoji:iceberg'
-          case 'jdbc-mysql':
-            return 'devicon:mysql-wordmark'
-          case 'jdbc-postgresql':
-            return 'devicon:postgresql-wordmark'
-          case 'jdbc-doris':
-            return 'custom-icons-doris'
-          case 'jdbc-starrocks':
-            return 'custom-icons-starrocks'
-          case 'lakehouse-paimon':
-            return 'custom-icons-paimon'
-          case 'lakehouse-hudi':
-            return 'custom-icons-hudi'
-          case 'lakehouse-generic':
-            return 'material-symbols:houseboat-outline'
-          case 'jdbc-oceanbase':
-            return 'custom-icons-oceanbase'
-          default:
-            return 'bx:book'
-        }
-      case 'messaging':
-        return 'skill-icons:kafka'
-      case 'fileset':
-        return 'twemoji:file-folder'
-      case 'model':
-        return 'carbon:machine-learning-model'
-      default:
-        return 'bx:book'
-    }
-  }
-
   const handleClickIcon = (e, nodeProps) => {
     e.stopPropagation()
     if (nodeProps.data.inUse === 'false') return
diff --git 
a/web/web/src/app/metalakes/metalake/rightContent/CreateCatalogDialog.js 
b/web/web/src/app/metalakes/metalake/rightContent/CreateCatalogDialog.js
index b6a967b5a3..0a479a9198 100644
--- a/web/web/src/app/metalakes/metalake/rightContent/CreateCatalogDialog.js
+++ b/web/web/src/app/metalakes/metalake/rightContent/CreateCatalogDialog.js
@@ -257,7 +257,21 @@ const CreateCatalogDialog = props => {
         let properties = {}
 
         const prevProperties = innerProps
-          .filter(i => (typeSelect === 'fileset' && i.key === 'location' ? 
i.value.trim() !== '' : i.key.trim() !== ''))
+          .filter(item => {
+            const hasKey = item.key.trim() !== ''
+
+            if (!hasKey) {
+              return false
+            }
+
+            if (typeSelect === 'fileset' && item.key === 'location') {
+              return item.value.trim() !== ''
+            }
+
+            const hasValue = item.value?.trim() !== ''
+
+            return item.required || hasValue
+          })
           .reduce((acc, item) => {
             acc[item.key] = item.value
 
diff --git a/web/web/src/app/metalakes/metalake/rightContent/MetalakePath.js 
b/web/web/src/app/metalakes/metalake/rightContent/MetalakePath.js
index 9deeff5375..f75e758b23 100644
--- a/web/web/src/app/metalakes/metalake/rightContent/MetalakePath.js
+++ b/web/web/src/app/metalakes/metalake/rightContent/MetalakePath.js
@@ -25,6 +25,8 @@ import { useSearchParams } from 'next/navigation'
 import { Link as MUILink, Breadcrumbs, Typography, Tooltip, styled, Box, 
IconButton } from '@mui/material'
 
 import Icon from '@/components/Icon'
+import { useAppSelector } from '@/lib/hooks/useStore'
+import { checkCatalogIcon } from '@/lib/utils/catalogIcons'
 
 const TextWrapper = styled(Typography)(({ theme }) => ({
   maxWidth: '120px',
@@ -36,10 +38,9 @@ const TextWrapper = styled(Typography)(({ theme }) => ({
 const Text = props => {
   return <TextWrapper component='span' {...props} />
 }
-
 const MetalakePath = props => {
   const searchParams = useSearchParams()
-
+  const store = useAppSelector(state => state.metalakes)
   const routeParams = {
     metalake: searchParams.get('metalake'),
     catalog: searchParams.get('catalog'),
@@ -123,7 +124,10 @@ const MetalakePath = props => {
               onClick={event => handleClick(event, catalogUrl)}
               underline='hover'
             >
-              <Icon icon='bx:book' fontSize={20} />
+              <Icon
+                icon={checkCatalogIcon({ type, provider: 
store.catalogs?.find(c => c.name === catalog)?.provider })}
+                fontSize={20}
+              />
               <Text data-refer={`nav-to-catalog-${catalog}`}>{catalog}</Text>
             </MUILink>
           </Tooltip>
diff --git a/web/web/src/lib/utils/catalogIcons.js 
b/web/web/src/lib/utils/catalogIcons.js
new file mode 100644
index 0000000000..ffbb617511
--- /dev/null
+++ b/web/web/src/lib/utils/catalogIcons.js
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export const checkCatalogIcon = ({ type, provider }) => {
+  switch (type) {
+    case 'relational':
+      switch (provider) {
+        case 'hive':
+          return 'custom-icons-hive'
+        case 'lakehouse-iceberg':
+          return 'openmoji:iceberg'
+        case 'jdbc-mysql':
+          return 'devicon:mysql-wordmark'
+        case 'jdbc-bigquery':
+          return 'simple-icons:googlebigquery'
+        case 'jdbc-postgresql':
+          return 'devicon:postgresql-wordmark'
+        case 'jdbc-doris':
+          return 'custom-icons-doris'
+        case 'jdbc-starrocks':
+          return 'custom-icons-starrocks'
+        case 'lakehouse-paimon':
+          return 'custom-icons-paimon'
+        case 'lakehouse-hudi':
+          return 'custom-icons-hudi'
+        case 'lakehouse-generic':
+          return 'material-symbols:houseboat-outline'
+        case 'jdbc-oceanbase':
+          return 'custom-icons-oceanbase'
+        default:
+          return 'bx:book'
+      }
+    case 'messaging':
+      return 'skill-icons:kafka'
+    case 'fileset':
+      return 'twemoji:file-folder'
+    case 'model':
+      return 'carbon:machine-learning-model'
+    default:
+      return 'bx:book'
+  }
+}
diff --git a/web/web/src/lib/utils/initial.js b/web/web/src/lib/utils/initial.js
index db6334b4be..edc760eb44 100644
--- a/web/web/src/lib/utils/initial.js
+++ b/web/web/src/lib/utils/initial.js
@@ -255,6 +255,54 @@ export const providers = [
       }
     ]
   },
+  {
+    label: 'Google BigQuery',
+    value: 'jdbc-bigquery',
+    defaultProps: [
+      {
+        key: 'project-id',
+        value: '',
+        required: true,
+        description: 'Google Cloud Project ID'
+      },
+      {
+        key: 'jdbc-driver',
+        value: '',
+        required: true,
+        description: 'e.g. com.simba.googlebigquery.jdbc42.Driver'
+      },
+      {
+        key: 'jdbc-url',
+        value: '',
+        required: true,
+        description: 'e.g. 
jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443'
+      },
+      {
+        key: 'jdbc-user',
+        value: '',
+        required: true,
+        description: 'Service account email'
+      },
+      {
+        key: 'jdbc-password',
+        value: '',
+        required: true,
+        description: 'Path to service account key file'
+      },
+      {
+        key: 'proxy-host',
+        value: '',
+        required: false,
+        description: 'Proxy server hostname or IP address (optional)'
+      },
+      {
+        key: 'proxy-port',
+        value: '',
+        required: false,
+        description: 'Proxy server port number (required if proxy-host is set)'
+      }
+    ]
+  },
   {
     label: 'Lakehouse Generic',
     value: 'lakehouse-generic',
@@ -525,6 +573,24 @@ const relationalColumnTypeMap = {
     'timestamp',
     'varchar'
   ],
+  'jdbc-bigquery': [
+    'binary',
+    'boolean',
+    'byte',
+    'char',
+    'date',
+    'decimal',
+    'double',
+    'float',
+    'integer',
+    'long',
+    'short',
+    'string',
+    'time',
+    'timestamp',
+    'timestamp_tz',
+    'varchar'
+  ],
   'jdbc-mysql': [
     'binary',
     'byte',

Reply via email to