mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-01-20 07:19:17 +01:00
feat: copy pairs on click in legend (#2087)
This commit is contained in:
parent
ede93469ea
commit
e46b7d33a7
@ -1,9 +1,10 @@
|
|||||||
import React, {FC, useMemo} from "preact/compat";
|
import React, {FC, useMemo, useState} from "preact/compat";
|
||||||
import {hexToRGB} from "../../utils/color";
|
import {hexToRGB} from "../../utils/color";
|
||||||
import {useAppState} from "../../state/common/StateContext";
|
import {useAppState} from "../../state/common/StateContext";
|
||||||
import {LegendItem} from "../../utils/uplot/types";
|
import {LegendItem} from "../../utils/uplot/types";
|
||||||
import "./legend.css";
|
import "./legend.css";
|
||||||
import {getDashLine} from "../../utils/uplot/helpers";
|
import {getDashLine} from "../../utils/uplot/helpers";
|
||||||
|
import Tooltip from "@mui/material/Tooltip";
|
||||||
|
|
||||||
export interface LegendProps {
|
export interface LegendProps {
|
||||||
labels: LegendItem[];
|
labels: LegendItem[];
|
||||||
@ -13,10 +14,18 @@ export interface LegendProps {
|
|||||||
const Legend: FC<LegendProps> = ({labels, onChange}) => {
|
const Legend: FC<LegendProps> = ({labels, onChange}) => {
|
||||||
const {query} = useAppState();
|
const {query} = useAppState();
|
||||||
|
|
||||||
|
const [copiedValue, setCopiedValue] = useState("");
|
||||||
|
|
||||||
const groups = useMemo(() => {
|
const groups = useMemo(() => {
|
||||||
return Array.from(new Set(labels.map(l => l.group)));
|
return Array.from(new Set(labels.map(l => l.group)));
|
||||||
}, [labels]);
|
}, [labels]);
|
||||||
|
|
||||||
|
const handleClickFreeField = async (val: string, id: string) => {
|
||||||
|
await navigator.clipboard.writeText(val);
|
||||||
|
setCopiedValue(id);
|
||||||
|
setTimeout(() => setCopiedValue(""), 2000);
|
||||||
|
};
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<div className="legendWrapper">
|
<div className="legendWrapper">
|
||||||
{groups.map((group) => <div className="legendGroup" key={group}>
|
{groups.map((group) => <div className="legendGroup" key={group}>
|
||||||
@ -39,7 +48,25 @@ const Legend: FC<LegendProps> = ({labels, onChange}) => {
|
|||||||
borderColor: legendItem.color,
|
borderColor: legendItem.color,
|
||||||
backgroundColor: `rgba(${hexToRGB(legendItem.color)}, 0.1)`
|
backgroundColor: `rgba(${hexToRGB(legendItem.color)}, 0.1)`
|
||||||
}}/>
|
}}/>
|
||||||
<div className="legendLabel">{legendItem.label}</div>
|
<div className="legendLabel">
|
||||||
|
{legendItem.freeFormFields.__name__ || `Query ${legendItem.group} result`}
|
||||||
|
{!!Object.keys(legendItem.freeFormFields).length && <>
|
||||||
|
 {
|
||||||
|
{Object.keys(legendItem.freeFormFields).filter(f => f !== "__name__").map((f) => {
|
||||||
|
const freeField = `${f}="${legendItem.freeFormFields[f]}"`;
|
||||||
|
const fieldId = `${legendItem.group}.${legendItem.label}.${freeField}`;
|
||||||
|
return <Tooltip arrow key={f} open={copiedValue === fieldId} title={"Copied!"}>
|
||||||
|
<span className="legendFreeFields" onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleClickFreeField(freeField, fieldId);
|
||||||
|
}}>
|
||||||
|
{f}: {legendItem.freeFormFields[f]}
|
||||||
|
</span>
|
||||||
|
</Tooltip>;
|
||||||
|
})}
|
||||||
|
}
|
||||||
|
</>}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
grid-gap: 6px;
|
grid-gap: 6px;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
justify-content: start;
|
justify-content: start;
|
||||||
padding: 5px 10px;
|
padding: 7px 50px 7px 10px;
|
||||||
background-color: #FFF;
|
background-color: #FFF;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: 0.2s ease;
|
transition: 0.2s ease;
|
||||||
@ -56,14 +56,27 @@
|
|||||||
border-style: solid;
|
border-style: solid;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
transition: 0.2s ease;
|
transition: 0.2s ease;
|
||||||
margin: 3px 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.legendLabel {
|
.legendLabel {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
|
line-height: 12px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.legendFreeFields {
|
||||||
|
padding: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legendFreeFields:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legendFreeFields:not(:last-child):after {
|
||||||
|
content: ",";
|
||||||
|
}
|
||||||
|
|
||||||
.legendWrapperHotkey {
|
.legendWrapperHotkey {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -10,6 +10,7 @@ export const getSeriesItem = (d: MetricResult, hideSeries: string[]): Series =>
|
|||||||
return {
|
return {
|
||||||
label,
|
label,
|
||||||
dash: getDashLine(d.group),
|
dash: getDashLine(d.group),
|
||||||
|
class: JSON.stringify(d.metric),
|
||||||
width: 1.4,
|
width: 1.4,
|
||||||
stroke: getColorLine(d.group, label),
|
stroke: getColorLine(d.group, label),
|
||||||
show: !includesHideSeries(label, d.group, hideSeries),
|
show: !includesHideSeries(label, d.group, hideSeries),
|
||||||
@ -25,7 +26,8 @@ export const getLegendItem = (s: Series, group: number): LegendItem => ({
|
|||||||
group,
|
group,
|
||||||
label: s.label || "",
|
label: s.label || "",
|
||||||
color: s.stroke as string,
|
color: s.stroke as string,
|
||||||
checked: s.show || false
|
checked: s.show || false,
|
||||||
|
freeFormFields: JSON.parse(s.class || "{}"),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getHideSeries = ({hideSeries, legend, metaKey, series}: HideSeriesArgs): string[] => {
|
export const getHideSeries = ({hideSeries, legend, metaKey, series}: HideSeriesArgs): string[] => {
|
||||||
|
@ -36,4 +36,5 @@ export interface LegendItem {
|
|||||||
label: string;
|
label: string;
|
||||||
color: string;
|
color: string;
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
|
freeFormFields: {[key: string]: string};
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user