mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-04 04:10:41 +08:00
Merge pull request #195 from SigNoz/refactor-gant-chart
refactor(FE: trace-gantt-chart): add ts support and change folder structure
This commit is contained in:
commit
7917b5f3b4
@ -48,7 +48,7 @@ const CustomSubText = styled(Paragraph)`
|
||||
`;
|
||||
|
||||
const SelectedSpanDetails = (props: SelectedSpanDetailsProps) => {
|
||||
const spanTags = props.data.tags;
|
||||
const spanTags = props.data?.tags;
|
||||
const service = props.data?.name?.split(":")[0];
|
||||
const operation = props.data?.name?.split(":")[1];
|
||||
|
||||
|
@ -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;
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -3,8 +3,8 @@ import { Table, Progress, Tabs, Button, Row, Col } from "antd";
|
||||
import "./TraceGanttChart.css";
|
||||
import { max, isEmpty, has } from "lodash-es";
|
||||
import styled from "styled-components";
|
||||
import getTreeData from "Src/modules/Traces/TraceGantChartHelpers";
|
||||
import { pushDStree } from "../../store/actions";
|
||||
import { pushDStree } from "Src/store/actions";
|
||||
import traverseTreeData from "Src/modules/Traces/TraceGanttChart/TraceGanttChartHelpers";
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
@ -17,11 +17,11 @@ const StyledButton = styled(Button)`
|
||||
`;
|
||||
|
||||
interface TraceGanttChartProps {
|
||||
treeData: pushDStree;
|
||||
treeData: pushDStree[];
|
||||
clickedSpan: pushDStree;
|
||||
selectedSpan: pushDStree;
|
||||
resetZoom: () => {};
|
||||
setSpanTagsInfo: () => {};
|
||||
setSpanTagsInfo: (p: { data: any }) => {};
|
||||
}
|
||||
|
||||
const TraceGanttChart = ({
|
||||
@ -37,12 +37,9 @@ const TraceGanttChart = ({
|
||||
const [defaultExpandedRows, setDefaultExpandedRows] = useState([]);
|
||||
const [sortedTreeData, setSortedTreeData] = useState(treeData);
|
||||
const [isReset, setIsReset] = useState(false);
|
||||
const [rowId, setRowId] = useState(0);
|
||||
const [tabsContainerWidth, setTabsContainerWidth] = useState(0);
|
||||
const tableRef = useRef("");
|
||||
let tabsContainer = document.querySelector(
|
||||
"#collapsable .ant-tabs-nav-list",
|
||||
);
|
||||
let tabsContainer = document.querySelector("#collapsable .ant-tabs-nav-list");
|
||||
|
||||
let tabs = document.querySelectorAll("#collapsable .ant-tabs-tab");
|
||||
|
||||
@ -58,7 +55,7 @@ const TraceGanttChart = ({
|
||||
if (clickedSpan) {
|
||||
setClickedSpanData(clickedSpan);
|
||||
}
|
||||
setTabsContainerWidth(tabsContainer?.offsetWidth)
|
||||
setTabsContainerWidth(tabsContainer?.offsetWidth);
|
||||
}
|
||||
// handleScroll(selectedSpan?.id);
|
||||
}, [sortedTreeData, treeData, clickedSpan]);
|
||||
@ -67,13 +64,11 @@ const TraceGanttChart = ({
|
||||
if (
|
||||
!isEmpty(clickedSpanData) &&
|
||||
clickedSpan &&
|
||||
!selectedRows.includes(clickedSpan.id)
|
||||
&& !isReset
|
||||
!selectedRows.includes(clickedSpan.id) &&
|
||||
!isReset
|
||||
) {
|
||||
setSelectedRows([clickedSpan.id]);
|
||||
getParentKeys(clickedSpan);
|
||||
let keys = [clickedSpan?.id, ...parentKeys];
|
||||
// setDefaultExpandedRows(keys)
|
||||
handleFocusOnSelectedPath("", [clickedSpan.id], clickedSpan);
|
||||
}
|
||||
}, [clickedSpan, selectedRows, isReset, clickedSpanData]);
|
||||
@ -87,17 +82,16 @@ const TraceGanttChart = ({
|
||||
}
|
||||
};
|
||||
|
||||
const getChildrenKeys = (obj) =>{
|
||||
const getChildrenKeys = (obj) => {
|
||||
if (has(obj, "children")) {
|
||||
childrenKeys.push(obj.id);
|
||||
if(!isEmpty(obj.children)){
|
||||
obj.children.map((item)=>{
|
||||
if (!isEmpty(obj.children)) {
|
||||
obj.children.map((item) => {
|
||||
getChildrenKeys(item);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!isEmpty(selectedSpan) && isEmpty(clickedSpan)) {
|
||||
@ -111,7 +105,6 @@ const TraceGanttChart = ({
|
||||
setDefaultExpandedRows([treeData?.[0]?.id]);
|
||||
// /.setSpanTagsInfo({data: treeData?.[0]})
|
||||
}
|
||||
|
||||
}, [selectedSpan, treeData]);
|
||||
|
||||
const getMaxEndTime = (treeData) => {
|
||||
@ -142,7 +135,7 @@ const TraceGanttChart = ({
|
||||
totalWidth = width of container
|
||||
*/
|
||||
const getPaddingLeft = (timeDiff, totalTime, totalWidth) => {
|
||||
return ((timeDiff / totalTime) * totalWidth ).toFixed(0);
|
||||
return ((timeDiff / totalTime) * totalWidth).toFixed(0);
|
||||
};
|
||||
|
||||
let tabMinVal = 0;
|
||||
@ -178,14 +171,18 @@ const TraceGanttChart = ({
|
||||
let paddingLeft = 0;
|
||||
let startTime = parseFloat(record.startTime);
|
||||
let duration = parseFloat((record.time / 1000000).toFixed(2));
|
||||
paddingLeft = parseInt(getPaddingLeft(startTime - minGlobal, maxGlobal - minGlobal, tabsContainerWidth));
|
||||
let textPadding = paddingLeft;
|
||||
if(paddingLeft === tabsContainerWidth - 20){
|
||||
textPadding = tabsContainerWidth - 40
|
||||
}
|
||||
length = ((duration / (maxGlobal - startTime)) * 100).toFixed(
|
||||
2,
|
||||
paddingLeft = parseInt(
|
||||
getPaddingLeft(
|
||||
startTime - minGlobal,
|
||||
maxGlobal - minGlobal,
|
||||
tabsContainerWidth,
|
||||
),
|
||||
);
|
||||
let textPadding = paddingLeft;
|
||||
if (paddingLeft === tabsContainerWidth - 20) {
|
||||
textPadding = tabsContainerWidth - 40;
|
||||
}
|
||||
length = ((duration / (maxGlobal - startTime)) * 100).toFixed(2);
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -203,15 +200,22 @@ const TraceGanttChart = ({
|
||||
|
||||
const handleFocusOnSelectedPath = (event, selectedRowsList = selectedRows) => {
|
||||
if (!isEmpty(selectedRowsList)) {
|
||||
let node: pushDStree = getTreeData(
|
||||
treeData,
|
||||
(item: pushDStree) => item.id === selectedRowsList[0],
|
||||
1,
|
||||
);
|
||||
setSpanTagsInfo({ data: node[0] });
|
||||
let node = {};
|
||||
traverseTreeData(treeData, (item: pushDStree) => {
|
||||
if (item.id === selectedRowsList[0]) {
|
||||
node = item;
|
||||
}
|
||||
});
|
||||
|
||||
getParentKeys(node[0]);
|
||||
getChildrenKeys(node[0]);
|
||||
try {
|
||||
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");
|
||||
Array.from(rows).map((row) => {
|
||||
@ -255,21 +259,26 @@ const TraceGanttChart = ({
|
||||
setIsReset(false);
|
||||
}
|
||||
},
|
||||
onSelect:(record)=>{
|
||||
handleRowOnClick(record)
|
||||
onSelect: (record) => {
|
||||
handleRowOnClick(record);
|
||||
},
|
||||
selectedRowKeys: selectedRows,
|
||||
};
|
||||
|
||||
const handleRowOnClick = (record) => {
|
||||
setRowId(record.id);
|
||||
let node = {};
|
||||
traverseTreeData(treeData, (item: pushDStree) => {
|
||||
if (item.id === record.id) {
|
||||
node = item;
|
||||
}
|
||||
});
|
||||
|
||||
let node: pushDStree = getTreeData(
|
||||
treeData,
|
||||
(item: pushDStree) => item.id === record.id,
|
||||
1,
|
||||
);
|
||||
setSpanTagsInfo({ data: node[0] });
|
||||
try {
|
||||
setSpanTagsInfo({ data: node });
|
||||
} catch (e) {
|
||||
// TODO: error logging.
|
||||
console.error("Node not found in TreeData.");
|
||||
}
|
||||
|
||||
const selectedRowKeys = selectedRows;
|
||||
if (selectedRowKeys.indexOf(record.id) >= 0) {
|
||||
@ -310,7 +319,7 @@ const TraceGanttChart = ({
|
||||
refs={tableRef}
|
||||
hideSelectAll={true}
|
||||
columns={columns}
|
||||
rowSelection={{ ...rowSelection, checkStrictly, type:'radio' }}
|
||||
rowSelection={{ ...rowSelection, checkStrictly, type: "radio" }}
|
||||
dataSource={sortedTreeData}
|
||||
rowKey="id"
|
||||
sticky={true}
|
||||
@ -322,7 +331,7 @@ const TraceGanttChart = ({
|
||||
expandedRowKeys={defaultExpandedRows}
|
||||
onExpandedRowsChange={handleOnExpandedRowsChange}
|
||||
pagination={false}
|
||||
scroll={{ y: 540}}
|
||||
scroll={{ y: 540 }}
|
||||
rowClassName="row-styles"
|
||||
filterMultiple={false}
|
||||
/>
|
@ -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;
|
1
frontend/src/modules/Traces/TraceGanttChart/index.js
Normal file
1
frontend/src/modules/Traces/TraceGanttChart/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default } from "./TraceGanttChart";
|
@ -6,13 +6,13 @@ import { Card, Row, Col, Space, Affix } from "antd";
|
||||
import * as d3 from "d3";
|
||||
import * as d3Tip from "d3-tip";
|
||||
import "./TraceGraph.css";
|
||||
import { spanToTreeUtil } from "../../utils/spanToTree";
|
||||
import { spanToTreeUtil } from "Src/utils/spanToTree";
|
||||
import {
|
||||
fetchTraceItem,
|
||||
pushDStree,
|
||||
spansWSameTraceIDResponse,
|
||||
} from "../../store/actions";
|
||||
import { StoreState } from "../../store/reducers";
|
||||
import { StoreState } from "Src/store/reducers";
|
||||
import SelectedSpanDetails from "./SelectedSpanDetails";
|
||||
import TraceGanttChart from "./TraceGanttChart";
|
||||
import styled from "styled-components";
|
||||
@ -36,11 +36,11 @@ const _TraceGraph = (props: TraceGraphProps) => {
|
||||
const [selectedSpan, setSelectedSpan] = useState({});
|
||||
const [clickedSpan, setClickedSpan] = useState(null);
|
||||
const [resetZoom, setResetZoom] = useState(false);
|
||||
const [sortedTreeData, setSortedTreeData] = useState<pushDStree>([]);
|
||||
const [sortedTreeData, setSortedTreeData] = useState<pushDStree[]>([]);
|
||||
|
||||
let sortedData = {};
|
||||
|
||||
const getSortedData = (treeData: [pushDStree], parent = {}) => {
|
||||
const getSortedData = (treeData: pushDStree[], parent = {}) => {
|
||||
if (!isEmpty(treeData)) {
|
||||
if (treeData[0].id !== "empty") {
|
||||
return Array.from(treeData).map((item, key) => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user