diff --git a/paimon-web-ui-new/src/api/models/catalog/index.ts b/paimon-web-ui-new/src/api/models/catalog/index.ts index edacc5dc9..204527977 100644 --- a/paimon-web-ui-new/src/api/models/catalog/index.ts +++ b/paimon-web-ui-new/src/api/models/catalog/index.ts @@ -29,4 +29,11 @@ export const getAllCatalogs = () => { return httpRequest.get('/catalog/getAllCatalogs') } +/** + * # Get database by catalog id + */ +export const getDatabasesByCatalogId = (id: number) => { + return httpRequest.get(`/database/getDatabasesByCatalogId/${id}`) +} + // #endregion diff --git a/paimon-web-ui-new/src/store/catalog/index.ts b/paimon-web-ui-new/src/store/catalog/index.ts index 0e5bb55c2..30da5fba5 100644 --- a/paimon-web-ui-new/src/store/catalog/index.ts +++ b/paimon-web-ui-new/src/store/catalog/index.ts @@ -16,26 +16,23 @@ specific language governing permissions and limitations under the License. */ import { NIcon, type TreeOption } from 'naive-ui' -import { FolderOpenOutline } from '@vicons/ionicons5' +import { FileTrayOutline, FolderOutline } from '@vicons/ionicons5' -import { getAllCatalogs, type Catalog } from "@/api/models/catalog" +import { getAllCatalogs, type Catalog } from '@/api/models/catalog' export interface CatalogState { - _catalogs: Catalog[]; + catalogs: TreeOption[]; _catalogLoading: boolean; } export const useCatalogStore = defineStore('catalog', { state: (): CatalogState => ({ - _catalogs: [], + catalogs: [], _catalogLoading: false }), persist: true, getters: { - catalogs: (state): TreeOption[] => { - return transformCatalog(state._catalogs) - }, catalogLoading: (state): boolean => { return state._catalogLoading } @@ -46,22 +43,67 @@ export const useCatalogStore = defineStore('catalog', { this._catalogLoading = true const res = await useAllCatalog() - this._catalogs = res.data + this.catalogs = transformCatalog(res.data) this._catalogLoading = false + }, + getDatabasesByCatalogId(id: number): Promise { + // TODO: fetch database list by catalog id + // Waiting for the deployment of the back end interface + + // const [, useDatabaseByCatalogId] = getDatabasesByCatalogId(id) + // return useDatabaseByCatalogId() + return new Promise((resolve) => { + setTimeout(() => { + resolve([ + { + label: 'database', + type: 'database', + key: ++id, + isLeaf: false, + prefix: () => + h(NIcon, null, { + default: () => h(FolderOutline) + }), + } + ]) + }, 1000) + }) + }, + getTablesByDataBaseId(id: number): Promise { + // TODO: fetch table list by catalog id and database name + // Waiting for the deployment of the back end interface + + // const [, useDatabaseByCatalogId] = getDatabasesByCatalogId(id) + // return useDatabaseByCatalogId() + return new Promise((resolve) => { + setTimeout(() => { + resolve([ + { + label: 'table', + type: 'table', + key: ++id, + isLeaf: true, + prefix: () => + h(NIcon, null, { + default: () => h(FileTrayOutline) + }), + } + ]) + }, 1000) + }) } } }) const transformCatalog = (catalogs: Catalog[]): TreeOption[] => { return catalogs.map(catalog => ({ - label: catalog.name, - type: catalog.type, + label: catalog.name || 'paimon', + type: catalog.type || 'catalog', key: catalog.id, isLeaf: false, - children: [], prefix: () => h(NIcon, null, { - default: () => h(FolderOpenOutline) + default: () => h(FolderOutline) }), })) } diff --git a/paimon-web-ui-new/src/views/metadata/components/menu-tree/index.tsx b/paimon-web-ui-new/src/views/metadata/components/menu-tree/index.tsx index 7e17e4c4d..461f4a97b 100644 --- a/paimon-web-ui-new/src/views/metadata/components/menu-tree/index.tsx +++ b/paimon-web-ui-new/src/views/metadata/components/menu-tree/index.tsx @@ -15,7 +15,8 @@ KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import { Search } from '@vicons/ionicons5' +import { Add, FolderOutline, FolderOpenOutline, Search } from '@vicons/ionicons5' +import { NButton, NIcon, type TreeOption } from 'naive-ui'; import { useCatalogStore } from '@/store/catalog' @@ -42,22 +43,64 @@ export default defineComponent({ }, ] - const nodeProps = () => { - return { - onClick () { - }, + const updatePrefixWithExpanded = ( + _keys: Array, + _option: Array, + meta: { + node: TreeOption | null + action: 'expand' | 'collapse' | 'filter' } + ) => { + if (!meta.node) return + switch (meta.action) { + case 'expand': + meta.node.prefix = () => + h(NIcon, null, { + default: () => h(FolderOpenOutline) + }) + break + case 'collapse': + meta.node.prefix = () => + h(NIcon, null, { + default: () => h(FolderOutline) + }) + break + } + } + + const renderSuffix = ({ option }: { option: TreeOption }) => { + return option.type !== 'table' ? h(NButton, { + quaternary: true, + circle: true, + size: 'tiny', + onClick: (e) => { + e.stopPropagation() + } + }, { + default: () => h(NIcon, null, { + default: () => h(Add) + }) + }) : undefined } onMounted(catalogStore.getAllCatalogs) + const onLoadMenu = async (node: TreeOption) => { + const loadFn = node.type === 'catalog' ? catalogStore.getDatabasesByCatalogId : catalogStore.getTablesByDataBaseId + node.children = await loadFn(node.key as number) + + return Promise.resolve() + } + return { menuLoading: catalogStoreRef.catalogLoading, menuList: catalogStoreRef.catalogs, dropdownMenu, filterValue, t, - nodeProps, + onLoadMenu, + updatePrefixWithExpanded, + renderSuffix } }, render() { @@ -65,6 +108,14 @@ export default defineComponent({
+ +
Catalog
+ + + + + +
{}} + renderSuffix={this.renderSuffix} + onUpdate:expandedKeys={this.updatePrefixWithExpanded} + onLoad={this.onLoadMenu} data={this.menuList} pattern={this.filterValue} - node-props={this.nodeProps} />