You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2023/01/10 15:49:45 UTC

[doris] 01/04: fix(ui): 1. fix component/table can not change pageSize,affect system/query profile/session page etc. (#15533)

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

morningman pushed a commit to branch branch-1.2-lts
in repository https://gitbox.apache.org/repos/asf/doris.git

commit 221149e5900683767ab668d3a7b404b564754b8a
Author: htyoung <ht...@hotmail.com>
AuthorDate: Mon Jan 9 08:46:18 2023 +0800

    fix(ui): 1. fix component/table can not change pageSize,affect system/query profile/session page etc. (#15533)
    
    2. add antd Table Component missing rowKey property to fit react specification
    2. fix system/query profile/session/configuration page maybe lead memory leak when switch these pages fast
    3.other grammar fix to fit typescript and react specification
    
    Co-authored-by: tongyang.hty <ha...@douyu.tv>
---
 ui/src/api/api.ts                                  |  64 +++++---
 ui/src/components/table/index.tsx                  |  48 +++---
 ui/src/i18n.tsx                                    |  15 +-
 ui/src/pages/configuration/index.tsx               |  37 +++--
 ui/src/pages/logs/index.tsx                        |  56 ++++---
 .../playground/content/components/data-prev.tsx    |  85 ++++++-----
 ui/src/pages/playground/page-side/index.tsx        |  20 +--
 ui/src/pages/playground/tree/index.tsx             | 164 +++++++++++----------
 ui/src/pages/query-profile/index.tsx               |  80 +++++-----
 ui/src/pages/session/index.tsx                     |  45 +++---
 ui/src/pages/system/index.tsx                      |  61 ++++----
 ui/src/utils/lazy.tsx                              |  17 ++-
 ui/src/utils/utils.ts                              |  37 ++---
 ui/tsconfig.json                                   |  94 ++++++------
 14 files changed, 442 insertions(+), 381 deletions(-)

diff --git a/ui/src/api/api.ts b/ui/src/api/api.ts
index 935958b3d3..083e44d790 100644
--- a/ui/src/api/api.ts
+++ b/ui/src/api/api.ts
@@ -18,35 +18,41 @@
 import {API_BASE} from 'Constants';
 import request from 'Utils/request';
 import {Result} from '@src/interfaces/http.interface';
+
 //login
 export function login<T>(data: any): Promise<Result<T>> {
     return request('/rest/v1/login', {
         method: 'POST',
-        headers:{Authorization: data.password?`Basic ${btoa(data.username+':'+data.password)}`:`Basic ${btoa(data.username+':')}`},
+        headers: {Authorization: data.password ? `Basic ${btoa(data.username + ':' + data.password)}` : `Basic ${btoa(data.username + ':')}`},
     });
 }
+
 //logout
 export function logOut<T>(): Promise<Result<T>> {
-    return request(`/rest/v1/logout`,{
+    return request(`/rest/v1/logout`, {
         method: 'POST',
     });
 }
+
 //home
 export function getHardwareInfo<T>(): Promise<Result<T>> {
-    return request(`/rest/v1/hardware_info/fe/`,{
+    return request(`/rest/v1/hardware_info/fe/`, {
         method: 'GET',
     });
 }
+
 //system
 export function getSystem<T>(data: any): Promise<Result<T>> {
-    return request(`/rest/v1/system${data.path}`,{
+    return request(`/rest/v1/system${data.path}`, {
         method: 'GET',
+        ...data
     });
 }
+
 //log
 export function getLog<T>(data: any): Promise<Result<T>> {
     let localUrl = '/rest/v1/log';
-    if(data.add_verbose){
+    if (data.add_verbose) {
         localUrl = `/rest/v1/log?add_verbose=${data.add_verbose}`;
     }
     if (data.del_verbose) {
@@ -55,71 +61,81 @@ export function getLog<T>(data: any): Promise<Result<T>> {
     // if (data.add_verbose && data.del_verbose) {
     //     localUrl += `/rest/v1/log?add_verbose=${data.add_verbose}&&del_verbose=${data.del_verbose}`;
     // }
-    return request(localUrl,{
-        method: (data.add_verbose || data.del_verbose)?'POST':'GET',
+    return request(localUrl, {
+        method: (data.add_verbose || data.del_verbose) ? 'POST' : 'GET',
+        ...data
     });
 }
+
 //query_profile
 export function queryProfile<T>(data: any): Promise<Result<T>> {
     let LocalUrl = '/rest/v1/query_profile/';
-    if(data.path){
+    if (data.path) {
         LocalUrl = `/rest/v1/query_profile/${data.path}`;
     }
-    return request(LocalUrl);
+    return request(LocalUrl, data);
 }
+
 //session
 export function getSession<T>(data: any): Promise<Result<T>> {
-    return request('/rest/v1/session');
+    return request('/rest/v1/session', data);
 }
+
 //config
 export function getConfig<T>(data: any): Promise<Result<T>> {
-    return request('/rest/v1/config/fe/');
+    return request('/rest/v1/config/fe/', data);
 }
+
 //query begin
-export function getDatabaseList<T>(data: any): Promise<Result<T>> {
+export function getDatabaseList<T>(data?: any): Promise<Result<T>> {
     let reURL = `${API_BASE}default_cluster/databases`;
-    if(data){
-        if(data.db_name){
+    if (data) {
+        if (data.db_name) {
             reURL += `/${data.db_name}/tables`;
         }
-        if(data.db_name&&data.tbl_name){
+        if (data.db_name && data.tbl_name) {
             reURL += `/${data.tbl_name}/schema`;
         }
     }
-    return request(reURL);
+    return request(reURL, data);
 }
+
 export function doQuery<T>(data: any): Promise<Result<T>> {
     return request(`/api/query/default_cluster/${data.db_name}`, {
-        method: 'POST',...data,
+        method: 'POST', ...data,
     });
 }
+
 export function doUp<T>(data: any): Promise<Result<T>> {
     let localHeader = {
         label: data.label,
         columns: data.columns,
-        column_separator: data. column_separator
+        column_separator: data.column_separator
     }
-    if(!localHeader.columns){
+    if (!localHeader.columns) {
         delete localHeader.columns
     }
     return request(`/api/default_cluster/${data.db_name}/${data.tbl_name}/upload?file_id=${data.file_id}&file_uuid=${data.file_uuid}`, {
-        method: 'PUT',headers:localHeader,
+        method: 'PUT', headers: localHeader,
     });
 }
+
 export function getUploadData<T>(data: any): Promise<Result<T>> {
     let localUrl = `/api/default_cluster/${data.db_name}/${data.tbl_name}/upload`
-    if(data.preview){
+    if (data.preview) {
         localUrl = `/api/default_cluster/${data.db_name}/${data.tbl_name}/upload?file_id=${data.file_id}&file_uuid=${data.file_uuid}&preview=true`
     }
-    return request(localUrl,{
+    return request(localUrl, {
         method: 'GET',
     });
 }
+
 export function deleteUploadData<T>(data: any): Promise<Result<T>> {
-    return request(`/api/default_cluster/${data.db_name}/${data.tbl_name}/upload?file_id=${data.file_id}&file_uuid=${data.file_uuid}`,{
+    return request(`/api/default_cluster/${data.db_name}/${data.tbl_name}/upload?file_id=${data.file_id}&file_uuid=${data.file_uuid}`, {
         method: 'DELETE',
     });
 }
+
 //query end
 export const AdHocAPI = {
     getDatabaseList,
@@ -131,4 +147,4 @@ export const AdHocAPI = {
     getHardwareInfo,
     getUploadData,
     deleteUploadData,
-};
\ No newline at end of file
+};
diff --git a/ui/src/components/table/index.tsx b/ui/src/components/table/index.tsx
index 94afff63c3..bd095c8631 100644
--- a/ui/src/components/table/index.tsx
+++ b/ui/src/components/table/index.tsx
@@ -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,54 +16,54 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- 
-import React, {useState,useEffect} from 'react';
+
+import React, {useState, useEffect} from 'react';
 import {Table, Popover, Input} from 'antd';
 import {FilterFilled} from '@ant-design/icons';
-import {getColumns, filterTableData} from './table.utils.tsx';
+import {getColumns, filterTableData} from './table.utils';
 import './index.less';
 
 export default function SortFilterTable(props: any) {
-    const {isFilter=false, isSort=false, allTableData, isInner, isSystem=false, path=''} = props;
-    const [tableData, setTableData] = useState([]);
-    const [localColumns, setColumns] = useState([]);
+    const {isFilter = false, isSort = false, allTableData, isInner, isSystem = false, path = '', rowKey} = props;
+    const [tableData, setTableData] = useState<any[]>([]);
+    const [localColumns, setColumns] = useState<any[]>([]);
     // function onChange(pagination, filters, sorter, extra) {
     //     console.log('params', pagination, filters, sorter, extra);
     // }
-    function changeTableData(e){
-        const localData = filterTableData(allTableData.rows,e.target.value);
+    function changeTableData(e) {
+        const localData = filterTableData(allTableData.rows, e.target.value);
         setTableData(localData);
     }
+
     const content = (
-        <Input placeholder="Filter data" onChange={e=>changeTableData(e)}/>
+        <Input placeholder="Filter data" onChange={e => changeTableData(e)}/>
     );
     useEffect(() => {
-        if(allTableData.rows&&allTableData.column_names){
-            setColumns(getColumns(allTableData.column_names, isSort, isInner, allTableData.href_columns||allTableData.href_column, path));
+        if (allTableData.rows && allTableData.column_names) {
+            setColumns(getColumns(allTableData.column_names, isSort, isInner, allTableData.href_columns || allTableData.href_column, path));
             setTableData(allTableData.rows);
         }
     }, [allTableData]);
 
-    return(
-        <span className='systemTable' >
-            {isFilter?<Popover className={isSystem?'searchSystem':'search'} content={content} trigger="click">
+    return (
+        <span className='systemTable'>
+            {isFilter ? <Popover className={isSystem ? 'searchSystem' : 'search'} content={content} trigger="click">
                 <FilterFilled/>
-            </Popover>:''}
+            </Popover> : ''}
             <Table
                 columns={localColumns}
+                rowKey={(record) => typeof rowKey === 'function' ? rowKey(record) : (typeof rowKey === 'string' ? rowKey : undefined)}
                 dataSource={tableData}
                 scroll={{ x: 'max-content' }}
                 size='small'
                 bordered
                 // onChange={onChange}
                 pagination={{
-                    size:'small',
-                    showTotal:(total, range) => `${range[0]}-${range[1]} of ${total} items`,
-                    showSizeChanger:true,
-                    showQuickJumper:true,
-                    hideOnSinglePage:true,
-                    pageSize:30,
-                    defaultPageSize:30,
+                    size: 'small',
+                    showTotal: (total, range) => `${range[0]}-${range[1]} of ${total} items`,
+                    showSizeChanger: true,
+                    showQuickJumper: true,
+                    defaultPageSize: 30,
                 }}
             />
         </span>
diff --git a/ui/src/i18n.tsx b/ui/src/i18n.tsx
index 331c465a0b..1a0c8676a5 100644
--- a/ui/src/i18n.tsx
+++ b/ui/src/i18n.tsx
@@ -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,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- 
+
 import LanguageDetector from 'i18next-browser-languagedetector';
 import i18n from 'i18next';
 import enUsTrans from '../public/locales/en-us.json';
@@ -24,8 +24,9 @@ import zhCnTrans from '../public/locales/zh-cn.json';
 import {
     initReactI18next
 } from 'react-i18next';
-i18n.use(LanguageDetector) 
-    .use(initReactI18next) 
+
+i18n.use(LanguageDetector)
+    .use(initReactI18next)
     .init({
         lng: localStorage.getItem('I18N_LANGUAGE') || "en",
         resources: {
@@ -39,9 +40,9 @@ i18n.use(LanguageDetector)
         fallbackLng: 'en',
         debug: false,
         interpolation: {
-            escapeValue: false 
+            escapeValue: false
         }
     });
 
 export default i18n;
- 
+
diff --git a/ui/src/pages/configuration/index.tsx b/ui/src/pages/configuration/index.tsx
index 0152d84039..cafd9f48b5 100644
--- a/ui/src/pages/configuration/index.tsx
+++ b/ui/src/pages/configuration/index.tsx
@@ -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,39 +16,38 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- 
-import React, {useState, useEffect} from 'react';
-import {Typography, Button, Row, Col} from 'antd';
-const {Title} = Typography;
+
+import React, {useEffect, useState} from 'react';
+import {Typography} from 'antd';
 import {getConfig} from 'Src/api/api';
 import Table from 'Src/components/table';
+
+const {Title} = Typography;
 export default function Configuration(params: any) {
-    const [allTableData, setAllTableData] = useState({});
-    const getConfigData = function(){
-        getConfig({}).then(res=>{
+    const [allTableData, setAllTableData] = useState<any>({column_names: [], rows: []});
+    const getConfigData = function (ac?: AbortController) {
+        getConfig({signal: ac?.signal}).then(res => {
             if (res && res.msg === 'success') {
                 setAllTableData(res.data);
             }
-        })
-            .catch(err=>{
-                setAllTableData({
-                    column_names:[],
-                    rows:[],
-                });
-            });
+        }).catch(err => {
+        });
     };
     useEffect(() => {
-        getConfigData();
+        const ac = new AbortController();
+        getConfigData(ac);
+        return () => ac.abort();
     }, []);
 
-    return(
-        <Typography style={{padding:'30px'}}>
+    return (
+        <Typography style={{padding: '30px'}}>
             <Title level={2}>Configure Info</Title>
             <Table
                 isSort={true}
                 isFilter={true}
                 // isInner={true}
                 allTableData={allTableData}
+                rowKey={record => record.Name}
             />
         </Typography>
     );
diff --git a/ui/src/pages/logs/index.tsx b/ui/src/pages/logs/index.tsx
index 9ca37f2860..065b55d510 100644
--- a/ui/src/pages/logs/index.tsx
+++ b/ui/src/pages/logs/index.tsx
@@ -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,36 +16,44 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- 
-import React,{useState, useEffect, useRef} from 'react';
-import {Typography, Divider, Row, Col, Input, BackTop} from 'antd';
-const {Title, Paragraph, Text} = Typography;
+
+import React, {useEffect, useRef, useState} from 'react';
+import {BackTop, Col, Divider, Input, Row, Typography} from 'antd';
 import {getLog} from 'Src/api/api';
+import {Result} from "@src/interfaces/http.interface";
+
+const {Title, Paragraph} = Typography;
 const {Search} = Input;
-import {Result} from '@src/interfaces/http.interface';
 export default function Logs(params: any) {
-    const container = useRef();
-    const [LogConfiguration, setLogConfiguration] = useState({});
-    const [LogContents, setLogContents] = useState({});
-    function getLogData(data){
-        getLog(data).then(res=>{
-            if(res.data && res.msg === 'success'){
-                if(res.data.LogConfiguration){
+    const container = useRef<HTMLDivElement>(null);
+    const [LogConfiguration, setLogConfiguration] = useState<any>({});
+    const [LogContents, setLogContents] = useState<any>({});
+
+    function getLogData(data) {
+        getLog(data).then((res: Result<any>) => {
+            if (res.data && res.msg === 'success') {
+                if (res.data.LogConfiguration) {
                     setLogConfiguration(res.data.LogConfiguration);
                 }
-                if(res.data.LogContents){
-                    container.current.innerHTML=res.data.LogContents.log;
+                if (res.data.LogContents) {
+                    if (container.current !== null) {
+                        container.current.innerHTML = res.data.LogContents.log;
+                    }
                     setLogContents(res.data.LogContents);
                 }
             }
+        }).catch(err => {
         });
     }
+
     useEffect(() => {
-        getLogData({});
+        const ac = new AbortController();
+        getLogData({signal: ac.signal});
+        return () => ac.abort();
     }, []);
-    return(
-        <Typography style={{padding:'30px'}}>
-            <Title >Log Configuration</Title>
+    return (
+        <Typography style={{padding: '30px'}}>
+            <Title>Log Configuration</Title>
             <Paragraph>
                 <p>Level: {LogConfiguration.VerboseNames}</p>
                 <p>Verbose Names:{LogConfiguration.VerboseNames}</p>
@@ -56,24 +64,24 @@ export default function Logs(params: any) {
                     <Search
                         placeholder="new verbose name"
                         enterButton="Add"
-                        onSearch={value => getLogData({add_verbose:value})}
+                        onSearch={value => getLogData({add_verbose: value})}
                     />
                 </Col>
                 <Col span={4} offset={1}>
                     <Search
                         placeholder="del verbose name"
                         enterButton="Delete"
-                        onSearch={value => getLogData({del_verbose:value})}
+                        onSearch={value => getLogData({del_verbose: value})}
                     />
                 </Col>
             </Row>
             <Divider/>
-            <Title style={{marginTop:'0px'}}>Log Contents</Title>
+            <Title style={{marginTop: '0px'}}>Log Contents</Title>
             <Paragraph>
                 <p>Log path is: {LogContents.logPath}</p>
                 <p>{LogContents.showingLast}</p>
             </Paragraph>
-            <div ref={container} style={{background: '#f9f9f9',padding: '20px'}}>
+            <div ref={container} style={{background: '#f9f9f9', padding: '20px'}}>
                 {/* {LogContents.log} */}
             </div>
             <BackTop></BackTop>
diff --git a/ui/src/pages/playground/content/components/data-prev.tsx b/ui/src/pages/playground/content/components/data-prev.tsx
index d3856848ce..8d027c34e2 100644
--- a/ui/src/pages/playground/content/components/data-prev.tsx
+++ b/ui/src/pages/playground/content/components/data-prev.tsx
@@ -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,65 +16,73 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- 
-import React,{useState,useEffect} from 'react';
+
+import React, {useEffect, useState} from 'react';
 import {AdHocAPI} from 'Src/api/api';
 import {getDbName} from 'Utils/utils';
-import {Row, Empty, notification, Table} from 'antd';
+import {notification, Row, Table} from 'antd';
 import {FlatBtn} from 'Components/flatbtn';
 import {useTranslation} from 'react-i18next';
+
 export function DataPrev(props: any) {
-    let { t } = useTranslation();
-    const {db_name,tbl_name} = getDbName();
-    const [tableData,setTableData] = useState([]);
-    const [columns,setColumns] = useState([]);
+    let {t} = useTranslation();
+    const {db_name, tbl_name} = getDbName();
+    const [tableData, setTableData] = useState<any[]>([]);
+    const [columns, setColumns] = useState<any[]>([]);
+
     function toQuery(): void {
-        if (!tbl_name){
-            notification.error({message: t('selectWarning')});
+        if (!tbl_name) {
+            notification.error({message: t<string>('selectWarning')});
             return;
         }
         AdHocAPI.doQuery({
             db_name,
-            body:{stmt:`SELECT * FROM ${db_name}.${tbl_name} LIMIT 10`},
-        }).then(res=>{
+            body: {stmt: `SELECT * FROM ${db_name}.${tbl_name} LIMIT 10`},
+        }).then((res: any) => {
             if (res && res.msg === 'success') {
-                console.log(getColumns(res.data?.meta),2222)
+                console.log(getColumns(res.data?.meta), 2222)
                 setColumns(getColumns(res.data?.meta))
-                setTableData(getTabledata(res.data));
+                setTableData(getTableData(res.data));
             }
-        })
-        .catch(()=>{
+        }).catch(() => {
             setTableData([]);
         });
     }
-    function getColumns(params: string[]) {
-        console.log(params,2222)
-        if(!params||params.length === 0){return [];}
-        
-        let arr = params.map(item=> {
+
+    function getColumns(params: any[]) {
+        if (!params || params.length === 0) {
+            return [];
+        }
+
+        let arr: any[] = params.map(item => {
             return {
                 title: item.name,
                 dataIndex: item.name,
                 key: item.name,
                 width: 150,
-                render:(text, record, index)=>{return text === '\\N' ? '-' : text}
+                render: (text, record, index) => {
+                    return text === '\\N' ? '-' : text
+                }
             };
         });
         return arr;
     }
-    function getTabledata(data){
-        let meta  = data.meta;
+
+    function getTableData(data): any[] {
+        let meta = data.meta;
         let source = data.data;
-        let res = [];
-        if(!source||source.length === 0){return [];}
-        let metaArr = meta.map(item=>item.name)
-        for (let i=0;i<source.length;i++) {
+        let res: any[] = [];
+        if (!source || source.length === 0) {
+            return [];
+        }
+        let metaArr = meta.map(item => item.name)
+        for (let i = 0; i < source.length; i++) {
             let node = source[i];
-            if(node.length !== meta.length){
-                return {}
+            if (node.length !== meta.length) {
+                return []
             }
             let obj = {}
-            metaArr.map((item,idx)=>{
+            metaArr.map((item, idx) => {
                 obj[item] = node[idx]
             })
             obj['key'] = i
@@ -82,13 +90,14 @@ export function DataPrev(props: any) {
         }
         return res;
     }
-    useEffect(()=>{
+
+    useEffect(() => {
         toQuery();
-    },[location.pathname]);
+    }, [location.pathname]);
     return (
         <div>
             <Row justify="space-between" style={{marginBottom: 10}}>
-                <span style={{paddingBottom:'15px'}}>{t('dataPreview')}({t('display10')})</span>
+                <span style={{paddingBottom: '15px'}}>{t('dataPreview') + "(" + t('display10') + ")"}</span>
                 <span>
                     {db_name}.{tbl_name}
                 </span>
@@ -103,13 +112,13 @@ export function DataPrev(props: any) {
             <Table
                 bordered
                 columns={columns}
-                style={{maxWidth:' calc(100vw - 350px)'}}
+                style={{maxWidth: ' calc(100vw - 350px)'}}
                 // scroll={{ x:'500', y: '36vh'}}
-                scroll={{ x: 1500, y: 300 }}
+                scroll={{x: 1500, y: 300}}
                 dataSource={tableData}
                 size="small"
             />
-           </div>
+        </div>
     );
 }
 
diff --git a/ui/src/pages/playground/page-side/index.tsx b/ui/src/pages/playground/page-side/index.tsx
index 10f3b4a9c4..3347621176 100644
--- a/ui/src/pages/playground/page-side/index.tsx
+++ b/ui/src/pages/playground/page-side/index.tsx
@@ -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,26 +16,27 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- 
-import React, {useState, useEffect, SyntheticEvent} from 'react';
+
+import React, {SyntheticEvent, useState} from 'react';
 import {ResizableBox} from 'react-resizable';
-require('react-resizable/css/styles.css');
 import styles from './index.less';
 
+require('react-resizable/css/styles.css');
+
 export function PageSide(props: any) {
     const {children} = props;
-    const [sideBoxWidth,setSideBoxWidth] = useState(300);
+    const [sideBoxWidth, setSideBoxWidth] = useState(300);
 
-    const onResize=function(e: SyntheticEvent, data: any) {
+    const onResize = function (e: SyntheticEvent, data: any) {
         const width = data.size.width || 300;
         setSideBoxWidth(width);
     };
     return (
-        <div className={styles['side']} >
+        <div className={styles['side']}>
             <ResizableBox
                 width={sideBoxWidth}
                 height={Infinity}
-                style={{'minHeight':'calc(100vh - 64px)','overflow':'hidden'}}
+                style={{'minHeight': 'calc(100vh - 64px)', 'overflow': 'hidden'}}
                 resizeHandles={['e']}
                 onResizeStart={onResize}
                 minConstraints={[300, 300]}
@@ -45,7 +46,6 @@ export function PageSide(props: any) {
                 {children}
             </ResizableBox>
         </div>
-
     );
 }
  
diff --git a/ui/src/pages/playground/tree/index.tsx b/ui/src/pages/playground/tree/index.tsx
index 0f0d440893..e3f56f98e7 100644
--- a/ui/src/pages/playground/tree/index.tsx
+++ b/ui/src/pages/playground/tree/index.tsx
@@ -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,25 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import React, {useState,useEffect} from 'react';
-import {Tree, Spin, Input} from 'antd';
-const { Search } = Input;
-import {TableOutlined, HddOutlined, ReloadOutlined} from '@ant-design/icons';
+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 {AdhocContentRouteKeyEnum,} from '../adhoc.data';
+import './index.css';
+
+const {Search} = Input;
+
 interface DataNode {
-  title: string;
-  key: string;
-  isLeaf?: boolean;
-  children?: DataNode[];
+    title: string;
+    key: string;
+    isLeaf?: boolean;
+    children?: DataNode[];
 }
-import './index.css';
+
 const initTreeDate: DataNode[] = [];
+
 function updateTreeData(list: DataNode[], key, children) {
     return list.map(node => {
         if (node.key === key) {
@@ -40,26 +42,30 @@ function updateTreeData(list: DataNode[], key, children) {
                 ...node,
                 children,
             };
-        } 
+        }
         return node;
     });
 }
+
 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);
-    const [expandedKeys, setExpandedKeys] = useState([]);
-    const [searchValue, setSearchValue] = useState('');
+    const [expandedKeys, setExpandedKeys] = useState<any[]>([]);
     const [autoExpandParent, setAutoExpandParent] = useState(true);
+
     useEffect(() => {
-        initTreeData()
+        const ac = new AbortController();
+        initTreeData(ac);
+        return () => ac.abort();
     }, []);
-    function initTreeData(){
-        AdHocAPI.getDatabaseList().then(res=>{
+
+    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)=>{
+                const treeData = res.data.map((item, index) => {
                     return {
                         title: item,
                         key: `${num}-1-${index}-${item}`,
@@ -70,34 +76,35 @@ export function AdHocTree(props: any) {
                 getRealTree(treeData);
             }
             setLoading(false);
+        }).catch(err => {
         });
     }
+
     function onLoadData({key, children}) {
-        const [random, storey, index, db_name] = key.split('-');
+        const [, storey, , db_name] = key.split('-');
         const param = {
             db_name,
             // tbl_name,
         };
-        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 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,
                             key: `2-${index}-${param.db_name}-${item}`,
-                            icon: <TableOutlined />,
+                            icon: <TableOutlined/>,
                             isLeaf: true,
                         };
                     }
-
                 });
                 const trData = updateTreeData(treeData, key, children);
                 setTreeData(trData);
                 getRealTree(trData);
             }
         });
-
     }
+
     function handleTreeSelect(
         keys: React.ReactText[],
         info: any,
@@ -107,73 +114,79 @@ export function AdHocTree(props: any) {
             props.history.push(`/Playground/${path}/${keys[0].split(':')[1]}`);
         }
     }
-    function onSearch(e){
-        const { value } = e.target;
-        const expandedKeys = treeData
-          .map((item, index) => {
-              if (getParentKey(value, treeData[index].children, index)) {
-                return item.key
-              } else {
-                  return null;
-              }
-          })
+
+    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;
+                }
+            })
         setExpandedKeys(expandedKeys);
-        setSearchValue(value);
         setAutoExpandParent(true);
         getRealTree(treeData, value);
-    };
+    }
+
     function onExpand(expandedKeys) {
         setExpandedKeys(expandedKeys);
         setAutoExpandParent(false);
-    };
+    }
+
     const getParentKey = (key, tree, idx) => {
         if (!tree) {
             return false;
         }
         for (let i = 0; i < tree.length; i++) {
-          const node = tree[i];
-          if (node.title.includes(key)) {
-            return true
-          } else {
-            treeData[idx].children ? treeData[idx].children[i].title = node.title : ''
-          }
+            const node = tree[i];
+            if (node.title.includes(key)) {
+                return true
+            } else {
+                treeData[idx].children ? treeData[idx].children[i].title = node.title : ''
+            }
         }
         return false;
     };
-    function getRealTree(treeData, value){
-        const realTree  = inner(treeData);
-        function inner(treeData){
+
+    function getRealTree(treeData, value?) {
+        const realTree = inner(treeData);
+
+        function inner(treeData) {
             return treeData.map(item => {
                 const search = value || '';
                 const index = item.title.indexOf(search);
                 const beforeStr = item.title.substr(0, index);
                 const afterStr = item.title.substr(index + search.length);
                 const title =
-                  index > -1 ? (
-                    <span>
+                    index > -1 ? (
+                        <span>
                       {beforeStr}
-                      <span className="site-tree-search-value">{search}</span>
-                      {afterStr}
+                            <span className="site-tree-search-value">{search}</span>
+                            {afterStr}
                     </span>
-                  ) : (
-                    item.title
-                  );
+                    ) : (
+                        item.title
+                    );
                 if (item.children) {
-                  return {...item, title, children: inner(item.children)};
+                    return {...item, title, children: inner(item.children)};
                 }
                 return {
-                  ...item,
-                  title
+                    ...item,
+                    title
                 };
             });
         }
-        debounce(setRealTree(realTree),300);
+
+        debounce(setRealTree(realTree), 300);
     }
+
     function debounce(fn, wait) {
-        var timer = null;
+        let timer = null;
         return function () {
-            var context = this
-            var args = arguments
+            let context = this
+            let args = arguments
             if (timer) {
                 clearTimeout(timer);
                 timer = null;
@@ -183,19 +196,20 @@ export function AdHocTree(props: any) {
             }, wait)
         }
     }
+
     return (
         <>
             <Spin spinning={loading} size="small"/>
             <div>
-                <Search 
-                    size="small" 
-                    style={{ padding: 5, position: 'fixed', zIndex: '99', width: '300px'}} 
-                    placeholder={t('search')} 
-                    enterButton={<ReloadOutlined />} 
+                <Search
+                    size="small"
+                    style={{padding: 5, position: 'fixed', zIndex: '99', width: '300px'}}
+                    placeholder={t('search')}
+                    enterButton={<ReloadOutlined/>}
                     onSearch={initTreeData}
-                    onChange={onSearch} />
+                    onChange={onSearch}/>
             </div>
-            
+
             <Tree
                 showIcon={true}
                 loadData={onLoadData}
@@ -203,12 +217,12 @@ 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)
                 }
             />
         </>
diff --git a/ui/src/pages/query-profile/index.tsx b/ui/src/pages/query-profile/index.tsx
index 2b296cd233..ccdf64ce26 100644
--- a/ui/src/pages/query-profile/index.tsx
+++ b/ui/src/pages/query-profile/index.tsx
@@ -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,74 +16,82 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- 
-import React, {useState, useEffect, useRef} from 'react';
-import {Typography, Button, Row, Col} from 'antd';
-const {Text, Title, Paragraph} = Typography;
+
+import React, {useEffect, useRef, useState} from 'react';
+import {Button, Col, Row, Typography} from 'antd';
 import {queryProfile} from 'Src/api/api';
 import Table from 'Src/components/table';
 import {useHistory} from 'react-router-dom';
+import {Result} from '@src/interfaces/http.interface';
+
+const {Text, Title} = Typography;
 export default function QueryProfile(params: any) {
     // const [parentUrl, setParentUrl] = useState('');
-    const container = useRef();
-    const [allTableData, setAllTableData] = useState({});
-    const [profile, setProfile] = useState();
+    const container = useRef<HTMLDivElement>(null);
+    const [allTableData, setAllTableData] = useState({column_names: [], rows: []});
+    const [profile, setProfile] = useState<any>();
     const history = useHistory();
-    const doQueryProfile = function(){
+    const doQueryProfile = function (ac?: AbortController) {
         const param = {
             path: getLastPath(),
+            signal: ac?.signal
         };
-        queryProfile(param).then(res=>{
+        queryProfile(param).then((res: Result<any>) => {
             if (res && res.msg === 'success') {
-                if(!res.data.column_names){
+                if (!res.data.column_names) {
                     setProfile(res.data);
-                    container.current.innerHTML=res.data;
-                }else{
+                    if (container.current !== null) {
+                        container.current.innerHTML = res.data;
+                    }
+                } else {
                     setProfile('');
                     setAllTableData(res.data);
                 }
             } else {
                 setAllTableData({
-                    column_names:[],
-                    rows:[],
+                    column_names: [],
+                    rows: [],
                 });
             }
-        })
-            .catch(err=>{
-                setAllTableData({
-                    column_names:[],
-                    rows:[],
-                });
-            });
+        }).catch(err => {
+        });
     };
     useEffect(() => {
-        doQueryProfile();
+        const ac = new AbortController();
+        doQueryProfile(ac);
+        return () => ac.abort();
     }, [location.pathname]);
-    function getLastPath(){
+
+    function getLastPath() {
         let arr = location.pathname.split('/');
         let str = arr.pop();
         return str === 'QueryProfile' ? '' : str;
     }
-    function goPrev(){
-        if (location.pathname === '/QueryProfile/') {return;}
+
+    function goPrev() {
+        if (location.pathname === '/QueryProfile/') {
+            return;
+        }
         history.push('/QueryProfile/');
     }
-    return(
-        <Typography style={{padding:'30px'}}>
-            <Title >Finished Queries</Title>
 
-            <Row style={{paddingBottom:'15px'}}>
-                <Col span={12} ><Text type="strong">This table lists the latest 100 queries</Text></Col>
-                <Col span={12} style={{textAlign:'right'}}>
-                    {profile?<Button  type="primary" onClick={goPrev}>back</Button>:''}
+    return (
+        <Typography style={{padding: '30px'}}>
+            <Title>Finished Queries</Title>
+
+            <Row style={{paddingBottom: '15px'}}>
+                <Col span={12}><Text strong={true}>This table lists the latest 100 queries</Text></Col>
+                <Col span={12} style={{textAlign: 'right'}}>
+                    {profile ? <Button type="primary" onClick={goPrev}>back</Button> : ''}
                 </Col>
             </Row>
             {
                 profile
-                    ?<div ref={container} style={{background: '#f9f9f9',padding: '20px'}}>
+                    ? <div ref={container} style={{background: '#f9f9f9', padding: '20px'}}>
                         {/* {profile} */}
                     </div>
-                    :<Table
+                    : <Table
+                        rowKey={(record) => record['Query ID']}
                         isSort={true}
                         isFilter={true}
                         isInner={'/QueryProfile'}
diff --git a/ui/src/pages/session/index.tsx b/ui/src/pages/session/index.tsx
index 393cf324d7..4c97c095be 100644
--- a/ui/src/pages/session/index.tsx
+++ b/ui/src/pages/session/index.tsx
@@ -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,47 +16,46 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- 
-import React, {useState, useEffect} from 'react';
-import {Typography, Button, Row, Col} from 'antd';
-const {Text, Title, Paragraph} = Typography;
+
+import React, {useEffect, useState} from 'react';
+import {Row, Typography} from 'antd';
 import {getSession} from 'Src/api/api';
 import Table from 'Src/components/table';
+
+const {Text, Title} = Typography;
 // import {useHistory} from 'react-router-dom';
 export default function Session(params: any) {
     // const [parentUrl, setParentUrl] = useState('');
-    const [allTableData, setAllTableData] = useState({});
+    const [allTableData, setAllTableData] = useState<any>({column_names: [], rows: []});
     // const history = useHistory();
-    const getSessionData = function(){
-        getSession({}).then(res=>{
+    const getSessionData = function (ac: AbortController) {
+        getSession({signal: ac.signal}).then(res => {
             if (res && res.msg === 'success') {
                 setAllTableData(res.data);
             }
-        })
-            .catch(err=>{
-                setAllTableData({
-                    column_names:[],
-                    rows:[],
-                });
-            });
+        }).catch(err => {
+        });
     };
     useEffect(() => {
-        getSessionData();
+        const ac = new AbortController();
+        getSessionData(ac);
+        return () => ac.abort();
     }, []);
-    return(
-        <Typography style={{padding:'30px'}}>
-            <Title >Session Info</Title>
+    return (
+        <Typography style={{padding: '30px'}}>
+            <Title>Session Info</Title>
 
-            <Row style={{paddingBottom:'15px'}}>
-                <Text type="strong">This page lists the session info, there are {allTableData?.rows?.length} active sessions.</Text>
+            <Row style={{paddingBottom: '15px'}}>
+                <Text strong={true}>This page lists the session info, there are {allTableData?.rows?.length} active
+                    sessions.</Text>
             </Row>
             <Table
                 isSort={true}
                 isFilter={true}
                 // isInner={true}
                 allTableData={allTableData}
+                rowKey={(record) => record.Id}
             />
-
         </Typography>
     );
 }
diff --git a/ui/src/pages/system/index.tsx b/ui/src/pages/system/index.tsx
index ce96744a5b..f03c366264 100644
--- a/ui/src/pages/system/index.tsx
+++ b/ui/src/pages/system/index.tsx
@@ -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,45 +16,48 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- 
 
-import React, {useState, useEffect} from 'react';
-import {Typography, Button, Row, Col} from 'antd';
-const {Text, Title, Paragraph} = Typography;
+
+import React, {useEffect, useState} from 'react';
+import {Button, Col, Row, Typography} from 'antd';
 import {getSystem} from 'Src/api/api';
 import Table from 'Src/components/table';
 import {useHistory} from 'react-router-dom';
+import {Result} from '@src/interfaces/http.interface';
+
+const {Text, Title, Paragraph} = Typography;
+
 export default function System(params: any) {
-    const [parentUrl, setParentUrl] = useState('');
-    const [allTableData, setAllTableData] = useState({});
+    const [parentUrl, setParentUrl] = useState<string>('');
+    const [allTableData, setAllTableData] = useState<any>({column_names: [], rows: []});
 
     const history = useHistory();
-    const getSystemData = function(){
+    const getSystemData = function (ac?: any) {
         const param = {
-            path:location.search,
+            path: location.search,
+            signal: ac?.signal,
         };
-        getSystem(param).then(res=>{
+        getSystem(param).then((res: Result<any>) => {
             if (res && res.msg === 'success') {
                 setAllTableData(res.data);
                 setParentUrl(res.data.parent_url);
             } else {
                 setAllTableData({
-                    column_names:[],
-                    rows:[],
+                    column_names: [],
+                    rows: [],
                 });
             }
-        })
-            .catch(err=>{
-                setAllTableData({
-                    column_names:[],
-                    rows:[],
-                });
-            });
+        }).catch(err => {
+        });
     };
+
     useEffect(() => {
-        getSystemData();
+        const ac = new AbortController();
+        getSystemData(ac);
+        return () => ac.abort();
     }, [location.search]);
-    function goPrev(){
+
+    function goPrev() {
         if (parentUrl === '/rest/v1/system') {
             history.push('/System?path=/');
             return;
@@ -63,16 +66,17 @@ export default function System(params: any) {
             history.push(parentUrl.split('v1/')[1]);
         }
     }
-    return(
-        <Typography style={{padding:'30px'}}>
+
+    return (
+        <Typography style={{padding: '30px'}}>
             <Title level={2}>System Info</Title>
-            <Text type="strong">This page lists the system info, like /proc in Linux.</Text>
+            <Text strong={true}>This page lists the system info, like /proc in Linux.</Text>
             <Paragraph>
 
             </Paragraph>
-            <Row style={{paddingBottom:'15px'}}>
-                <Col span={12} style={{color:'#02a0f9'}}>Current path: {location.search.split('=')[1]}</Col>
-                <Col span={12} style={{textAlign:'right'}}>
+            <Row style={{paddingBottom: '15px'}}>
+                <Col span={12} style={{color: '#02a0f9'}}>Current path: {location.search.split('=')[1]}</Col>
+                <Col span={12} style={{textAlign: 'right'}}>
                     <Button size='small' type="primary" onClick={goPrev}>Parent Dir</Button>
                 </Col>
             </Row>
@@ -84,6 +88,7 @@ export default function System(params: any) {
                 path = 'System'
                 isSystem = {true}
                 allTableData={allTableData}
+                rowKey={(record) => record.name}
             />
         </Typography>
     );
diff --git a/ui/src/utils/lazy.tsx b/ui/src/utils/lazy.tsx
index df9d483c60..f031556eea 100644
--- a/ui/src/utils/lazy.tsx
+++ b/ui/src/utils/lazy.tsx
@@ -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,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
- 
+
 import React, {Component} from 'react';
 
 const asyncComponent = importComponent => {
-    return class extends Component {
+    return class extends Component<{}, { component: any }> {
         constructor(props) {
             super(props);
             this.state = {
                 component: null
             };
         }
+
         componentDidMount() {
-            importComponent()
-                .then(cmp => {
-                    this.setState({component: cmp.default});
-                });
+            importComponent().then(cmp => {
+                this.setState({component: cmp.default});
+            });
         }
+
         render() {
             const C = this.state.component;
             return C ? <C {...this.props}/> : null;
diff --git a/ui/src/utils/utils.ts b/ui/src/utils/utils.ts
index 584c288edc..eeb5b657f9 100644
--- a/ui/src/utils/utils.ts
+++ b/ui/src/utils/utils.ts
@@ -27,16 +27,14 @@ function isSuccess(response) {
 
     let {code, msg} = response;
 
-    if (code === 0 && msg === 'success') {
-        return true
-    }
-    return false;
+    return code === 0 && msg === 'success';
 }
-function getDbName(params) {
+
+function getDbName(params?: any) {
     const infoArr = location.pathname.split('/');
-    const str = infoArr[infoArr.length-1];
-    const res = {};
-    if(str && str !=='Playground'){
+    const str = infoArr[infoArr.length - 1];
+    const res: any = {};
+    if (str && str !== 'Playground') {
         const db_name = str.split('-')[0];
         const tbl_name = str.split('-')[1];
         res.db_name = db_name;
@@ -44,10 +42,11 @@ function getDbName(params) {
     }
     return res;
 }
+
 function getTimeNow() {
     let dateNow = new Date();
     let fmt = 'yyyy-MM-dd hh:mm:ss';
-    var o = {
+    let o = {
         'M+': dateNow.getMonth() + 1,
         'd+': dateNow.getDate(),
         'h+': dateNow.getHours(),
@@ -58,29 +57,31 @@ function getTimeNow() {
     };
     if (/(y+)/.test(fmt)) {
         fmt = fmt.replace(
-          RegExp.$1,
-          (dateNow.getFullYear() + '').substr(4 - RegExp.$1.length)
+            RegExp.$1,
+            (dateNow.getFullYear() + '').substr(4 - RegExp.$1.length)
         );
     }
-    for (var k in o) {
+    for (let k in o) {
         if (new RegExp('(' + k + ')').test(fmt)) {
             fmt = fmt.replace(
                 RegExp.$1,
                 RegExp.$1.length === 1
-                ? o[k]
-                : ('00' + o[k]).substr(('' + o[k]).length)
+                    ? o[k]
+                    : ('00' + o[k]).substr(('' + o[k]).length)
             );
         }
     }
     return fmt;
 }
-function getBasePath(){
+
+function getBasePath() {
     let arr = location.pathname.split('/');
     let res = '';
-    if(arr.length>5){
-        arr = arr.slice(0,5);
+    if (arr.length > 5) {
+        arr = arr.slice(0, 5);
         res = arr.join('/');
     }
     return res;
 }
-module.exports = {isSuccess, getDbName, getTimeNow, getBasePath};
\ No newline at end of file
+
+export {isSuccess, getDbName, getTimeNow, getBasePath};
diff --git a/ui/tsconfig.json b/ui/tsconfig.json
index 0f07e067e8..19d16e4e61 100644
--- a/ui/tsconfig.json
+++ b/ui/tsconfig.json
@@ -1,29 +1,30 @@
 {
-    "compilerOptions": {
-      "outDir": "dist",
-      "module": "commonjs",
-      "target": "es5",
-      "lib": ["es7", "dom", "es2015.iterable", "es2019"],
-      "sourceMap": true,
-      "allowJs": true,
-      "jsx": "react",
-      "moduleResolution": "node",
-      "forceConsistentCasingInFileNames": false,
-      "noImplicitReturns": true,
-      "noImplicitThis": true,
-      "noImplicitAny": false,
-      "strictNullChecks": true,
-      "esModuleInterop": true,
-      "suppressImplicitAnyIndexErrors": true,
-      "noUnusedLocals": true,
-      "allowSyntheticDefaultImports": true,
-      "experimentalDecorators": true,
-      "emitDecoratorMetadata": true,
-      "noImplicitUseStrict": true,
-      "alwaysStrict": false,
-      "downlevelIteration": true,
-      "baseUrl": "./",
-      "paths": {
+  "compilerOptions": {
+    "outDir": "dist",
+    "module": "commonjs",
+    "target": "es5",
+    "lib": ["es7", "dom", "es2015.iterable", "es2019"],
+    "sourceMap": true,
+    "allowJs": true,
+    "jsx": "react",
+    "moduleResolution": "node",
+    "forceConsistentCasingInFileNames": false,
+    "noImplicitReturns": true,
+    "noImplicitThis": true,
+    "noImplicitAny": false,
+    "strictNullChecks": true,
+    "resolveJsonModule": true,
+    "esModuleInterop": true,
+    "suppressImplicitAnyIndexErrors": true,
+    "noUnusedLocals": true,
+    "allowSyntheticDefaultImports": true,
+    "experimentalDecorators": true,
+    "emitDecoratorMetadata": true,
+    "noImplicitUseStrict": true,
+    "alwaysStrict": false,
+    "downlevelIteration": true,
+    "baseUrl": "./",
+    "paths": {
         "Components/*": ["src/components/*"],
         "Src": ["src"],
         "Utils/*": ["src/utils/*"],
@@ -32,28 +33,27 @@
         "Constants": ["src/constants"],
         "@hooks/*": ["src/hooks/*"],
         "@src/*": ["src/*"]
-      },
-      "typeRoots": [
-        "./node_modules/@types",
-        "custom_typings",
-        "./typings/**/*.d.ts"
-      ]
     },
-    "exclude": [
-      "build",
-      "scripts",
-      "webpack",
-      "jest",
-      "bin",
-      "runtime",
-      "view",
-      "public_gen",
-      "public",
-      "node_modules",
-      "coverage",
-      ".vscode"
-    ],
+    "typeRoots": [
+      "./node_modules/@types",
+      "custom_typings",
+      "./typings/**/*.d.ts"
+    ]
+  },
+  "exclude": [
+    "build",
+    "scripts",
+    "webpack",
+    "jest",
+    "bin",
+    "runtime",
+    "view",
+    "public_gen",
+    "public",
+    "node_modules",
+    "coverage",
+    ".vscode"
+  ],
     "includes": ["src/**/*.ts", "src/**/*.tsx", "global.d.ts"],
     "types": ["typePatches"]
-  }
-  
\ No newline at end of file
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org