From ebf8a711108822a3c42e3b4035549c895af9e580 Mon Sep 17 00:00:00 2001 From: morningman Date: Mon, 2 Nov 2020 12:03:51 +0800 Subject: [PATCH] [FE UI] Fix some bugs about new FE UI 1. Add a search boxer in the left tree view of Playground. 2. Fix some visual bugs of UI. 3. Fix bugs that link failed in QueryProfile view. 4. Fix bugs that cookie is always invalid. 5. Set cookie to HTTP_ONLY to make it more safe. --- .../httpv2/controller/BaseController.java | 2 + ui/public/locales/en-us.json | 4 +- ui/public/locales/zh-cn.json | 4 +- ui/src/components/table/index.tsx | 1 - ui/src/components/table/table.utils.tsx | 6 +- ui/src/pages/layout/index.tsx | 2 +- .../content/components/data-prev.tsx | 92 +++++++----- .../playground/content/content-result.tsx | 4 +- .../playground/content/content-structure.tsx | 1 + ui/src/pages/playground/content/index.less | 1 + ui/src/pages/playground/content/index.tsx | 2 +- ui/src/pages/playground/page-side/index.less | 2 +- ui/src/pages/playground/page-side/index.tsx | 3 +- ui/src/pages/playground/tree/index.css | 3 + ui/src/pages/playground/tree/index.tsx | 140 +++++++++++++++--- ui/src/pages/query-profile/index.tsx | 2 +- 16 files changed, 196 insertions(+), 73 deletions(-) create mode 100644 ui/src/pages/playground/tree/index.css diff --git a/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/BaseController.java b/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/BaseController.java index 3bbea54f02c329..bd36e3c229992d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/BaseController.java +++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/BaseController.java @@ -106,6 +106,7 @@ protected void addSession(HttpServletRequest request, HttpServletResponse respon Cookie cookie = new Cookie(PALO_SESSION_ID, key); cookie.setMaxAge(PALO_SESSION_EXPIRED_TIME); cookie.setPath("/"); + cookie.setHttpOnly(true); response.addCookie(cookie); LOG.debug("add session cookie: {} {}", PALO_SESSION_ID, key); HttpAuthManager.getInstance().addSessionValue(key, value); @@ -170,6 +171,7 @@ public void updateCookieAge(HttpServletRequest request, String cookieName, int a for (Cookie cookie : cookies) { if (cookie.getName() != null && cookie.getName().equals(cookieName)) { cookie.setMaxAge(age); + cookie.setPath("/"); response.addCookie(cookie); LOG.debug("get update cookie: {} {}", cookie.getName(), cookie.getValue()); } diff --git a/ui/public/locales/en-us.json b/ui/public/locales/en-us.json index ba4200138f5460..97f076d39b1c1e 100644 --- a/ui/public/locales/en-us.json +++ b/ui/public/locales/en-us.json @@ -47,5 +47,7 @@ "tips":"Tips", "fileSizeWarning": "File size cannot exceed 100M", "selectWarning": "Please select a table", - "executionTime": "Execution Time" + "executionTime": "Execution Time", + "search":"Search", + "executionFailed":"Execution failed" } diff --git a/ui/public/locales/zh-cn.json b/ui/public/locales/zh-cn.json index 24a7335735b180..ec1ccf41e1ac34 100644 --- a/ui/public/locales/zh-cn.json +++ b/ui/public/locales/zh-cn.json @@ -47,5 +47,7 @@ "tips": "提示", "fileSizeWarning": "文件大小不能超过100m", "selectWarning": "请选择表", - "executionTime": "执行时间" + "executionTime": "执行时间", + "search":"查询", + "executionFailed": "执行失败" } diff --git a/ui/src/components/table/index.tsx b/ui/src/components/table/index.tsx index f775739e5522d3..8c082b752fe758 100644 --- a/ui/src/components/table/index.tsx +++ b/ui/src/components/table/index.tsx @@ -50,7 +50,6 @@ export default function SortFilterTable(props: any) { :''} {text}; } - return {text}; + return {text}; } return text === '\\N' ? '-' : text; } export function getColumns(params: string[], isSort: boolean, isInner, hrefColumn, path) { if(!params||params.length === 0){return [];} - let arr = params.map(item=> { + let arr = params.map((item,idx)=> { if (isSort) { return { title: item, dataIndex: item, className: 'pr-25', + key: item+idx, sorter: (a,b)=>sortItems(a, b, item), render:(text, record, index)=>getLinkItem(text,record, index, isInner, item, hrefColumn, path), }; @@ -50,6 +51,7 @@ export function getColumns(params: string[], isSort: boolean, isInner, hrefColum title: item, dataIndex: item, className: 'pr-25', + key: item+idx, render:(text, record, index)=>getLinkItem(text, record, index, isInner, item, hrefColumn, path), }; }); diff --git a/ui/src/pages/layout/index.tsx b/ui/src/pages/layout/index.tsx index 8c14ac4b1aa1a1..0ea4ba6257a063 100644 --- a/ui/src/pages/layout/index.tsx +++ b/ui/src/pages/layout/index.tsx @@ -91,7 +91,7 @@ function Layouts(props: any) { ); return ( -
+
{history.replace('/home');setCurrent('')}}>
diff --git a/ui/src/pages/playground/content/components/data-prev.tsx b/ui/src/pages/playground/content/components/data-prev.tsx index 96ab1e0f29e88b..d3856848ce6943 100644 --- a/ui/src/pages/playground/content/components/data-prev.tsx +++ b/ui/src/pages/playground/content/components/data-prev.tsx @@ -20,26 +20,68 @@ import React,{useState,useEffect} from 'react'; import {AdHocAPI} from 'Src/api/api'; import {getDbName} from 'Utils/utils'; -import {Row, Empty} from 'antd'; +import {Row, Empty, notification, 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([]); function toQuery(): void { + if (!tbl_name){ + notification.error({message: t('selectWarning')}); + return; + } AdHocAPI.doQuery({ db_name, body:{stmt:`SELECT * FROM ${db_name}.${tbl_name} LIMIT 10`}, }).then(res=>{ if (res && res.msg === 'success') { - setTableData(res.data); + console.log(getColumns(res.data?.meta),2222) + setColumns(getColumns(res.data?.meta)) + setTableData(getTabledata(res.data)); } }) .catch(()=>{ setTableData([]); }); } + function getColumns(params: string[]) { + console.log(params,2222) + if(!params||params.length === 0){return [];} + + let arr = params.map(item=> { + return { + title: item.name, + dataIndex: item.name, + key: item.name, + width: 150, + render:(text, record, index)=>{return text === '\\N' ? '-' : text} + }; + }); + return arr; + } + function getTabledata(data){ + 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{ + obj[item] = node[idx] + }) + obj['key'] = i + res.push(obj) + } + return res; + } useEffect(()=>{ toQuery(); },[location.pathname]); @@ -58,42 +100,16 @@ export function DataPrev(props: any) { {t('refresh')} -
- {tableData?.meta?.length - ?
-
-
- - - {tableData?.meta?.map(item => ( - - ))} - - - - {tableData.data?.map((item,index) => ( - - {item.map((tdData,index) => ( - - ))} - - ))} - -
- {item.name} -
- {tdData == '\\N'?'-':tdData} -
- - :} - - + + ); } diff --git a/ui/src/pages/playground/content/content-result.tsx b/ui/src/pages/playground/content/content-result.tsx index 627fa99370332f..4eea84e8920d66 100644 --- a/ui/src/pages/playground/content/content-result.tsx +++ b/ui/src/pages/playground/content/content-result.tsx @@ -123,7 +123,7 @@ export function AdhocContentResult(props) { ) : ( } - text={"执行失败: "+runningQueryInfo.msg +' '+ runningQueryInfo.data} + text={`${t('executionFailed')}: `+runningQueryInfo.msg +' '+ runningQueryInfo.data} color="red" style={{ marginBottom: 10, @@ -141,7 +141,7 @@ export function AdhocContentResult(props) { */} {t('executionTime')}: - {runningQueryInfo.data?.time + ' ms'} + {(runningQueryInfo.data?.time?runningQueryInfo.data?.time:0) + ' ms'} {/* {t('endTime')}: diff --git a/ui/src/pages/playground/content/content-structure.tsx b/ui/src/pages/playground/content/content-structure.tsx index 703a68c449cc83..8aedb22dc23bc0 100644 --- a/ui/src/pages/playground/content/content-structure.tsx +++ b/ui/src/pages/playground/content/content-structure.tsx @@ -86,6 +86,7 @@ export function ContentStructure(props: any) { bordered rowKey='Field' columns={columns} + scroll={{ y: '36vh' }} loading={{ spinning: getTableInfoRequest.loading, delay: TABLE_DELAY, diff --git a/ui/src/pages/playground/content/index.less b/ui/src/pages/playground/content/index.less index 6a60d496d18267..ae98a1f044e7ba 100644 --- a/ui/src/pages/playground/content/index.less +++ b/ui/src/pages/playground/content/index.less @@ -23,6 +23,7 @@ under the License. */ &-operator { margin-top: 10px; } + width: calc(100vw - 350px); } .adhoc-content-favorite { diff --git a/ui/src/pages/playground/content/index.tsx b/ui/src/pages/playground/content/index.tsx index bc0f035c9eec12..50c69e8b80f9e1 100644 --- a/ui/src/pages/playground/content/index.tsx +++ b/ui/src/pages/playground/content/index.tsx @@ -206,7 +206,7 @@ export function AdHocContent(props: any) { ( -
+
diff --git a/ui/src/pages/playground/page-side/index.less b/ui/src/pages/playground/page-side/index.less index 0a80f520566166..e82972e1c8aea5 100644 --- a/ui/src/pages/playground/page-side/index.less +++ b/ui/src/pages/playground/page-side/index.less @@ -19,5 +19,5 @@ under the License. */ flex: 0 0 300px; height: 100%; background: #fff; - min-height: calc(100vh - 60px); + min-height: calc(100vh - 64px); } \ No newline at end of file diff --git a/ui/src/pages/playground/page-side/index.tsx b/ui/src/pages/playground/page-side/index.tsx index 570584b3d437ad..10f3b4a9c4957c 100644 --- a/ui/src/pages/playground/page-side/index.tsx +++ b/ui/src/pages/playground/page-side/index.tsx @@ -34,7 +34,8 @@ export function PageSide(props: any) {
{ if (node.key === key) { return { ...node, children, }; - } else if (node.children) { - return { - ...node, - children: updateTreeData(node.children, key, children), - }; - } + } return node; }); } export function AdHocTree(props: any) { - + 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 [autoExpandParent, setAutoExpandParent] = useState(true); useEffect(() => { + initTreeData() + }, []); + function initTreeData(){ AdHocAPI.getDatabaseList().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: `1-${index}-${item}`, + key: `${num}-1-${index}-${item}`, icon: , }; }); setTreeData(treeData); + getRealTree(treeData); } setLoading(false); }); - }, []); + } function onLoadData({key, children}) { - const [storey, index, db_name, tbl_name] = key.split('-'); + const [random, storey, index, db_name] = key.split('-'); const param = { db_name, - tbl_name, + // tbl_name, }; return AdHocAPI.getDatabaseList(param).then(res=>{ if (res.msg=='success' && Array.isArray(res.data)) { - const treeData = res.data.map((item,index)=>{ - if(storey==1){ + const children = res.data.map((item,index)=>{ + if (storey === '1'){ return { title: item, key: `2-${index}-${param.db_name}-${item}`, @@ -86,9 +91,9 @@ export function AdHocTree(props: any) { } }); - setTreeData(origin => - updateTreeData(origin, key, treeData), - ); + const trData = updateTreeData(treeData, key, children); + setTreeData(trData); + getRealTree(trData); } }); @@ -102,14 +107,103 @@ 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; + } + }) + 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 : '' + } + } + return false; + }; + 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 ? ( + + {beforeStr} + {search} + {afterStr} + + ) : ( + item.title + ); + if (item.children) { + return {...item, title, children: inner(item.children)}; + } + return { + ...item, + title + }; + }); + } + debounce(setRealTree(realTree),300); + } + function debounce(fn, wait) { + var timer = null; + return function () { + var context = this + var args = arguments + if (timer) { + clearTimeout(timer); + timer = null; + } + timer = setTimeout(function () { + fn.apply(context, args) + }, wait) + } + } return ( <> +
+ } + onSearch={initTreeData} + onChange={onSearch} /> +
+ handleTreeSelect( selectedKeys, diff --git a/ui/src/pages/query-profile/index.tsx b/ui/src/pages/query-profile/index.tsx index 7beb2aea162e4e..2b296cd233dad1 100644 --- a/ui/src/pages/query-profile/index.tsx +++ b/ui/src/pages/query-profile/index.tsx @@ -86,7 +86,7 @@ export default function QueryProfile(params: any) { :
}