[fix](ui) fix database cannot be choosed bug (#32091)

This commit is contained in:
Jeffrey
2024-03-12 22:56:59 +08:00
committed by yiguolei
parent 6d2924668e
commit 5539f85fec
4 changed files with 172 additions and 123 deletions

View File

@ -6,9 +6,9 @@
* 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
@ -16,23 +16,23 @@
* specific language governing permissions and limitations
* under the License.
*/
/**
* @file test cron
* @author lpx
* @since 2020/08/19
*/
import React, {useState} from 'react';
import {Layout, Menu, Dropdown, notification, Button} from 'antd';
import { CaretDownOutlined, LogoutOutlined} from '@ant-design/icons';
import {renderRoutes} from 'react-router-config';
import {useHistory} from 'react-router-dom';
import {useTranslation} from 'react-i18next';
import React, { useState } from 'react';
import { Layout, Menu, Dropdown, notification, Button } from 'antd';
import { CaretDownOutlined, LogoutOutlined } from '@ant-design/icons';
import { renderRoutes } from 'react-router-config';
import { useHistory } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import routes from 'Src/router';
import {logOut} from 'Src/api/api';
import { logOut } from 'Src/api/api';
import './index.css';
import styles from './index.less';
const {Header, Content, Footer} = Layout;
const { Header, Content, Footer } = Layout;
function Layouts(props: any) {
let { t } = useTranslation();
const [route, setRoute] = useState(props.route.routes);
@ -48,7 +48,7 @@ function Layouts(props: any) {
if (location.pathname === e.key) {
location.reload();
}
if(location.pathname.includes('Playground')){
if (location.pathname.includes('Playground')) {
history.push(e.key);
location.reload();
}
@ -59,52 +59,74 @@ function Layouts(props: any) {
}
function clearAllCookie() {
var keys = document.cookie.match(/[^ =;]+(?=\=)/g);
if(keys) {
for(var i = keys.length; i--;)
document.cookie = keys[i] + '=0;expires=' + new Date(0).toUTCString()
if (keys) {
for (var i = keys.length; i--; )
document.cookie =
keys[i] + '=0;expires=' + new Date(0).toUTCString();
}
}
function onLogout(){
logOut().then((res)=>{
localStorage.setItem('username','');
function onLogout() {
logOut().then((res) => {
localStorage.removeItem('username');
clearAllCookie();
notification.success({message: t('exitSuccessfully')})
notification.success({ message: t('exitSuccessfully') });
history.push('/login');
})
});
}
function changeLanguage(){
if (localStorage.getItem('I18N_LANGUAGE') === 'zh-CN'){
localStorage.setItem('I18N_LANGUAGE','en');
location.reload()
function changeLanguage() {
if (localStorage.getItem('I18N_LANGUAGE') === 'zh-CN') {
localStorage.setItem('I18N_LANGUAGE', 'en');
location.reload();
} else {
localStorage.setItem('I18N_LANGUAGE','zh-CN');
location.reload()
localStorage.setItem('I18N_LANGUAGE', 'zh-CN');
location.reload();
}
}
const menu = (
<Menu>
<Menu.Item onClick={onLogout}>
<LogoutOutlined style={{marginRight: 8}}/>
<LogoutOutlined style={{ marginRight: 8 }} />
{t('signOut')}
</Menu.Item>
</Menu>
);
return (
<Layout>
<Header style={{position: 'fixed', zIndex: 99, width: '100%'}}>
<div className={styles['logo']} onClick={()=>{history.replace('/home');setCurrent('')}}></div>
<span className='userSet'>
<Button style={{'color':'#000'}} type="text" size='small' onClick={changeLanguage}>{localStorage.getItem('I18N_LANGUAGE') === 'zh-CN' ? 'English' : '中文'}</Button>
<Header style={{ position: 'fixed', zIndex: 99, width: '100%' }}>
<div
className={styles['logo']}
onClick={() => {
history.replace('/home');
setCurrent('');
}}
></div>
<span className="userSet">
<Button
style={{ color: '#000' }}
type="text"
size="small"
onClick={changeLanguage}
>
{localStorage.getItem('I18N_LANGUAGE') === 'zh-CN'
? 'English'
: '中文'}
</Button>
<Dropdown overlay={menu}>
<span className="ant-dropdown-link">
{/* <img alt="" className='avatar' src=''/> */}
{localStorage.getItem('username')} <CaretDownOutlined/>
{localStorage.getItem('username')}{' '}
<CaretDownOutlined />
</span>
</Dropdown>
</span>
<Menu theme="light" onClick={handleClick} selectedKeys={[current]} mode="horizontal">
{routes?.routes[1]?.routes?.map(item => {
if (item.title !== 'Login'&&item.title !== 'Home') {
<Menu
theme="light"
onClick={handleClick}
selectedKeys={[current]}
mode="horizontal"
>
{routes?.routes[1]?.routes?.map((item) => {
if (item.title !== 'Login' && item.title !== 'Home') {
return (
<Menu.Item key={item.path}>
{item.title}
@ -115,19 +137,22 @@ function Layouts(props: any) {
</Menu>
</Header>
<Content className="site-layout" style={{marginTop: 64}}>
<div className="site-layout-background" style={{minHeight: 380}}>
<Content className="site-layout" style={{ marginTop: 64 }}>
<div
className="site-layout-background"
style={{ minHeight: 380 }}
>
{renderRoutes(route)}
</div>
</Content>
{/* <Footer style={{textAlign: 'center'}}>xxx</Footer> */}
</Layout>
);
}
export default Layouts;/**
export default Layouts;
/**
* 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
@ -135,9 +160,9 @@ export default Layouts;/**
* 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
@ -145,4 +170,3 @@ export default Layouts;/**
* specific language governing permissions and limitations
* under the License.
*/

View File

@ -16,15 +16,15 @@
* specific language governing permissions and limitations
* under the License.
*/
import React, {useEffect, useState} from 'react';
import {Input, Spin, Tree} from 'antd';
import {HddOutlined, ReloadOutlined, TableOutlined} from '@ant-design/icons';
import {AdHocAPI} from 'Src/api/api';
import {useTranslation} from 'react-i18next';
import {AdhocContentRouteKeyEnum,} from '../adhoc.data';
import React, { useEffect, useState } from 'react';
import { Input, Spin, Tree } from 'antd';
import { HddOutlined, ReloadOutlined, TableOutlined } from '@ant-design/icons';
import { AdHocAPI } from 'Src/api/api';
import { useTranslation } from 'react-i18next';
import { AdhocContentRouteKeyEnum } from '../adhoc.data';
import './index.css';
const {Search} = Input;
const { Search } = Input;
interface DataNode {
title: string;
@ -36,7 +36,7 @@ interface DataNode {
const initTreeDate: DataNode[] = [];
function updateTreeData(list: DataNode[], key, children) {
return list.map(node => {
return list.map((node) => {
if (node.key === key) {
return {
...node,
@ -48,7 +48,7 @@ function updateTreeData(list: DataNode[], key, children) {
}
export function AdHocTree(props: any) {
let {t} = useTranslation();
let { t } = useTranslation();
const [treeData, setTreeData] = useState(initTreeDate);
const [realTree, setRealTree] = useState(initTreeDate);
const [loading, setLoading] = useState(true);
@ -62,38 +62,41 @@ export function AdHocTree(props: any) {
}, []);
function initTreeData(ac?: AbortController) {
AdHocAPI.getDatabaseList({signal: ac?.signal}).then(res => {
if (res.msg === 'success' && Array.isArray(res.data)) {
const num = Math.random()
const treeData = res.data.map((item, index) => {
return {
title: item,
key: `${num}-1-${index}-${item}`,
icon: <HddOutlined/>,
};
});
setTreeData(treeData);
getRealTree(treeData);
}
setLoading(false);
}).catch(err => {
});
AdHocAPI.getDatabaseList({ signal: ac?.signal })
.then((res) => {
if (res.msg === 'success' && Array.isArray(res.data)) {
const num = Math.random();
const treeData = res.data.map((item, index) => {
return {
title: item,
keys: [item],
key: `${num}-1-${index}-${item}`,
icon: <HddOutlined />,
};
});
setTreeData(treeData);
getRealTree(treeData);
}
setLoading(false);
})
.catch((err) => {});
}
function onLoadData({key, children}) {
function onLoadData({ key, children }) {
const [, storey, , db_name] = key.split('-');
const param = {
db_name,
// tbl_name,
};
return AdHocAPI.getDatabaseList(param).then(res => {
return AdHocAPI.getDatabaseList(param).then((res) => {
if (res.msg == 'success' && Array.isArray(res.data)) {
const children = res.data.map((item, index) => {
if (storey === '1') {
return {
title: item,
keys: [param.db_name, item],
key: `2-${index}-${param.db_name}-${item}`,
icon: <TableOutlined/>,
icon: <TableOutlined />,
isLeaf: true,
};
}
@ -108,23 +111,24 @@ export function AdHocTree(props: any) {
function handleTreeSelect(
keys: React.ReactText[],
info: any,
path: AdhocContentRouteKeyEnum = AdhocContentRouteKeyEnum.Result,
path: AdhocContentRouteKeyEnum = AdhocContentRouteKeyEnum.Result
) {
if (keys.length > 0) {
props.history.push(`/Playground/${path}/${keys[0].split(':')[1]}`);
console.log(info);
const tablePath = info.node.keys.join('-');
if (info.node.keys.length > 0) {
props.history.push(`/Playground/${path}/${tablePath}`);
}
}
function onSearch(e) {
const {value} = e.target;
const expandedKeys: any[] = treeData
.map((item, index) => {
if (getParentKey(value, treeData[index].children, index)) {
return item.key
} else {
return null;
}
})
const { value } = e.target;
const expandedKeys: any[] = treeData.map((item, index) => {
if (getParentKey(value, treeData[index].children, index)) {
return item.key;
} else {
return null;
}
});
setExpandedKeys(expandedKeys);
setAutoExpandParent(true);
getRealTree(treeData, value);
@ -142,9 +146,11 @@ export function AdHocTree(props: any) {
for (let i = 0; i < tree.length; i++) {
const node = tree[i];
if (node.title.includes(key)) {
return true
return true;
} else {
treeData[idx].children ? treeData[idx].children[i].title = node.title : ''
treeData[idx].children
? (treeData[idx].children[i].title = node.title)
: '';
}
}
return false;
@ -154,7 +160,7 @@ export function AdHocTree(props: any) {
const realTree = inner(treeData);
function inner(treeData) {
return treeData.map(item => {
return treeData.map((item) => {
const search = value || '';
const index = item.title.indexOf(search);
const beforeStr = item.title.substr(0, index);
@ -162,19 +168,21 @@ export function AdHocTree(props: any) {
const title =
index > -1 ? (
<span>
{beforeStr}
<span className="site-tree-search-value">{search}</span>
{beforeStr}
<span className="site-tree-search-value">
{search}
</span>
{afterStr}
</span>
</span>
) : (
item.title
);
if (item.children) {
return {...item, title, children: inner(item.children)};
return { ...item, title, children: inner(item.children) };
}
return {
...item,
title
title,
};
});
}
@ -185,29 +193,35 @@ export function AdHocTree(props: any) {
function debounce(fn, wait) {
let timer = null;
return function () {
let context = this
let args = arguments
let context = this;
let args = arguments;
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(function () {
fn.apply(context, args)
}, wait)
}
fn.apply(context, args);
}, wait);
};
}
return (
<>
<Spin spinning={loading} size="small"/>
<Spin spinning={loading} size="small" />
<div>
<Search
size="small"
style={{padding: 5, position: 'fixed', zIndex: '99', width: '300px'}}
style={{
padding: 5,
position: 'fixed',
zIndex: '99',
width: '300px',
}}
placeholder={t('search')}
enterButton={<ReloadOutlined/>}
enterButton={<ReloadOutlined />}
onSearch={initTreeData}
onChange={onSearch}/>
onChange={onSearch}
/>
</div>
<Tree
@ -217,16 +231,20 @@ export function AdHocTree(props: any) {
onExpand={onExpand}
expandedKeys={expandedKeys}
autoExpandParent={autoExpandParent}
style={{'width': '100%', height: '86vh', paddingTop: '35px', overflowY: 'scroll'}}
style={{
width: '100%',
height: '86vh',
paddingTop: '35px',
overflowY: 'scroll',
}}
onSelect={(selectedKeys, info) =>
handleTreeSelect(
selectedKeys,
info,
AdhocContentRouteKeyEnum.Structure)
AdhocContentRouteKeyEnum.Structure
)
}
/>
</>
);
}

View File

@ -6,9 +6,9 @@
* 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
@ -16,15 +16,15 @@
* specific language governing permissions and limitations
* under the License.
*/
import React from 'react';
import { Route, Redirect, Switch } from 'react-router-dom';
import {getBasePath} from 'Src/utils/utils';
import { checkLogin, getBasePath } from 'Src/utils/utils';
let isLogin = document.cookie;
let isLogin = checkLogin();
const renderRoutes = (routes, authPath = '/login') => {
let basepath = getBasePath();
if(routes){
if (routes) {
return (
<Switch>
{routes.map((route, i) => (
@ -33,28 +33,27 @@ const renderRoutes = (routes, authPath = '/login') => {
path={route.path}
exact={route.exact}
strict={route.strict}
render= { props =>{
if(props.location.pathname === basepath+'/'){
return <Redirect to={"/home"} />;
render={(props) => {
if (props.location.pathname === basepath + '/') {
return <Redirect to={'/home'} />;
}
if (isLogin) {
return route.render ? (
route.render({ ...props, route: route })
) : (
<route.component {...props} route={route} />
)
route.render({ ...props, route: route })
) : (
<route.component {...props} route={route} />
);
} else {
isLogin = '1';
return <Redirect to={authPath} />;
}}
}
}
}}
/>
))}
</Switch>
)
);
}
return null
}
return null;
};
export default renderRoutes;

View File

@ -92,4 +92,12 @@ function replaceToTxt(str: string) {
return strNoBr;
}
export {isSuccess, getDbName, getTimeNow, getBasePath, replaceToTxt};
function checkLogin() {
const username = localStorage.getItem('username');
if (username) {
return true;
}
return false;
}
export {isSuccess, getDbName, getTimeNow, getBasePath, replaceToTxt, checkLogin};