mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-01-10 15:14:09 +00:00
parent
300d701df0
commit
81b5db04f6
5 changed files with 93 additions and 9 deletions
|
@ -14,13 +14,14 @@ interface RecursiveProps {
|
|||
isRoot?: boolean;
|
||||
trace: Trace;
|
||||
totalMsec: number;
|
||||
isExpandedAll? : boolean;
|
||||
}
|
||||
|
||||
interface OpenLevels {
|
||||
[x: number]: boolean
|
||||
}
|
||||
|
||||
const NestedNav: FC<RecursiveProps> = ({ isRoot, trace, totalMsec }) => {
|
||||
const NestedNav: FC<RecursiveProps> = ({ isRoot, trace, totalMsec, isExpandedAll }) => {
|
||||
const { isDarkTheme } = useAppState();
|
||||
const { isMobile } = useDeviceDetect();
|
||||
const [openLevels, setOpenLevels] = useState({} as OpenLevels);
|
||||
|
@ -53,6 +54,26 @@ const NestedNav: FC<RecursiveProps> = ({ isRoot, trace, totalMsec }) => {
|
|||
});
|
||||
};
|
||||
|
||||
const getIdsFromChildren = (tracingData: Trace) => {
|
||||
const ids = [tracingData.idValue];
|
||||
tracingData?.children?.forEach((child) => {
|
||||
ids.push(...getIdsFromChildren(child));
|
||||
});
|
||||
return ids;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!isExpandedAll) {
|
||||
setOpenLevels([]);
|
||||
return;
|
||||
}
|
||||
|
||||
const allIds = getIdsFromChildren(trace);
|
||||
const openLevels = {} as OpenLevels;
|
||||
allIds.forEach(id => { openLevels[id] = true; });
|
||||
setOpenLevels(openLevels);
|
||||
}, [isExpandedAll]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames({
|
||||
|
@ -106,13 +127,14 @@ const NestedNav: FC<RecursiveProps> = ({ isRoot, trace, totalMsec }) => {
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
{openLevels[trace.idValue] && (
|
||||
{(openLevels[trace.idValue]) && (
|
||||
<div className="vm-nested-nav__childrens">
|
||||
{hasChildren && trace.children.map((trace) => (
|
||||
<NestedNav
|
||||
key={trace.duration}
|
||||
trace={trace}
|
||||
totalMsec={totalMsec}
|
||||
isExpandedAll={isExpandedAll}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
$color-base-nested-nav: $color-tropical-blue;
|
||||
$color-base-nested-nav-dark: $color-background-body;
|
||||
$width-line: 2px;
|
||||
$left-position: calc(-1 * $padding-small);
|
||||
|
||||
.vm-nested-nav {
|
||||
position: relative;
|
||||
|
@ -48,19 +50,19 @@ $color-base-nested-nav-dark: $color-background-body;
|
|||
content: "";
|
||||
position: absolute;
|
||||
top: calc(50% - 1px);
|
||||
height: 2px;
|
||||
height: $width-line;
|
||||
width: $padding-small;
|
||||
background-color: $color-base-nested-nav;
|
||||
left: calc(-1 * $padding-small);
|
||||
left: $left-position;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 50%;
|
||||
left: calc(-1 * $padding-small);
|
||||
left: $left-position;
|
||||
height: calc(50% + $padding-small);
|
||||
width: 2px;
|
||||
width: $width-line;
|
||||
background-color: $color-base-nested-nav;
|
||||
}
|
||||
|
||||
|
@ -122,9 +124,9 @@ $color-base-nested-nav-dark: $color-background-body;
|
|||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(-1 * $padding-small);
|
||||
left: $left-position;
|
||||
height: 100%;
|
||||
width: 2px;
|
||||
width: $width-line;
|
||||
background-color: $color-base-nested-nav;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { FC, useState } from "preact/compat";
|
||||
import Trace from "./Trace";
|
||||
import Button from "../Main/Button/Button";
|
||||
import { CodeIcon, DeleteIcon } from "../Main/Icons";
|
||||
import { ArrowDownIcon, CodeIcon, DeleteIcon, DownloadIcon } from "../Main/Icons";
|
||||
import "./style.scss";
|
||||
import NestedNav from "./NestedNav/NestedNav";
|
||||
import Alert from "../Main/Alert/Alert";
|
||||
|
@ -20,6 +20,7 @@ interface TraceViewProps {
|
|||
const TracingsView: FC<TraceViewProps> = ({ traces, jsonEditor = false, onDeleteClick }) => {
|
||||
const { isMobile } = useDeviceDetect();
|
||||
const [openTrace, setOpenTrace] = useState<Trace | null>(null);
|
||||
const [expandedTraces, setExpandedTraces] = useState<number[]>([]);
|
||||
|
||||
const handleCloseJson = () => {
|
||||
setOpenTrace(null);
|
||||
|
@ -52,6 +53,27 @@ const TracingsView: FC<TraceViewProps> = ({ traces, jsonEditor = false, onDelete
|
|||
setOpenTrace(tracingData);
|
||||
};
|
||||
|
||||
const handleSaveToFile = (tracingData: Trace) => () => {
|
||||
const blob = new Blob([tracingData.originalJSON], { type: "application/json" });
|
||||
const href = URL.createObjectURL(blob);
|
||||
|
||||
const link = document.createElement("a");
|
||||
link.href = href;
|
||||
link.download = `vmui_trace_${tracingData.queryValue}.json`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(href);
|
||||
};
|
||||
|
||||
const handleExpandAll = (tracingData: Trace) => () => {
|
||||
setExpandedTraces(prev => prev.includes(tracingData.idValue)
|
||||
? prev.filter(n => n !== tracingData.idValue)
|
||||
: [...prev, tracingData.idValue]
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="vm-tracings-view">
|
||||
|
@ -64,6 +86,28 @@ const TracingsView: FC<TraceViewProps> = ({ traces, jsonEditor = false, onDelete
|
|||
<h3 className="vm-tracings-view-trace-header-title">
|
||||
Trace for <b className="vm-tracings-view-trace-header-title__query">{trace.queryValue}</b>
|
||||
</h3>
|
||||
<Tooltip title={expandedTraces.includes(trace.idValue) ? "Collapse All" : "Expand All"}>
|
||||
<Button
|
||||
variant="text"
|
||||
startIcon={(
|
||||
<div
|
||||
className={classNames({
|
||||
"vm-tracings-view-trace-header__expand-icon": true,
|
||||
"vm-tracings-view-trace-header__expand-icon_open": expandedTraces.includes(trace.idValue) })}
|
||||
><ArrowDownIcon/></div>
|
||||
)}
|
||||
onClick={handleExpandAll(trace)}
|
||||
ariaLabel={expandedTraces.includes(trace.idValue) ? "Collapse All" : "Expand All"}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={"Save Trace to JSON"}>
|
||||
<Button
|
||||
variant="text"
|
||||
startIcon={<DownloadIcon/>}
|
||||
onClick={handleSaveToFile(trace)}
|
||||
ariaLabel="Save trace to JSON"
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={"Open JSON"}>
|
||||
<Button
|
||||
variant="text"
|
||||
|
@ -92,6 +136,7 @@ const TracingsView: FC<TraceViewProps> = ({ traces, jsonEditor = false, onDelete
|
|||
isRoot
|
||||
trace={trace}
|
||||
totalMsec={trace.duration}
|
||||
isExpandedAll={expandedTraces.includes(trace.idValue)}
|
||||
/>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
@ -21,6 +21,20 @@
|
|||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
&__expand-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 20px;
|
||||
transition: transform 200ms ease-in-out;
|
||||
transform: rotate(-90deg);
|
||||
color: $color-text-secondary;
|
||||
|
||||
&_open {
|
||||
transform: rotate(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__nav {
|
||||
|
|
|
@ -64,6 +64,7 @@ The sandbox cluster installation is running under the constant load generated by
|
|||
- add an `Export query` button to the graph that saves the result of executing the query in `JSON`. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5497).
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add `-vmui.defaultTimezone` flag to set a default timezone. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5375) and [these docs](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/app/vmui#timezone-configuration).
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): include UTC in the timezone selection dropdown for standardized time referencing. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5375).
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add the ability to expand/collapse all tracing entries and download tracing data in .json format. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5677).
|
||||
* FEATURE: add [VictoriaMetrics datasource](https://github.com/VictoriaMetrics/grafana-datasource) to docker compose environment. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5363).
|
||||
|
||||
* BUGFIX: properly return the list of matching label names and label values from [`/api/v1/labels`](https://docs.victoriametrics.com/url-examples.html#apiv1labels) and [`/api/v1/label/.../values`](https://docs.victoriametrics.com/url-examples.html#apiv1labelvalues) when the database contains more than `-search.maxUniqueTimeseries` unique [time series](https://docs.victoriametrics.com/keyConcepts.html#time-series) on the selected time range. Previously VictoriaMetrics could return `the number of matching timeseries exceeds ...` error in this case. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5055).
|
||||
|
|
Loading…
Reference in a new issue