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

nicholasjiang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/paimon-webui.git


The following commit(s) were added to refs/heads/main by this push:
     new ca456f4  [Feature] Support dynamic menu tree integration with query 
page (#236)
ca456f4 is described below

commit ca456f4dcad17ede406047330bbf1777d158dfe4
Author: s7monk <[email protected]>
AuthorDate: Wed May 22 21:30:59 2024 +0800

    [Feature] Support dynamic menu tree integration with query page (#236)
---
 .../query/components/menu-tree/index.module.scss   |  34 ++-
 .../query/components/menu-tree/index.tsx           | 258 ++++++++++++++-------
 2 files changed, 201 insertions(+), 91 deletions(-)

diff --git 
a/paimon-web-ui/src/views/playground/components/query/components/menu-tree/index.module.scss
 
b/paimon-web-ui/src/views/playground/components/query/components/menu-tree/index.module.scss
index 536333a..7e692a9 100644
--- 
a/paimon-web-ui/src/views/playground/components/query/components/menu-tree/index.module.scss
+++ 
b/paimon-web-ui/src/views/playground/components/query/components/menu-tree/index.module.scss
@@ -18,16 +18,42 @@ under the License. */
 .container {
   width: 100%;
   height: 100%;
+  box-sizing: border-box;
 
   .card {
     height: 100%;
 
-    .search {
+    .vertical {
       display: flex;
-    }
+      flex-direction: column;
+      height: 100%;
+      gap: 8px;
 
-    .icon {
-      display: flex;
+      .search {
+        display: flex;
+      }
+
+      .icon {
+        display: flex;
+      }
+
+      .scroll {
+        position: relative;
+        flex: 1;
+      }
+
+      .detail-container {
+        height: 45%;
+        margin-left: -18px;
+        margin-right: -18px;
+
+        .detail-vertical {
+          display: flex;
+          flex-direction: column;
+          height: 100%;
+          gap: 2px;
+        }
+      }
     }
   }
 }
diff --git 
a/paimon-web-ui/src/views/playground/components/query/components/menu-tree/index.tsx
 
b/paimon-web-ui/src/views/playground/components/query/components/menu-tree/index.tsx
index 552a78b..333069e 100644
--- 
a/paimon-web-ui/src/views/playground/components/query/components/menu-tree/index.tsx
+++ 
b/paimon-web-ui/src/views/playground/components/query/components/menu-tree/index.tsx
@@ -15,78 +15,59 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License. */
 
-import { CodeSlash, FileTrayFullOutline, Search, ServerOutline } from 
'@vicons/ionicons5';
+import {CloseSharp, CodeSlash, FileTrayFullOutline, Search, ServerOutline} 
from '@vicons/ionicons5';
+import { useCatalogStore } from '@/store/catalog'
 import styles from './index.module.scss'
 import { NIcon, type TreeOption } from 'naive-ui';
+import {DatabaseOutlined} from "@vicons/antd";
+import type { DataTypeDTO } from "@/api/models/catalog";
+import {getColumns} from "@/api/models/catalog";
 
 export default defineComponent({
   name: 'MenuTree',
   setup() {
     const { t } = useLocaleHooks()
 
-    const treeVariables = reactive({
-      treeData: [
-        {
-          key: 'paimon',
-          label: 'paimon',
-          prefix: () =>
-            h(NIcon, null, {
-              default: () => h(ServerOutline)
-            }),
-          children: [
-            {
-              key: 'user',
-              label: 'user',
-              prefix: () =>
-                h(NIcon, null, {
-                  default: () => h(ServerOutline)
-                }),
-              children: [
-                {
-                  label: 'user_table',
-                  key: '1',
-                  content: 'select * from abc where abc.a="abc";select * from 
cba where cba.a="cba";',
-                  prefix: () =>
-                    h(NIcon, null, {
-                      default: () => h(FileTrayFullOutline)
-                    })
-                },
-                {
-                  label: 'people_table',
-                  key: '2',
-                  content: 'select * from abc where abc.a="abc";',
-                  prefix: () =>
-                    h(NIcon, null, {
-                      default: () => h(FileTrayFullOutline)
-                    })
-                }
-              ]
-            },
-            {
-              key: 'role',
-              label: 'role',
-              prefix: () =>
-                h(NIcon, null, {
-                  default: () => h(ServerOutline)
-                }),
-              children: [
-                {
-                  label: 'user_table',
-                  key: '3',
-                  content: 'select * from kkk;',
-                  prefix: () =>
-                    h(NIcon, null, {
-                      default: () => h(FileTrayFullOutline)
-                    })
-                },
-              ]
-            }
-          ]
+    const catalogStore = useCatalogStore()
+    const catalogStoreRef = storeToRefs(catalogStore)
+    const [tableColumns, useColumns, { loading }] = getColumns()
+
+    const filterValue = ref('')
+    const selectedKeys = ref([])
+
+    const renderPrefix = ({ option }: { option: TreeOption }) => {
+      let icon = ServerOutline
+      switch (option.type) {
+        case 'catalog':
+          icon = DatabaseOutlined
+          break
+        case 'database':
+          icon = ServerOutline
+          break
+        case 'table':
+          icon = FileTrayFullOutline
+      }
+
+      return h(NIcon, null, {
+        default: () => h(icon)
+      })
+    }
+
+    const onLoadMenu = async (node: TreeOption) => {
+      if (node.type === 'catalog') {
+        node.children = await catalogStore.getDatabasesById(node.key as number)
+      } else {
+        const [catalogId, catalogName, databaseName] = (node.key as 
string)?.split(' ') || []
+        const params = {
+          catalogId: Number(catalogId),
+          catalogName,
+          databaseName
         }
-      ],
-      filterValue: '',
-      selectedKeys: []
-    })
+        node.children = (await catalogStore.getTablesByDataBaseId(params)) || 
[]
+      }
+
+      return Promise.resolve()
+    }
 
     const nodeProps = ({ option }: { option: TreeOption }) => {
       return {
@@ -107,9 +88,25 @@ export default defineComponent({
       }
     }
 
-    const handleTreeSelect = (value: never[], option: { children: any; }[]) => 
{
-      if (option[0]?.children) return
-      treeVariables.selectedKeys = value
+    const dataNodeProps = ({ option }: { option: TreeOption }) => {
+      return {
+        onClick () {
+          const { type } = option
+          if (type === 'table') {
+            isDetailVisible.value = true
+            const { catalogId, name, ...tableData } = 
JSON.parse(option.key?.toString() || '')
+            catalogStore.setCurrentTable({
+              catalogId: Number(catalogId),
+              tableName: name,
+              name,
+              ...tableData
+            })
+          }
+        },
+      }
+    }
+
+    const handleTreeSelect = ({ option }: { option: TreeOption }) => {
     }
 
     // mitt - handle tab choose
@@ -161,43 +158,130 @@ export default defineComponent({
       }
     ]) as any
 
+    const isDetailVisible = ref(true);
+    const handleClose = () => {
+      isDetailVisible.value = !isDetailVisible.value;
+    }
+
+    const onFetchData = async () => {
+      if (catalogStore.currentTable && 
Object.keys(catalogStore.currentTable).length > 0) {
+        useColumns({
+          params: catalogStore.currentTable
+        })
+      }
+    }
+
+    watch(() => catalogStore.currentTable, onFetchData)
+
     onMounted(() => {
-      mittBus.emit('initTreeData', treeVariables)
+      catalogStore.getAllCatalogs(true)
     })
 
+    onMounted(onFetchData)
+
+    const columns = computed(() => tableColumns.value?.columns || []);
+
+    const getTypePrefix = (dataType: DataTypeDTO) => {
+      const numericTypes = ['INT', 'BIGINT', 'FLOAT', 'DOUBLE', 'DECIMAL', 
'NUMERIC'];
+      const type = dataType.type || 'Unknown';
+      if (numericTypes.includes(type)) {
+        return { prefix: '123', color: '#33994A' };
+      } else {
+        return { prefix: 'Aa'};
+      }
+    }
+
     return {
       t,
-      ...toRefs(treeVariables),
+      filterValue,
+      menuList: catalogStoreRef.catalogs,
+      onLoadMenu,
       nodeProps,
+      dataNodeProps,
       handleTreeSelect,
+      renderPrefix,
+      handleClose,
       savedQueryList,
-      recordList
+      recordList,
+      currentTable: catalogStoreRef.currentTable,
+      columns,
+      isDetailVisible,
+      selectedKeys,
+      getTypePrefix
     }
   },
   render() {
     return (
       <div class={styles.container}>
         <n-card class={styles.card} content-style={'padding:7px 18px;'}>
-          <n-tabs default-value="data" justify-content="space-between" 
type="line">
-            <n-tab-pane name="data" tab={this.t('playground.data')}>
-              <n-space vertical>
-                <n-input placeholder={this.t('playground.search')} 
style="width: 100%;"
-                  v-model:value={this.filterValue}
-                  v-slots={{
-                    prefix: () => <n-icon component={Search} />
-                  }}
+          <n-tabs default-value="data" justify-content="space-between" 
type="line" style={'height: 100%'}>
+            <n-tab-pane name="data" tab={this.t('playground.data')} 
style={'height: 100%'}>
+              <div class={styles.vertical}>
+                <n-input placeholder={this.t('playground.search')}
+                         v-model:value={this.filterValue}
+                         v-slots={{
+                           prefix: () => <n-icon component={Search} />
+                         }}
                 >
                 </n-input>
-                <n-tree
-                  block-line
-                  expand-on-click
-                  selected-keys={this.selectedKeys}
-                  on-update:selected-keys={this.handleTreeSelect}
-                  data={this.treeData}
-                  pattern={this.filterValue}
-                  node-props={this.nodeProps}
-                />
-              </n-space>
+                <div class={styles.scroll}>
+                  <n-scrollbar style={'position: absolute'}>
+                    <n-tree
+                      block-line
+                      expand-on-click
+                      selected-keys={this.selectedKeys}
+                      on-update:selected-keys={this.handleTreeSelect}
+                      data={this.menuList}
+                      pattern={this.filterValue}
+                      node-props={this.dataNodeProps}
+                      onLoad={this.onLoadMenu}
+                      render-prefix={this.renderPrefix}
+                    />
+                  </n-scrollbar>
+                </div>
+                { this.isDetailVisible && this.currentTable && (
+                  <div class={styles['detail-container']}>
+                    <n-card style={'border-radius: 0; height: 100%; 
border-width: 1.4px 0px 0px 0px;'}
+                            content-style={'padding:0;'} >
+                      <div class={styles['detail-vertical']}>
+                        <n-card style={'border: none;'} 
content-style={'padding:16px 16px;'}>
+                          <n-space justify="space-between">
+                            <span>{this.currentTable.tableName}</span>
+                            <n-button
+                              text
+                              onClick={this.handleClose}
+                              v-slots={{
+                                icon: () => <n-icon 
component={CloseSharp}></n-icon>
+                              }}
+                            >
+                            </n-button>
+                          </n-space>
+                        </n-card>
+                        <n-card style={'border: none; flex:1;'} 
content-style={'padding:0px 22px;'}>
+                          <div style={'height: 100%; position: relative;'}>
+                            <n-scrollbar style={'position: absolute;'}>
+                              <n-space vertical>
+                                {this.columns.map((column, index) => (
+                                  <n-space key={index} justify="space-between">
+                                    <div style={{ display: 'flex', alignItems: 
'center' }}>
+                                      <div style={{ width: '24.7px', 
textAlign: 'right', marginRight: '10px',
+                                        color: 
this.getTypePrefix(column.dataType || { type: 'Unknown' }).color }}>
+                                        {this.getTypePrefix(column.dataType || 
{ type: 'Unknown' }).prefix}
+                                      </div>
+                                      <span>{column.field}</span>
+                                    </div>
+                                    <span>{typeof column.dataType === 'object' 
? column.dataType.type : column.dataType}</span>
+                                  </n-space>
+                                ))}
+                              </n-space>
+                            </n-scrollbar>
+                          </div>
+                        </n-card>
+                      </div>
+                    </n-card>
+                  </div>
+                )}
+              </div>
             </n-tab-pane>
             <n-tab-pane name="saved_query" 
tab={this.t('playground.saved_query')}>
               <n-space vertical>

Reply via email to