refactor: add ts support to selectedSpanDetails and TraceGanttChartHelpers, change folder structure

This commit is contained in:
Nidhi Tandon 2021-06-27 08:47:46 +05:30
parent 0c12eaf89b
commit 421a102291
9 changed files with 173 additions and 161 deletions

View File

@ -1,14 +1,14 @@
import React from "react"; import React from "react";
import { Card, Space, Tabs, Typography } from "antd"; import { Card, Space, Tabs, Typography } from "antd";
import styled from "styled-components"; import styled from "styled-components";
import { pushDStree } from "../../store/actions"; import { pushDStree } from "Src/store/actions";
const { TabPane } = Tabs; const { TabPane } = Tabs;
const { Text } = Typography; const { Text } = Typography;
interface SelectedSpanDetailsProps { interface SelectedSpanDetailsProps {
data: pushDStree data: pushDStree;
} }
const Title = styled(Text)` const Title = styled(Text)`
@ -17,79 +17,82 @@ const Title = styled(Text)`
`; `;
const SelectedSpanDetails = (props: SelectedSpanDetailsProps) => { const SelectedSpanDetails = (props: SelectedSpanDetailsProps) => {
let spanTags = props.data?.tags;
let spanTags = props.data.tags;
let service = props.data?.name?.split(":")[0]; let service = props.data?.name?.split(":")[0];
let operation = props.data?.name?.split(":")[1]; let operation = props.data?.name?.split(":")[1];
return ( return (
<Card style={{ border: "none", background: "transparent", padding: 0 }} bodyStyle={{ padding: 0 }}> <Card
style={{ border: "none", background: "transparent", padding: 0 }}
bodyStyle={{ padding: 0 }}
>
<Space direction="vertical"> <Space direction="vertical">
<strong> Details for selected Span </strong> <strong> Details for selected Span </strong>
<Space direction="vertical" size={2}> <Space direction="vertical" size={2}>
<Text style={{ marginTop: "18px" }}> <Text style={{ marginTop: "18px" }}>Service</Text>
Service <Title style={{ color: "#2D9CDB", fontSize: "12px" }}>{service}</Title>
</Text>
<Title style={{ color: "#2D9CDB", fontSize: "12px" }}>
{service}
</Title>
</Space> </Space>
<Space direction="vertical" size={2}> <Space direction="vertical" size={2}>
<Text> <Text>Operation</Text>
Operation <Text style={{ color: "#2D9CDB", fontSize: "12px" }}>{operation}</Text>
</Text>
<Text style={{ color: "#2D9CDB", fontSize: "12px" }}>
{operation}
</Text>
</Space> </Space>
</Space> </Space>
<Tabs defaultActiveKey="1"> <Tabs defaultActiveKey="1">
<TabPane tab="Tags" key="1"> <TabPane tab="Tags" key="1">
{spanTags && spanTags.map((tags, index) => { {spanTags &&
return ( spanTags.map((tags, index) => {
<> return (
{tags.value && ( <>
<> {tags.value && (
<Text style={{ color: "#BDBDBD", fontSize: "12px", marginBottom: "8px" }}> <>
{tags.key} <Text
</Text> style={{ color: "#BDBDBD", fontSize: "12px", marginBottom: "8px" }}
<div style={{ >
{tags.key}
</Text>
<div
style={{
background: "#4F4F4F",
color: "#2D9CDB",
fontSize: "12px",
padding: "6px 8px",
wordBreak: "break-all",
marginBottom: "16px",
}}
>
{tags.key === "error" ? "true" : tags.value}
</div>
</>
)}
</>
);
})}
</TabPane>
<TabPane tab="Errors" key="2">
{spanTags &&
spanTags
.filter((tags) => tags.key === "error")
.map((error) => (
<>
<Text
style={{ color: "#BDBDBD", fontSize: "12px", marginBottom: "8px" }}
>
{error.key}
</Text>
<div
style={{
background: "#4F4F4F", background: "#4F4F4F",
color: "#2D9CDB", color: "#2D9CDB",
fontSize: "12px", fontSize: "12px",
padding: "6px 8px", padding: "6px 8px",
wordBreak: "break-all", wordBreak: "break-all",
marginBottom: "16px", marginBottom: "16px",
}}> }}
{tags.key === "error" ? "true" : tags.value} >
</div> true
</> </div>
)} </>
</> ))}
);
})}
</TabPane>
<TabPane tab="Errors" key="2">
{spanTags && spanTags
.filter((tags) => tags.key === "error")
.map((error) => (
<>
<Text style={{ color: "#BDBDBD", fontSize: "12px", marginBottom: "8px" }}>
{error.key}
</Text>
<div style={{
background: "#4F4F4F",
color: "#2D9CDB",
fontSize: "12px",
padding: "6px 8px",
wordBreak: "break-all",
marginBottom: "16px",
}}>
true
</div>
</>
))}
</TabPane> </TabPane>
</Tabs> </Tabs>
</Card> </Card>

View File

@ -1,41 +0,0 @@
// Doing DFS traversal on the tree
// resultCount : how many entries you want. where -1 means all possible entries.
// func(obj) : takes one element of the data structure and returns true if need to select or not
// program to implement stack data structure
import { isEmpty } from "lodash-es";
const getTreeData = (tree, callback, resultCount = -1) => {
if (resultCount === 0 || isEmpty(tree) || tree.id === "empty") return null;
let data = tree;
let result = [];
let stk = [];
stk.push(data);
while (!isEmpty(stk)) {
let x = stk[stk.length - 1];
// marked means seeing the node for the second time.
if (x.marked) {
delete x.marked;
stk.pop();
x.map((item) => {
if (callback(item) === true) {
result.push(item);
if (resultCount !== -1 && result.length === resultCount) return result;
}
});
} else {
x.marked = true;
x.map((item) => {
if (item.children.length > 0) {
stk.push(item.children);
}
});
}
}
return result;
};
export default getTreeData;

View File

@ -1,13 +0,0 @@
.row-styles{
cursor: pointer
}
.hide{
display: none;
}
.ant-tabs-nav-list{
justify-content: space-between;
width: 100%;
}
.ant-table-body table {
margin-bottom: 64px;
}

View File

@ -0,0 +1,13 @@
.row-styles {
cursor: pointer;
}
.hide {
display: none;
}
.ant-tabs-nav-list {
justify-content: space-between;
width: 100%;
}
.ant-table-body table {
margin-bottom: 64px;
}

View File

@ -3,8 +3,8 @@ import { Table, Progress, Tabs, Button, Row, Col } from "antd";
import "./TraceGanttChart.css"; import "./TraceGanttChart.css";
import { max, isEmpty, has } from "lodash-es"; import { max, isEmpty, has } from "lodash-es";
import styled from "styled-components"; import styled from "styled-components";
import getTreeData from "Src/modules/Traces/TraceGantChartHelpers"; import { pushDStree } from "Src/store/actions";
import { pushDStree } from "../../store/actions"; import traverseTreeData from "Src/modules/Traces/TraceGanttChart/TraceGanttChartHelpers";
const { TabPane } = Tabs; const { TabPane } = Tabs;
@ -17,11 +17,11 @@ const StyledButton = styled(Button)`
`; `;
interface TraceGanttChartProps { interface TraceGanttChartProps {
treeData: pushDStree; treeData: pushDStree[];
clickedSpan: pushDStree; clickedSpan: pushDStree;
selectedSpan: pushDStree; selectedSpan: pushDStree;
resetZoom: () => {}; resetZoom: () => {};
setSpanTagsInfo: () => {}; setSpanTagsInfo: (p: { data: any }) => {};
} }
const TraceGanttChart = ({ const TraceGanttChart = ({
@ -37,12 +37,9 @@ const TraceGanttChart = ({
const [defaultExpandedRows, setDefaultExpandedRows] = useState([]); const [defaultExpandedRows, setDefaultExpandedRows] = useState([]);
const [sortedTreeData, setSortedTreeData] = useState(treeData); const [sortedTreeData, setSortedTreeData] = useState(treeData);
const [isReset, setIsReset] = useState(false); const [isReset, setIsReset] = useState(false);
const [rowId, setRowId] = useState(0);
const [tabsContainerWidth, setTabsContainerWidth] = useState(0); const [tabsContainerWidth, setTabsContainerWidth] = useState(0);
const tableRef = useRef(""); const tableRef = useRef("");
let tabsContainer = document.querySelector( let tabsContainer = document.querySelector("#collapsable .ant-tabs-nav-list");
"#collapsable .ant-tabs-nav-list",
);
let tabs = document.querySelectorAll("#collapsable .ant-tabs-tab"); let tabs = document.querySelectorAll("#collapsable .ant-tabs-tab");
@ -58,7 +55,7 @@ const TraceGanttChart = ({
if (clickedSpan) { if (clickedSpan) {
setClickedSpanData(clickedSpan); setClickedSpanData(clickedSpan);
} }
setTabsContainerWidth(tabsContainer?.offsetWidth) setTabsContainerWidth(tabsContainer?.offsetWidth);
} }
// handleScroll(selectedSpan?.id); // handleScroll(selectedSpan?.id);
}, [sortedTreeData, treeData, clickedSpan]); }, [sortedTreeData, treeData, clickedSpan]);
@ -67,13 +64,11 @@ const TraceGanttChart = ({
if ( if (
!isEmpty(clickedSpanData) && !isEmpty(clickedSpanData) &&
clickedSpan && clickedSpan &&
!selectedRows.includes(clickedSpan.id) !selectedRows.includes(clickedSpan.id) &&
&& !isReset !isReset
) { ) {
setSelectedRows([clickedSpan.id]); setSelectedRows([clickedSpan.id]);
getParentKeys(clickedSpan); getParentKeys(clickedSpan);
let keys = [clickedSpan?.id, ...parentKeys];
// setDefaultExpandedRows(keys)
handleFocusOnSelectedPath("", [clickedSpan.id], clickedSpan); handleFocusOnSelectedPath("", [clickedSpan.id], clickedSpan);
} }
}, [clickedSpan, selectedRows, isReset, clickedSpanData]); }, [clickedSpan, selectedRows, isReset, clickedSpanData]);
@ -87,17 +82,16 @@ const TraceGanttChart = ({
} }
}; };
const getChildrenKeys = (obj) =>{ const getChildrenKeys = (obj) => {
if (has(obj, "children")) { if (has(obj, "children")) {
childrenKeys.push(obj.id); childrenKeys.push(obj.id);
if(!isEmpty(obj.children)){ if (!isEmpty(obj.children)) {
obj.children.map((item)=>{ obj.children.map((item) => {
getChildrenKeys(item); getChildrenKeys(item);
}) });
} }
} }
} };
useEffect(() => { useEffect(() => {
if (!isEmpty(selectedSpan) && isEmpty(clickedSpan)) { if (!isEmpty(selectedSpan) && isEmpty(clickedSpan)) {
@ -111,7 +105,6 @@ const TraceGanttChart = ({
setDefaultExpandedRows([treeData?.[0]?.id]); setDefaultExpandedRows([treeData?.[0]?.id]);
// /.setSpanTagsInfo({data: treeData?.[0]}) // /.setSpanTagsInfo({data: treeData?.[0]})
} }
}, [selectedSpan, treeData]); }, [selectedSpan, treeData]);
const getMaxEndTime = (treeData) => { const getMaxEndTime = (treeData) => {
@ -142,7 +135,7 @@ const TraceGanttChart = ({
totalWidth = width of container totalWidth = width of container
*/ */
const getPaddingLeft = (timeDiff, totalTime, totalWidth) => { const getPaddingLeft = (timeDiff, totalTime, totalWidth) => {
return ((timeDiff / totalTime) * totalWidth ).toFixed(0); return ((timeDiff / totalTime) * totalWidth).toFixed(0);
}; };
let tabMinVal = 0; let tabMinVal = 0;
@ -178,14 +171,18 @@ const TraceGanttChart = ({
let paddingLeft = 0; let paddingLeft = 0;
let startTime = parseFloat(record.startTime); let startTime = parseFloat(record.startTime);
let duration = parseFloat((record.time / 1000000).toFixed(2)); let duration = parseFloat((record.time / 1000000).toFixed(2));
paddingLeft = parseInt(getPaddingLeft(startTime - minGlobal, maxGlobal - minGlobal, tabsContainerWidth)); paddingLeft = parseInt(
let textPadding = paddingLeft; getPaddingLeft(
if(paddingLeft === tabsContainerWidth - 20){ startTime - minGlobal,
textPadding = tabsContainerWidth - 40 maxGlobal - minGlobal,
} tabsContainerWidth,
length = ((duration / (maxGlobal - startTime)) * 100).toFixed( ),
2,
); );
let textPadding = paddingLeft;
if (paddingLeft === tabsContainerWidth - 20) {
textPadding = tabsContainerWidth - 40;
}
length = ((duration / (maxGlobal - startTime)) * 100).toFixed(2);
return ( return (
<> <>
@ -203,15 +200,22 @@ const TraceGanttChart = ({
const handleFocusOnSelectedPath = (event, selectedRowsList = selectedRows) => { const handleFocusOnSelectedPath = (event, selectedRowsList = selectedRows) => {
if (!isEmpty(selectedRowsList)) { if (!isEmpty(selectedRowsList)) {
let node: pushDStree = getTreeData( let node = {};
treeData, traverseTreeData(treeData, (item: pushDStree) => {
(item: pushDStree) => item.id === selectedRowsList[0], if (item.id === selectedRowsList[0]) {
1, node = item;
); }
setSpanTagsInfo({ data: node[0] }); });
getParentKeys(node[0]); try {
getChildrenKeys(node[0]); setSpanTagsInfo({ data: node });
} catch (e) {
// TODO: error logging.
console.error("Node not found in Tree Data.");
}
getParentKeys(node);
getChildrenKeys(node);
let rows = document.querySelectorAll("#collapsable table tbody tr"); let rows = document.querySelectorAll("#collapsable table tbody tr");
Array.from(rows).map((row) => { Array.from(rows).map((row) => {
@ -255,21 +259,26 @@ const TraceGanttChart = ({
setIsReset(false); setIsReset(false);
} }
}, },
onSelect:(record)=>{ onSelect: (record) => {
handleRowOnClick(record) handleRowOnClick(record);
}, },
selectedRowKeys: selectedRows, selectedRowKeys: selectedRows,
}; };
const handleRowOnClick = (record) => { const handleRowOnClick = (record) => {
setRowId(record.id); let node = {};
traverseTreeData(treeData, (item: pushDStree) => {
if (item.id === record.id) {
node = item;
}
});
let node: pushDStree = getTreeData( try {
treeData, setSpanTagsInfo({ data: node });
(item: pushDStree) => item.id === record.id, } catch (e) {
1, // TODO: error logging.
); console.error("Node not found in TreeData.");
setSpanTagsInfo({ data: node[0] }); }
const selectedRowKeys = selectedRows; const selectedRowKeys = selectedRows;
if (selectedRowKeys.indexOf(record.id) >= 0) { if (selectedRowKeys.indexOf(record.id) >= 0) {
@ -310,7 +319,7 @@ const TraceGanttChart = ({
refs={tableRef} refs={tableRef}
hideSelectAll={true} hideSelectAll={true}
columns={columns} columns={columns}
rowSelection={{ ...rowSelection, checkStrictly, type:'radio' }} rowSelection={{ ...rowSelection, checkStrictly, type: "radio" }}
dataSource={sortedTreeData} dataSource={sortedTreeData}
rowKey="id" rowKey="id"
sticky={true} sticky={true}
@ -322,7 +331,7 @@ const TraceGanttChart = ({
expandedRowKeys={defaultExpandedRows} expandedRowKeys={defaultExpandedRows}
onExpandedRowsChange={handleOnExpandedRowsChange} onExpandedRowsChange={handleOnExpandedRowsChange}
pagination={false} pagination={false}
scroll={{ y: 540}} scroll={{ y: 540 }}
rowClassName="row-styles" rowClassName="row-styles"
filterMultiple={false} filterMultiple={false}
/> />

View File

@ -0,0 +1,40 @@
import { isEmpty } from "lodash-es";
import { pushDStree } from "Src/store/actions";
interface itemProps {
treeData: pushDStree[];
marked: boolean;
}
// Doing DFS traversal on the tree.
// Callback to be called for each element in the tree once.
const traverseTreeData = (
tree: pushDStree[],
callback: (item: pushDStree) => void,
): void => {
if (isEmpty(tree) || tree[0].id === "empty") return;
let node = { treeData: tree, marked: false };
let stk: [itemProps] = [node];
while (!isEmpty(stk)) {
let x = stk[stk.length - 1];
// marked means seeing the node for the second time.
if (x.marked) {
x.marked = false;
stk.pop();
x.treeData.map((item: pushDStree) => {
callback(item);
});
} else {
x.marked = true;
x.treeData.map((item) => {
if (item.children.length > 0) {
stk.push({ treeData: item.children, marked: false });
}
});
}
}
};
export default traverseTreeData;

View File

@ -0,0 +1 @@
export { default } from "./TraceGanttChart";

View File

@ -6,13 +6,13 @@ import { Card, Row, Col, Space, Affix } from "antd";
import * as d3 from "d3"; import * as d3 from "d3";
import * as d3Tip from "d3-tip"; import * as d3Tip from "d3-tip";
import "./TraceGraph.css"; import "./TraceGraph.css";
import { spanToTreeUtil } from "../../utils/spanToTree"; import { spanToTreeUtil } from "Src/utils/spanToTree";
import { import {
fetchTraceItem, fetchTraceItem,
pushDStree, pushDStree,
spansWSameTraceIDResponse, spansWSameTraceIDResponse,
} from "../../store/actions"; } from "../../store/actions";
import { StoreState } from "../../store/reducers"; import { StoreState } from "Src/store/reducers";
import SelectedSpanDetails from "./SelectedSpanDetails"; import SelectedSpanDetails from "./SelectedSpanDetails";
import TraceGanttChart from "./TraceGanttChart"; import TraceGanttChart from "./TraceGanttChart";
import styled from "styled-components"; import styled from "styled-components";
@ -36,11 +36,11 @@ const _TraceGraph = (props: TraceGraphProps) => {
const [selectedSpan, setSelectedSpan] = useState({}); const [selectedSpan, setSelectedSpan] = useState({});
const [clickedSpan, setClickedSpan] = useState(null); const [clickedSpan, setClickedSpan] = useState(null);
const [resetZoom, setResetZoom] = useState(false); const [resetZoom, setResetZoom] = useState(false);
const [sortedTreeData, setSortedTreeData] = useState<pushDStree>([]); const [sortedTreeData, setSortedTreeData] = useState<pushDStree[]>([]);
let sortedData = {}; let sortedData = {};
const getSortedData = (treeData: [pushDStree], parent = {}) => { const getSortedData = (treeData: pushDStree[], parent = {}) => {
if (!isEmpty(treeData)) { if (!isEmpty(treeData)) {
if (treeData[0].id !== "empty") { if (treeData[0].id !== "empty") {
return Array.from(treeData).map((item, key) => { return Array.from(treeData).map((item, key) => {