mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-03-11 15:34:56 +00:00
vmui: improve the appearance of the trace (#5091)
This commit is contained in:
parent
34961dd4b8
commit
133425f0c0
5 changed files with 108 additions and 23 deletions
|
@ -32,6 +32,10 @@ $padding-modal: $padding-medium;
|
|||
&-header {
|
||||
padding: $padding-small $padding-small $padding-small $padding-global;
|
||||
margin-bottom: $padding-global;
|
||||
|
||||
&__title {
|
||||
max-width: 80vw;
|
||||
}
|
||||
}
|
||||
|
||||
&-body {
|
||||
|
@ -69,6 +73,10 @@ $padding-modal: $padding-medium;
|
|||
&__title {
|
||||
font-weight: bold;
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 50vw;
|
||||
}
|
||||
|
||||
&__close {
|
||||
|
|
|
@ -8,8 +8,10 @@ import classNames from "classnames";
|
|||
import { useAppState } from "../../../state/common/StateContext";
|
||||
import useDeviceDetect from "../../../hooks/useDeviceDetect";
|
||||
import Button from "../../Main/Button/Button";
|
||||
import { humanizeSeconds } from "../../../utils/time";
|
||||
|
||||
interface RecursiveProps {
|
||||
isRoot?: boolean;
|
||||
trace: Trace;
|
||||
totalMsec: number;
|
||||
}
|
||||
|
@ -18,7 +20,7 @@ interface OpenLevels {
|
|||
[x: number]: boolean
|
||||
}
|
||||
|
||||
const NestedNav: FC<RecursiveProps> = ({ trace, totalMsec }) => {
|
||||
const NestedNav: FC<RecursiveProps> = ({ isRoot, trace, totalMsec }) => {
|
||||
const { isDarkTheme } = useAppState();
|
||||
const { isMobile } = useDeviceDetect();
|
||||
const [openLevels, setOpenLevels] = useState({} as OpenLevels);
|
||||
|
@ -27,6 +29,8 @@ const NestedNav: FC<RecursiveProps> = ({ trace, totalMsec }) => {
|
|||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const [showFullMessage, setShowFullMessage] = useState(false);
|
||||
|
||||
const duration = humanizeSeconds(trace.duration / 1000) || `${trace.duration}ms`;
|
||||
|
||||
useEffect(() => {
|
||||
if (!messageRef.current) return;
|
||||
const contentElement = messageRef.current;
|
||||
|
@ -40,24 +44,29 @@ const NestedNav: FC<RecursiveProps> = ({ trace, totalMsec }) => {
|
|||
setShowFullMessage(prev => !prev);
|
||||
};
|
||||
|
||||
const hasChildren = trace.children && !!trace.children.length;
|
||||
const progress = trace.duration / totalMsec * 100;
|
||||
const handleListClick = (level: number) => () => {
|
||||
if (!hasChildren) return;
|
||||
setOpenLevels((prevState:OpenLevels) => {
|
||||
return { ...prevState, [level]: !prevState[level] };
|
||||
});
|
||||
};
|
||||
const hasChildren = trace.children && !!trace.children.length;
|
||||
const progress = trace.duration / totalMsec * 100;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames({
|
||||
"vm-nested-nav": true,
|
||||
"vm-nested-nav_root": isRoot,
|
||||
"vm-nested-nav_dark": isDarkTheme,
|
||||
"vm-nested-nav_mobile": isMobile,
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className="vm-nested-nav-header"
|
||||
className={classNames({
|
||||
"vm-nested-nav-header": true,
|
||||
"vm-nested-nav-header_open": openLevels[trace.idValue],
|
||||
})}
|
||||
onClick={handleListClick(trace.idValue)}
|
||||
>
|
||||
{hasChildren && (
|
||||
|
@ -84,7 +93,7 @@ const NestedNav: FC<RecursiveProps> = ({ trace, totalMsec }) => {
|
|||
</div>
|
||||
<div className="vm-nested-nav-header-bottom">
|
||||
<div className="vm-nested-nav-header-bottom__duration">
|
||||
{`duration: ${trace.duration} ms`}
|
||||
{`duration: ${duration}`}
|
||||
</div>
|
||||
{(isExpanded || showFullMessage) && (
|
||||
<Button
|
||||
|
@ -97,15 +106,17 @@ const NestedNav: FC<RecursiveProps> = ({ trace, totalMsec }) => {
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
{openLevels[trace.idValue] && <div>
|
||||
{hasChildren && trace.children.map((trace) => (
|
||||
<NestedNav
|
||||
key={trace.duration}
|
||||
trace={trace}
|
||||
totalMsec={totalMsec}
|
||||
/>
|
||||
))}
|
||||
</div>}
|
||||
{openLevels[trace.idValue] && (
|
||||
<div className="vm-nested-nav__childrens">
|
||||
{hasChildren && trace.children.map((trace) => (
|
||||
<NestedNav
|
||||
key={trace.duration}
|
||||
trace={trace}
|
||||
totalMsec={totalMsec}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,29 +1,71 @@
|
|||
@use "src/styles/variables" as *;
|
||||
|
||||
$color-base-nested-nav: $color-tropical-blue;
|
||||
$color-base-nested-nav-dark: $color-background-body;
|
||||
|
||||
.vm-nested-nav {
|
||||
margin-left: $padding-medium;
|
||||
position: relative;
|
||||
margin-left: $padding-global;
|
||||
border-radius: $border-radius-small;
|
||||
background-color: rgba($color-tropical-blue, 0.4);
|
||||
|
||||
&_dark &-header {
|
||||
background-color: $color-base-nested-nav-dark;
|
||||
|
||||
&:after, &:before {
|
||||
background-color: $color-base-nested-nav-dark;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: rgba($color-white, 0.08) 0 0 0 1px;
|
||||
}
|
||||
}
|
||||
|
||||
&_mobile {
|
||||
margin-left: $padding-small;
|
||||
}
|
||||
|
||||
&_dark {
|
||||
background-color: rgba($color-black, 0.1);
|
||||
&_root > &-header {
|
||||
&:before,
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-header {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: $padding-small;
|
||||
padding: $padding-small;
|
||||
border-radius: $border-radius-small;
|
||||
transition: background-color 200ms ease-in-out;
|
||||
transition: box-shadow 200ms ease-in-out;
|
||||
cursor: pointer;
|
||||
background-color: rgba($color-base-nested-nav, 0.4);
|
||||
margin-bottom: $padding-small;
|
||||
z-index: 2;
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: calc(50% - 1px);
|
||||
height: 2px;
|
||||
width: $padding-small;
|
||||
background-color: $color-base-nested-nav;
|
||||
left: calc(-1 * $padding-small);
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 50%;
|
||||
left: calc($padding-global / -2);
|
||||
height: calc(50% + $padding-small);
|
||||
width: 2px;
|
||||
background-color: $color-base-nested-nav;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $color-hover-black;
|
||||
box-shadow: rgba($color-black, 0.08) 0 0 0 1px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
|
@ -32,9 +74,11 @@
|
|||
justify-content: center;
|
||||
width: 20px;
|
||||
transition: transform 200ms ease-in-out;
|
||||
transform: rotate(-90deg);
|
||||
color: $color-text-secondary;
|
||||
|
||||
&_open {
|
||||
transform: rotate(180deg);
|
||||
transform: rotate(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,4 +116,22 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__childrens > .vm-nested-nav:not(:last-child) {
|
||||
&:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc($padding-global / -2);
|
||||
height: 100%;
|
||||
width: 2px;
|
||||
background-color: $color-base-nested-nav;
|
||||
}
|
||||
}
|
||||
|
||||
&__childrens > .vm-nested-nav_dark:not(:last-child) {
|
||||
&:before {
|
||||
background-color: $color-base-nested-nav-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ const TracingsView: FC<TraceViewProps> = ({ traces, jsonEditor = false, onDelete
|
|||
})}
|
||||
>
|
||||
<NestedNav
|
||||
isRoot
|
||||
trace={trace}
|
||||
totalMsec={trace.duration}
|
||||
/>
|
||||
|
|
|
@ -30,6 +30,10 @@ const shortDurations = supportedDurations.map(d => d.short);
|
|||
|
||||
export const roundToMilliseconds = (num: number): number => Math.round(num*1000)/1000;
|
||||
|
||||
export const humanizeSeconds = (num: number): string => {
|
||||
return getDurationFromMilliseconds(dayjs.duration(num, "seconds").asMilliseconds());
|
||||
};
|
||||
|
||||
export const roundStep = (step: number) => {
|
||||
let result = roundToMilliseconds(step);
|
||||
const integerStep = Math.round(step);
|
||||
|
@ -46,8 +50,7 @@ export const roundStep = (step: number) => {
|
|||
if (step < 1 && step > 0.01) {
|
||||
result = Math.round(step * 40) / 40; // float to thousandths multiple of 5
|
||||
}
|
||||
|
||||
const humanize = getDurationFromMilliseconds(dayjs.duration(result || 0.001, "seconds").asMilliseconds());
|
||||
const humanize = humanizeSeconds(result || 0.001);
|
||||
return humanize.replace(/\s/g, "");
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue