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

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


The following commit(s) were added to refs/heads/branch-1.2 by this push:
     new 1e6d16b106 [Cherry-pick to branch-1.2] [#10148] fix(web-v2(UI)): 
suport no columns table for creating clickhouse provider (#10153) (#10184)
1e6d16b106 is described below

commit 1e6d16b1068c01662a59d16ddd1d12d26ba93f37
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Wed Mar 4 15:54:32 2026 +0800

    [Cherry-pick to branch-1.2] [#10148] fix(web-v2(UI)): suport no columns 
table for creating clickhouse provider (#10153) (#10184)
    
    **Cherry-pick Information:**
    - Original commit: 94c9f58dad620439ef9ba0e28cdf611a62135cad
    - Target branch: `branch-1.2`
    - Status: ✅ Clean cherry-pick (no conflicts)
    
    Co-authored-by: Qian Xia <[email protected]>
---
 .../app/catalogs/rightContent/CreateTableDialog.js | 166 ++++++++++++++-------
 1 file changed, 111 insertions(+), 55 deletions(-)

diff --git a/web-v2/web/src/app/catalogs/rightContent/CreateTableDialog.js 
b/web-v2/web/src/app/catalogs/rightContent/CreateTableDialog.js
index a15bf07b6d..d9c11e7a7e 100644
--- a/web-v2/web/src/app/catalogs/rightContent/CreateTableDialog.js
+++ b/web-v2/web/src/app/catalogs/rightContent/CreateTableDialog.js
@@ -115,10 +115,17 @@ export default function CreateTableDialog({ ...props }) {
   const [form] = Form.useForm()
   const values = Form.useWatch([], form)
 
+  const isClickHouseDistributedEngine =
+    provider === 'jdbc-clickhouse' &&
+    values?.properties?.find(item => item?.key === 
'engine')?.value?.toLowerCase?.() === 'distributed'
+  const isColumnsRequired = !isClickHouseDistributedEngine
+
   const defaultValues = {
     name: '',
     comment: '',
-    columns: [{ id: '', name: '', typeObj: { type: '' }, required: false, 
comment: '' }],
+    columns: isClickHouseDistributedEngine
+      ? []
+      : [{ id: '', name: '', typeObj: { type: '' }, required: false, comment: 
'' }],
     properties: []
   }
   const supportProperties = getPropInfo(provider).allowAdd
@@ -149,7 +156,20 @@ export default function CreateTableDialog({ ...props }) {
   }
 
   useEffect(() => {
-    const tabs = [...tabOptions]
+    const tabs = [
+      {
+        label: (
+          <span
+            className={cn('font-normal text-[rgb(0,0,0,0.88)]', {
+              'before:mr-0.5 before:font-["SimSun"] before:text-[#ff4d4f] 
before:content-["*"]': isColumnsRequired
+            })}
+          >
+            Columns
+          </span>
+        ),
+        key: 'columns'
+      }
+    ]
     if (partitioningInfo) {
       tabs.push({
         label: <span className='font-normal 
text-[rgb(0,0,0,0.88)]'>Partitions</span>,
@@ -185,7 +205,7 @@ export default function CreateTableDialog({ ...props }) {
       })
     }
     setTabOptions(tabs)
-  }, [provider, partitioningInfo, sortOredsInfo, indexesInfo, 
distributionInfo])
+  }, [isColumnsRequired, provider, partitioningInfo, sortOredsInfo, 
indexesInfo, distributionInfo])
 
   useEffect(() => {
     scrollRef.current && handScroll()
@@ -486,6 +506,24 @@ export default function CreateTableDialog({ ...props }) {
     }
   }, [provider, values?.format])
 
+  useEffect(() => {
+    if (!open || editTable) {
+      return
+    }
+
+    const columns = form.getFieldValue('columns') || []
+
+    if (isClickHouseDistributedEngine && columns.length === 1 && 
!columns[0]?.name && !columns[0]?.typeObj?.type) {
+      form.setFieldValue('columns', [])
+
+      return
+    }
+
+    if (!isClickHouseDistributedEngine && columns.length === 0) {
+      form.setFieldValue('columns', [{ id: '', name: '', typeObj: { type: '' 
}, required: false, comment: '' }])
+    }
+  }, [open, editTable, isClickHouseDistributedEngine, form])
+
   const getColumnType = typeObj => {
     const { type } = typeObj
     if (!ColumnSpesicalType.includes(type)) {
@@ -547,55 +585,57 @@ export default function CreateTableDialog({ ...props }) {
             name: values.name.trim(),
             comment: values.comment,
             tagsToAdd: values.tags,
-            columns: values.columns.map(col => {
-              const column = {
-                uniqueId: col.uniqueId || col.name,
-                name: col.name,
-                type: getColumnType(col.typeObj),
-                nullable: !col.required,
-                comment: col.comment || ''
-              }
-              if (autoIncrementInfo) {
-                column['autoIncrement'] = col.autoIncrement
-              }
-              if (col.defaultValue) {
-                switch (col.defaultValue.type) {
-                  case 'field':
-                    column['defaultValue'] = {
-                      type: 'field',
-                      fieldName: [col.defaultValue?.fieldName]
-                    }
-                    break
-                  case 'function':
-                    column['defaultValue'] = {
-                      type: 'function',
-                      funcName: col.defaultValue?.funcName,
-                      funcArgs: col.defaultValue?.funcArgs.map(f => {
-                        const func = {}
-                        if (f.type === 'literal') {
-                          func['type'] = 'literal'
-                          func['dataType'] = 'string'
-                          func['value'] = f.value
-                        } else {
-                          func['type'] = 'field'
-                          func['fieldName'] = [f.fieldName]
-                        }
+            columns: (values.columns || [])
+              .filter(col => col?.name)
+              .map(col => {
+                const column = {
+                  uniqueId: col.uniqueId || col.name,
+                  name: col.name,
+                  type: getColumnType(col.typeObj),
+                  nullable: !col.required,
+                  comment: col.comment || ''
+                }
+                if (autoIncrementInfo) {
+                  column['autoIncrement'] = col.autoIncrement
+                }
+                if (col.defaultValue) {
+                  switch (col.defaultValue.type) {
+                    case 'field':
+                      column['defaultValue'] = {
+                        type: 'field',
+                        fieldName: [col.defaultValue?.fieldName]
+                      }
+                      break
+                    case 'function':
+                      column['defaultValue'] = {
+                        type: 'function',
+                        funcName: col.defaultValue?.funcName,
+                        funcArgs: col.defaultValue?.funcArgs.map(f => {
+                          const func = {}
+                          if (f.type === 'literal') {
+                            func['type'] = 'literal'
+                            func['dataType'] = 'string'
+                            func['value'] = f.value
+                          } else {
+                            func['type'] = 'field'
+                            func['fieldName'] = [f.fieldName]
+                          }
 
-                        return func
-                      })
-                    }
-                    break
-                  default:
-                    column['defaultValue'] = {
-                      type: 'literal',
-                      dataType: col.defaultValue?.dataType || 'string',
-                      value: col.defaultValue?.value
-                    }
+                          return func
+                        })
+                      }
+                      break
+                    default:
+                      column['defaultValue'] = {
+                        type: 'literal',
+                        dataType: col.defaultValue?.dataType || 'string',
+                        value: col.defaultValue?.value
+                      }
+                  }
                 }
-              }
 
-              return column
-            }),
+                return column
+              }),
             properties:
               values.properties &&
               values.properties.reduce((acc, item) => {
@@ -759,6 +799,7 @@ export default function CreateTableDialog({ ...props }) {
   const renderTableColumns = (fields, subOpt) => {
     const pageSize = 10
     const isShowPagination = fields.length > pageSize
+    const lastPage = Math.max(1, Math.ceil(fields.length / pageSize))
 
     return (
       <div className='flex flex-col divide-y divide-solid border-b 
border-solid'>
@@ -925,16 +966,17 @@ export default function CreateTableDialog({ ...props }) {
                 <div className='px-2 py-1'>
                   <Icons.Minus
                     className={cn('size-4 cursor-pointer text-gray-400 
hover:text-defaultPrimary', {
-                      'text-gray-100 hover:text-gray-200 cursor-not-allowed': 
form.getFieldValue('columns').length === 1
+                      'text-gray-100 hover:text-gray-200 cursor-not-allowed':
+                        form.getFieldValue('columns').length === 1 && 
isColumnsRequired
                     })}
                     onClick={() => {
-                      if (form.getFieldValue('columns').length === 1) return
+                      if (form.getFieldValue('columns').length === 1 && 
isColumnsRequired) return
                       subOpt.remove(subField.name)
                       if (fields.length - 1 === pageOffset * pageSize) {
-                        setPageOffset(pageOffset - 1)
+                        setPageOffset(Math.max(1, pageOffset - 1))
                       } else if (fields.length - 1 < pageOffset * pageSize) {
                         const to = Math.ceil(fields.length / pageSize)
-                        setPageOffset((fields.length - 1) % pageSize === 0 ? 
to - 1 : to)
+                        setPageOffset(Math.max(1, (fields.length - 1) % 
pageSize === 0 ? to - 1 : to))
                       }
                     }}
                   />
@@ -953,7 +995,7 @@ export default function CreateTableDialog({ ...props }) {
             total={fields.length}
           />
         )}
-        {pageOffset === Math.ceil(fields.length / pageSize) && (
+        {(fields.length === 0 || pageOffset === lastPage) && (
           <div className='text-center'>
             <Button
               type='link'
@@ -1328,7 +1370,21 @@ export default function CreateTableDialog({ ...props }) {
                   className={tabKey !== 'columns' ? 'hidden' : ''}
                   label=''
                   name='columns'
-                  rules={[{ required: true }]}
+                  rules={[
+                    {
+                      validator: (_, columns) => {
+                        if (!isColumnsRequired) {
+                          return Promise.resolve()
+                        }
+
+                        if (columns?.length > 0) {
+                          return Promise.resolve()
+                        }
+
+                        return Promise.reject(new Error('At least one column 
is required'))
+                      }
+                    }
+                  ]}
                   help=''
                 >
                   <Form.List name='columns'>{(fields, subOpt) => 
renderTableColumns(fields, subOpt)}</Form.List>

Reply via email to