Skip to content

Commit

Permalink
[apache#2614][apache#2530] Add web UI support for Kafka catalog and a…
Browse files Browse the repository at this point in the history
…dd default page for no data tree
  • Loading branch information
LauraXia123 committed Apr 10, 2024
1 parent abcfa96 commit f0671e4
Show file tree
Hide file tree
Showing 10 changed files with 427 additions and 97 deletions.
152 changes: 97 additions & 55 deletions web/src/app/metalakes/metalake/MetalakeTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useEffect, useRef, useState } from 'react'

import { useRouter } from 'next/navigation'

import { IconButton, Typography } from '@mui/material'
import { IconButton, Typography, Box } from '@mui/material'
import { Tree } from 'antd'

import Icon from '@/components/Icon'
Expand All @@ -23,7 +23,8 @@ import {
setSelectedNodes,
setLoadedNodes,
getTableDetails,
getFilesetDetails
getFilesetDetails,
getTopicDetails
} from '@/lib/store/metalakes'

import { extractPlaceholder } from '@/lib/utils'
Expand Down Expand Up @@ -63,20 +64,33 @@ const MetalakeTree = props => {
const handleClickIcon = (e, nodeProps) => {
e.stopPropagation()

if (nodeProps.data.node === 'table') {
if (store.selectedNodes.includes(nodeProps.data.key)) {
const pathArr = extractPlaceholder(nodeProps.data.key)
const [metalake, catalog, schema, table] = pathArr
dispatch(getTableDetails({ init: true, metalake, catalog, schema, table }))
switch (nodeProps.data.node) {
case 'table': {
if (store.selectedNodes.includes(nodeProps.data.key)) {
const pathArr = extractPlaceholder(nodeProps.data.key)
const [metalake, catalog, schema, table] = pathArr
dispatch(getTableDetails({ init: true, metalake, catalog, schema, table }))
}
break
}
} else if (nodeProps.data.node === 'fileset') {
if (store.selectedNodes.includes(nodeProps.data.key)) {
const pathArr = extractPlaceholder(nodeProps.data.key)
const [metalake, catalog, schema, fileset] = pathArr
dispatch(getFilesetDetails({ init: true, metalake, catalog, schema, fileset }))
case 'fileset': {
if (store.selectedNodes.includes(nodeProps.data.key)) {
const pathArr = extractPlaceholder(nodeProps.data.key)
const [metalake, catalog, schema, fileset] = pathArr
dispatch(getFilesetDetails({ init: true, metalake, catalog, schema, fileset }))
}
break
}
} else {
dispatch(setIntoTreeNodeWithFetch({ key: nodeProps.data.key }))
case 'topic': {
if (store.selectedNodes.includes(nodeProps.data.key)) {
const pathArr = extractPlaceholder(nodeProps.data.key)
const [metalake, catalog, schema, topic] = pathArr
dispatch(getTopicDetails({ init: true, metalake, catalog, schema, topic }))
}
break
}
default:
dispatch(setIntoTreeNodeWithFetch({ key: nodeProps.data.key }))
}
}

Expand Down Expand Up @@ -195,6 +209,22 @@ const MetalakeTree = props => {
<Icon icon={isHover !== nodeProps.data.key ? 'bx:file' : 'mdi:reload'} fontSize='inherit' />
</IconButton>
)
case 'topic':
return (
<IconButton
disableRipple={!store.selectedNodes.includes(nodeProps.data.key)}
size='small'
sx={{ color: '#666' }}
onClick={e => handleClickIcon(e, nodeProps)}
onMouseEnter={e => onMouseEnter(e, nodeProps)}
onMouseLeave={e => onMouseLeave(e, nodeProps)}
>
<Icon
icon={isHover !== nodeProps.data.key ? 'material-symbols:topic-outline' : 'mdi:reload'}
fontSize='inherit'
/>
</IconButton>
)

default:
return <></>
Expand Down Expand Up @@ -225,51 +255,63 @@ const MetalakeTree = props => {

useEffect(() => {
if (store.selectedNodes.length !== 0) {
treeRef.current.scrollTo({ key: store.selectedNodes[0] })
treeRef.current && treeRef.current.scrollTo({ key: store.selectedNodes[0] })
}
}, [store.selectedNodes])
}, [store.selectedNodes, treeRef])

useEffect(() => {
dispatch(setExpandedNodes(store.expandedNodes))
}, [store.metalakeTree, dispatch])

return (
<>
<Tree
ref={treeRef}
rootStyle={{
'& .antTreeTitle': {
width: '100%'
}
}}
treeData={store.metalakeTree}
loadData={onLoadData}
loadedKeys={store.loadedNodes}
selectedKeys={store.selectedNodes}
expandedKeys={store.expandedNodes}
onExpand={onExpand}
onSelect={onSelect}
height={height}
defaultExpandAll
blockNode
showIcon
className={clsx([
'[&_.ant-tree-switcher]:twc-inline-flex',
'[&_.ant-tree-switcher]:twc-justify-center',
'[&_.ant-tree-switcher]:twc-items-center',

'[&_.ant-tree-iconEle]:twc-w-[unset]',
'[&_.ant-tree-iconEle]:twc-inline-flex',
'[&_.ant-tree-iconEle]:twc-items-center',

'[&_.ant-tree-title]:twc-inline-flex',
'[&_.ant-tree-title]:twc-w-[calc(100%-24px)]',
'[&_.ant-tree-title]:twc-text-lg',

'[&_.ant-tree-node-content-wrapper]:twc-inline-flex',
'[&_.ant-tree-node-content-wrapper]:twc-items-center',
'[&_.ant-tree-node-content-wrapper]:twc-leading-[28px]'
])}
data-refer='tree-view'
icon={nodeProps => renderIcon(nodeProps)}
titleRender={nodeData => renderNode(nodeData)}
/>
{store.metalakeTree.length ? (
<Tree
ref={treeRef}
rootStyle={{
'& .antTreeTitle': {
width: '100%'
}
}}
treeData={store.metalakeTree}
loadData={onLoadData}
loadedKeys={store.loadedNodes}
selectedKeys={store.selectedNodes}
expandedKeys={store.expandedNodes}
onExpand={onExpand}
onSelect={onSelect}
height={height}
defaultExpandAll
blockNode
showIcon
className={clsx([
'[&_.ant-tree-switcher]:twc-inline-flex',
'[&_.ant-tree-switcher]:twc-justify-center',
'[&_.ant-tree-switcher]:twc-items-center',

'[&_.ant-tree-iconEle]:twc-w-[unset]',
'[&_.ant-tree-iconEle]:twc-inline-flex',
'[&_.ant-tree-iconEle]:twc-items-center',

'[&_.ant-tree-title]:twc-inline-flex',
'[&_.ant-tree-title]:twc-w-[calc(100%-24px)]',
'[&_.ant-tree-title]:twc-text-lg',

'[&_.ant-tree-node-content-wrapper]:twc-inline-flex',
'[&_.ant-tree-node-content-wrapper]:twc-items-center',
'[&_.ant-tree-node-content-wrapper]:twc-leading-[28px]'
])}
data-refer='tree-view'
icon={nodeProps => renderIcon(nodeProps)}
titleRender={nodeData => renderNode(nodeData)}
/>
) : (
<Box className={`twc-h-full twc-grow twc-flex twc-items-center twc-flex-col twc-justify-center`}>
<Typography sx={{ color: theme => theme.palette.text.primary }} data-refer='no-data'>
No data
</Typography>
</Box>
)}
</>
)
}
Expand Down
29 changes: 22 additions & 7 deletions web/src/app/metalakes/metalake/MetalakeView.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ import {
fetchSchemas,
fetchTables,
fetchFilesets,
fetchTopics,
getMetalakeDetails,
getCatalogDetails,
getSchemaDetails,
getTableDetails,
getFilesetDetails,
getTopicDetails,
setSelectedNodes
} from '@/lib/store/metalakes'

Expand All @@ -40,10 +42,11 @@ const MetalakeView = () => {
type: searchParams.get('type'),
schema: searchParams.get('schema'),
table: searchParams.get('table'),
fileset: searchParams.get('fileset')
fileset: searchParams.get('fileset'),
topic: searchParams.get('topic')
}
if ([...searchParams.keys()].length) {
const { metalake, catalog, type, schema, table, fileset } = routeParams
const { metalake, catalog, type, schema, table, fileset, topic } = routeParams

if (paramsSize === 1 && metalake) {
dispatch(fetchCatalogs({ init: true, page: 'metalakes', metalake }))
Expand All @@ -56,10 +59,18 @@ const MetalakeView = () => {
}

if (paramsSize === 4 && catalog && type && schema) {
if (type === 'fileset') {
dispatch(fetchFilesets({ init: true, page: 'schemas', metalake, catalog, schema }))
} else {
dispatch(fetchTables({ init: true, page: 'schemas', metalake, catalog, schema }))
switch (type) {
case 'relational':
dispatch(fetchTables({ init: true, page: 'schemas', metalake, catalog, schema }))
break
case 'fileset':
dispatch(fetchFilesets({ init: true, page: 'schemas', metalake, catalog, schema }))
break
case 'messaging':
dispatch(fetchTopics({ init: true, page: 'schemas', metalake, catalog, schema }))
break
default:
break
}
dispatch(getSchemaDetails({ metalake, catalog, schema }))
}
Expand All @@ -71,6 +82,10 @@ const MetalakeView = () => {
if (paramsSize === 5 && catalog && schema && fileset) {
dispatch(getFilesetDetails({ init: true, metalake, catalog, schema, fileset }))
}

if (paramsSize === 5 && catalog && schema && topic) {
dispatch(getTopicDetails({ init: true, metalake, catalog, schema, topic }))
}
}

dispatch(
Expand All @@ -81,7 +96,7 @@ const MetalakeView = () => {
routeParams.schema ? `{{${routeParams.schema}}}` : ''
}${routeParams.table ? `{{${routeParams.table}}}` : ''}${
routeParams.fileset ? `{{${routeParams.fileset}}}` : ''
}`
}${routeParams.topic ? `{{${routeParams.topic}}}` : ''}`
]
: []
)
Expand Down
73 changes: 56 additions & 17 deletions web/src/app/metalakes/metalake/rightContent/CreateCatalogDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { yupResolver } from '@hookform/resolvers/yup'

import { groupBy } from 'lodash-es'
import { genUpdates } from '@/lib/utils'
import { providers } from '@/lib/utils/initial'
import { providers, filesetProviders, messagingProviders } from '@/lib/utils/initial'
import { nameRegex, keyRegex } from '@/lib/utils/regex'
import { useSearchParams } from 'next/navigation'

Expand All @@ -45,11 +45,9 @@ const defaultValues = {
type: 'relational',
provider: '',
comment: '',
propItems: providers[0].defaultProps
propItems: []
}

const providerTypeValues = providers.map(i => i.value)

const schema = yup.object().shape({
name: yup
.string()
Expand All @@ -58,8 +56,19 @@ const schema = yup.object().shape({
nameRegex,
'This field must start with a letter or underscore, and can only contain letters, numbers, and underscores'
),
type: yup.mixed().oneOf(['relational', 'fileset']).required(),
provider: yup.mixed().oneOf(providerTypeValues).required(),
type: yup.mixed().oneOf(['relational', 'fileset', 'messaging']).required(),
provider: yup.string().when('type', (type, schema) => {
switch (type) {
case 'relational':
return schema.oneOf(providers.map(i => i.value)).required()
case 'fileset':
return schema.oneOf(filesetProviders.map(i => i.value)).required()
case 'messaging':
return schema.oneOf(messagingProviders.map(i => i.value)).required()
default:
return schema
}
}),
propItems: yup.array().of(
yup.object().shape({
required: yup.boolean(),
Expand Down Expand Up @@ -284,12 +293,22 @@ const CreateCatalogDialog = props => {
}

useEffect(() => {
if (typeSelect === 'fileset') {
setProviderTypes(providers.filter(p => p.value === 'hadoop'))
setValue('provider', 'hadoop')
} else {
setProviderTypes(providers.filter(p => p.value !== 'hadoop'))
setValue('provider', 'hive')
switch (typeSelect) {
case 'relational': {
setProviderTypes(providers)
setValue('provider', 'hive')
break
}
case 'fileset': {
setProviderTypes(filesetProviders)
setValue('provider', 'hadoop')
break
}
case 'messaging': {
setProviderTypes(messagingProviders)
setValue('provider', 'kafka')
break
}
}

// eslint-disable-next-line react-hooks/exhaustive-deps
Expand All @@ -298,16 +317,16 @@ const CreateCatalogDialog = props => {
useEffect(() => {
let defaultProps = []

const providerItemIndex = providers.findIndex(i => i.value === providerSelect)
const providerItemIndex = providerTypes.findIndex(i => i.value === providerSelect)

if (providerItemIndex !== -1) {
defaultProps = providers[providerItemIndex].defaultProps
defaultProps = providerTypes[providerItemIndex].defaultProps

resetPropsFields(providers, providerItemIndex)
resetPropsFields(providerTypes, providerItemIndex)

if (type === 'create') {
setInnerProps(defaultProps)
setValue('propItems', providers[providerItemIndex].defaultProps)
setValue('propItems', providerTypes[providerItemIndex].defaultProps)
}
}

Expand All @@ -324,7 +343,26 @@ const CreateCatalogDialog = props => {
setValue('type', data.type)
setValue('provider', data.provider)

const providerItem = providers.find(i => i.value === data.provider)
let providersItems = []

switch (data.type) {
case 'relational': {
providersItems = providers
break
}
case 'fileset': {
providersItems = filesetProviders
break
}
case 'messaging': {
providersItems = messagingProviders
break
}
}

setProviderTypes(providersItems)

const providerItem = providersItems.find(i => i.value === data.provider)
let propsItems = [...providerItem.defaultProps]

propsItems = propsItems.map((it, idx) => {
Expand Down Expand Up @@ -427,6 +465,7 @@ const CreateCatalogDialog = props => {
>
<MenuItem value={'relational'}>relational</MenuItem>
<MenuItem value={'fileset'}>fileset</MenuItem>
<MenuItem value={'messaging'}>messaging</MenuItem>
</Select>
)}
/>
Expand Down
Loading

0 comments on commit f0671e4

Please sign in to comment.