mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-02-09 15:27:11 +00:00
vmui: fix step field (#3561)
* feat: use a unit next to the step value * app/vmselect/vmui: `make vmui-update` Co-authored-by: Aliaksandr Valialkin <valyala@victoriametrics.com>
This commit is contained in:
parent
7e49818c6d
commit
6f21435d2d
17 changed files with 181 additions and 93 deletions
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"files": {
|
"files": {
|
||||||
"main.css": "./static/css/main.74a50bcc.css",
|
"main.css": "./static/css/main.9a291a47.css",
|
||||||
"main.js": "./static/js/main.2a5e72d0.js",
|
"main.js": "./static/js/main.e0294822.js",
|
||||||
"static/js/27.c1ccfd29.chunk.js": "./static/js/27.c1ccfd29.chunk.js",
|
"static/js/27.c1ccfd29.chunk.js": "./static/js/27.c1ccfd29.chunk.js",
|
||||||
"index.html": "./index.html"
|
"index.html": "./index.html"
|
||||||
},
|
},
|
||||||
"entrypoints": [
|
"entrypoints": [
|
||||||
"static/css/main.74a50bcc.css",
|
"static/css/main.9a291a47.css",
|
||||||
"static/js/main.2a5e72d0.js"
|
"static/js/main.e0294822.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -1 +1 @@
|
||||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="VM-UI is a metric explorer for Victoria Metrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono&family=Lato:wght@300;400;700&display=swap" rel="stylesheet"><script src="./dashboards/index.js" type="module"></script><script defer="defer" src="./static/js/main.2a5e72d0.js"></script><link href="./static/css/main.74a50bcc.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="VM-UI is a metric explorer for Victoria Metrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono&family=Lato:wght@300;400;700&display=swap" rel="stylesheet"><script src="./dashboards/index.js" type="module"></script><script defer="defer" src="./static/js/main.e0294822.js"></script><link href="./static/css/main.9a291a47.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
app/vmselect/vmui/static/js/main.e0294822.js
Normal file
2
app/vmselect/vmui/static/js/main.e0294822.js
Normal file
File diff suppressed because one or more lines are too long
|
@ -38,7 +38,7 @@ const AdditionalSettings: FC = () => {
|
||||||
queryDispatch({ type: "TOGGLE_AUTOCOMPLETE" });
|
queryDispatch({ type: "TOGGLE_AUTOCOMPLETE" });
|
||||||
};
|
};
|
||||||
|
|
||||||
const onChangeStep = (value: number) => {
|
const onChangeStep = (value: string) => {
|
||||||
graphDispatch({ type: "SET_CUSTOM_STEP", payload: value });
|
graphDispatch({ type: "SET_CUSTOM_STEP", payload: value });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import React, { FC, useCallback, useEffect, useState } from "preact/compat";
|
import React, { FC, useEffect, useState } from "preact/compat";
|
||||||
import debounce from "lodash.debounce";
|
|
||||||
import { RestartIcon } from "../../Main/Icons";
|
import { RestartIcon } from "../../Main/Icons";
|
||||||
import TextField from "../../Main/TextField/TextField";
|
import TextField from "../../Main/TextField/TextField";
|
||||||
import Button from "../../Main/Button/Button";
|
import Button from "../../Main/Button/Button";
|
||||||
import Tooltip from "../../Main/Tooltip/Tooltip";
|
import Tooltip from "../../Main/Tooltip/Tooltip";
|
||||||
|
import { ErrorTypes } from "../../../types";
|
||||||
|
import { supportedDurations } from "../../../utils/time";
|
||||||
|
|
||||||
interface StepConfiguratorProps {
|
interface StepConfiguratorProps {
|
||||||
defaultStep?: number,
|
defaultStep?: string,
|
||||||
value?: number,
|
value?: string,
|
||||||
setStep: (step: number) => void,
|
setStep: (step: string) => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
const StepConfigurator: FC<StepConfiguratorProps> = ({ value, defaultStep, setStep }) => {
|
const StepConfigurator: FC<StepConfiguratorProps> = ({ value, defaultStep, setStep }) => {
|
||||||
|
@ -16,40 +17,46 @@ const StepConfigurator: FC<StepConfiguratorProps> = ({ value, defaultStep, setSt
|
||||||
const [customStep, setCustomStep] = useState(value || defaultStep);
|
const [customStep, setCustomStep] = useState(value || defaultStep);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
const handleApply = (step: number) => setStep(step || 1);
|
const handleApply = (value?: string) => {
|
||||||
const debouncedHandleApply = useCallback(debounce(handleApply, 500), []);
|
const step = value || customStep || defaultStep || "1s";
|
||||||
|
const durations = step.match(/[a-zA-Z]+/g) || [];
|
||||||
const onChangeStep = (val: string) => {
|
setStep(!durations.length ? `${step}s` : step);
|
||||||
const value = +val;
|
|
||||||
if (!value) return;
|
|
||||||
handleSetStep(value);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSetStep = (value: number) => {
|
const handleChangeStep = (value: string) => {
|
||||||
if (value > 0) {
|
const numbers = value.match(/[-+]?([0-9]*\.[0-9]+|[0-9]+)/g) || [];
|
||||||
setCustomStep(value);
|
const durations = value.match(/[a-zA-Z]+/g) || [];
|
||||||
debouncedHandleApply(value);
|
const isValidNumbers = numbers.length && numbers.every(num => parseFloat(num) > 0);
|
||||||
|
const isValidDuration = durations.every(d => supportedDurations.find(dur => dur.short === d));
|
||||||
|
const isValidStep = isValidNumbers && isValidDuration;
|
||||||
|
|
||||||
|
setCustomStep(value);
|
||||||
|
|
||||||
|
if (isValidStep) {
|
||||||
setError("");
|
setError("");
|
||||||
} else {
|
} else {
|
||||||
setError("step is out of allowed range");
|
setError(ErrorTypes.validStep);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
handleSetStep(defaultStep || 1);
|
const value = defaultStep || "1s";
|
||||||
|
handleChangeStep(value);
|
||||||
|
handleApply(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (value) handleSetStep(value);
|
if (value) handleChangeStep(value);
|
||||||
}, [value]);
|
}, [value]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TextField
|
<TextField
|
||||||
label="Step value of seconds"
|
label="Step value"
|
||||||
type="number"
|
|
||||||
value={customStep}
|
value={customStep}
|
||||||
error={error}
|
error={error}
|
||||||
onChange={onChangeStep}
|
onChange={handleChangeStep}
|
||||||
|
onEnter={handleApply}
|
||||||
|
onBlur={handleApply}
|
||||||
endIcon={(
|
endIcon={(
|
||||||
<Tooltip title="Reset step to default">
|
<Tooltip title="Reset step to default">
|
||||||
<Button
|
<Button
|
||||||
|
|
|
@ -16,7 +16,7 @@ import "./style.scss";
|
||||||
export interface GraphViewProps {
|
export interface GraphViewProps {
|
||||||
data?: MetricResult[];
|
data?: MetricResult[];
|
||||||
period: TimeParams;
|
period: TimeParams;
|
||||||
customStep: number;
|
customStep: string;
|
||||||
query: string[];
|
query: string[];
|
||||||
alias?: string[],
|
alias?: string[],
|
||||||
yaxis: YaxisState;
|
yaxis: YaxisState;
|
||||||
|
@ -56,7 +56,7 @@ const GraphView: FC<GraphViewProps> = ({
|
||||||
fullWidth = true
|
fullWidth = true
|
||||||
}) => {
|
}) => {
|
||||||
const { timezone } = useTimeState();
|
const { timezone } = useTimeState();
|
||||||
const currentStep = useMemo(() => customStep || period.step || 1, [period.step, customStep]);
|
const currentStep = useMemo(() => customStep || period.step || "1s", [period.step, customStep]);
|
||||||
|
|
||||||
const [dataChart, setDataChart] = useState<uPlotData>([[]]);
|
const [dataChart, setDataChart] = useState<uPlotData>([[]]);
|
||||||
const [series, setSeries] = useState<uPlotSeries[]>([]);
|
const [series, setSeries] = useState<uPlotSeries[]>([]);
|
||||||
|
|
|
@ -15,7 +15,7 @@ interface FetchQueryParams {
|
||||||
predefinedQuery?: string[]
|
predefinedQuery?: string[]
|
||||||
visible: boolean
|
visible: boolean
|
||||||
display?: DisplayType,
|
display?: DisplayType,
|
||||||
customStep: number,
|
customStep: string,
|
||||||
hideQuery?: number[]
|
hideQuery?: number[]
|
||||||
showAllSeries?: boolean
|
showAllSeries?: boolean
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,19 @@ import ExploreMetricItem from "./ExploreMetricItem/ExploreMetricItem";
|
||||||
import TextField from "../../components/Main/TextField/TextField";
|
import TextField from "../../components/Main/TextField/TextField";
|
||||||
import { CloseIcon, SearchIcon } from "../../components/Main/Icons";
|
import { CloseIcon, SearchIcon } from "../../components/Main/Icons";
|
||||||
import Switch from "../../components/Main/Switch/Switch";
|
import Switch from "../../components/Main/Switch/Switch";
|
||||||
|
import StepConfigurator from "../../components/Configurators/StepConfigurator/StepConfigurator";
|
||||||
|
import { useTimeState } from "../../state/time/TimeStateContext";
|
||||||
|
import { useGraphDispatch, useGraphState } from "../../state/graph/GraphStateContext";
|
||||||
|
import usePrevious from "../../hooks/usePrevious";
|
||||||
|
|
||||||
const ExploreMetrics: FC = () => {
|
const ExploreMetrics: FC = () => {
|
||||||
useSetQueryParams();
|
useSetQueryParams();
|
||||||
|
|
||||||
|
const { period: { step }, duration } = useTimeState();
|
||||||
|
const { customStep } = useGraphState();
|
||||||
|
const graphDispatch = useGraphDispatch();
|
||||||
|
const prevDuration = usePrevious(duration);
|
||||||
|
|
||||||
const [job, setJob] = useState("");
|
const [job, setJob] = useState("");
|
||||||
const [instance, setInstance] = useState("");
|
const [instance, setInstance] = useState("");
|
||||||
const [searchMetric, setSearchMetric] = useState("");
|
const [searchMetric, setSearchMetric] = useState("");
|
||||||
|
@ -64,14 +73,27 @@ const ExploreMetrics: FC = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleChangeStep = (value: string) => {
|
||||||
|
graphDispatch({ type: "SET_CUSTOM_STEP", payload: value });
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setInstance("");
|
setInstance("");
|
||||||
}, [job]);
|
}, [job]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!customStep && step) handleChangeStep(step);
|
||||||
|
}, [step]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (duration === prevDuration || !prevDuration) return;
|
||||||
|
if (customStep) handleChangeStep(step || "1s");
|
||||||
|
}, [duration, prevDuration]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="vm-explore-metrics">
|
<div className="vm-explore-metrics">
|
||||||
<div className="vm-explore-metrics-header vm-block">
|
<div className="vm-explore-metrics-header vm-block">
|
||||||
<div className="vm-explore-metrics-header-top">
|
<div className="vm-explore-metrics-header__job">
|
||||||
<Select
|
<Select
|
||||||
value={job}
|
value={job}
|
||||||
list={jobs}
|
list={jobs}
|
||||||
|
@ -80,6 +102,8 @@ const ExploreMetrics: FC = () => {
|
||||||
onChange={setJob}
|
onChange={setJob}
|
||||||
searchable
|
searchable
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="vm-explore-metrics-header__instance">
|
||||||
<Select
|
<Select
|
||||||
value={instance}
|
value={instance}
|
||||||
list={instances}
|
list={instances}
|
||||||
|
@ -90,29 +114,38 @@ const ExploreMetrics: FC = () => {
|
||||||
clearable
|
clearable
|
||||||
searchable
|
searchable
|
||||||
/>
|
/>
|
||||||
<div className="vm-explore-metrics-header-top__switch-graphs">
|
|
||||||
<Switch
|
|
||||||
label={"Show only opened metrics"}
|
|
||||||
value={onlyGraphs}
|
|
||||||
onChange={setOnlyGraphs}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<TextField
|
<div className="vm-explore-metrics-header__step">
|
||||||
autofocus
|
<StepConfigurator
|
||||||
label="Metric search"
|
defaultStep={step}
|
||||||
value={searchMetric}
|
setStep={handleChangeStep}
|
||||||
onChange={setSearchMetric}
|
value={customStep}
|
||||||
startIcon={<SearchIcon/>}
|
/>
|
||||||
endIcon={(
|
</div>
|
||||||
<div
|
<div className="vm-explore-metrics-header__switch-graphs">
|
||||||
className="vm-explore-metrics-header__clear-icon"
|
<Switch
|
||||||
onClick={handleClearSearch}
|
label={"Show only opened metrics"}
|
||||||
>
|
value={onlyGraphs}
|
||||||
<CloseIcon/>
|
onChange={setOnlyGraphs}
|
||||||
</div>
|
/>
|
||||||
)}
|
</div>
|
||||||
/>
|
<div className="vm-explore-metrics-header__search">
|
||||||
|
<TextField
|
||||||
|
autofocus
|
||||||
|
label="Metric search"
|
||||||
|
value={searchMetric}
|
||||||
|
onChange={setSearchMetric}
|
||||||
|
startIcon={<SearchIcon/>}
|
||||||
|
endIcon={(
|
||||||
|
<div
|
||||||
|
className="vm-explore-metrics-header__clear-icon"
|
||||||
|
onClick={handleClearSearch}
|
||||||
|
>
|
||||||
|
<CloseIcon/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isLoading && <Spinner />}
|
{isLoading && <Spinner />}
|
||||||
|
|
|
@ -6,22 +6,49 @@
|
||||||
gap: $padding-medium;
|
gap: $padding-medium;
|
||||||
|
|
||||||
&-header {
|
&-header {
|
||||||
display: grid;
|
display: flex;
|
||||||
gap: $padding-small;
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: $padding-small $padding-medium;
|
||||||
|
|
||||||
&-top {
|
&__job {
|
||||||
display: grid;
|
min-width: 200px;
|
||||||
grid-template-columns: minmax(200px, 300px) minmax(200px, 500px) auto;
|
max-width: 300px;
|
||||||
align-items: center;
|
width: 100%;
|
||||||
gap: $padding-medium;
|
|
||||||
|
|
||||||
&__switch-graphs {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__instance {
|
||||||
|
min-width: 200px;
|
||||||
|
max-width: 500px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__step {
|
||||||
|
}
|
||||||
|
|
||||||
|
&__switch-graphs {
|
||||||
|
}
|
||||||
|
|
||||||
|
&__search {
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
//&-top {
|
||||||
|
// display: grid;
|
||||||
|
// grid-template-columns: minmax(200px, 300px) minmax(200px, 500px) auto;
|
||||||
|
// align-items: center;
|
||||||
|
// gap: $padding-medium;
|
||||||
|
//
|
||||||
|
// &__switch-graphs {
|
||||||
|
// display: flex;
|
||||||
|
// align-items: center;
|
||||||
|
// justify-content: flex-end;
|
||||||
|
// gap: $padding-medium;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
&__clear-icon {
|
&__clear-icon {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { InfoIcon } from "../../../components/Main/Icons";
|
||||||
import "./style.scss";
|
import "./style.scss";
|
||||||
import Alert from "../../../components/Main/Alert/Alert";
|
import Alert from "../../../components/Main/Alert/Alert";
|
||||||
import Tooltip from "../../../components/Main/Tooltip/Tooltip";
|
import Tooltip from "../../../components/Main/Tooltip/Tooltip";
|
||||||
|
import usePrevious from "../../../hooks/usePrevious";
|
||||||
|
|
||||||
export interface PredefinedPanelsProps extends PanelSettings {
|
export interface PredefinedPanelsProps extends PanelSettings {
|
||||||
filename: string;
|
filename: string;
|
||||||
|
@ -27,12 +28,13 @@ const PredefinedPanel: FC<PredefinedPanelsProps> = ({
|
||||||
alias
|
alias
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const { period } = useTimeState();
|
const { period, duration } = useTimeState();
|
||||||
const dispatch = useTimeDispatch();
|
const dispatch = useTimeDispatch();
|
||||||
|
const prevDuration = usePrevious(duration);
|
||||||
|
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const [visible, setVisible] = useState(true);
|
const [visible, setVisible] = useState(true);
|
||||||
const [customStep, setCustomStep] = useState<number>(period.step || 1);
|
const [customStep, setCustomStep] = useState(period.step || "1s");
|
||||||
const [yaxis, setYaxis] = useState<YaxisState>({
|
const [yaxis, setYaxis] = useState<YaxisState>({
|
||||||
limits: {
|
limits: {
|
||||||
enable: false,
|
enable: false,
|
||||||
|
@ -75,6 +77,11 @@ const PredefinedPanel: FC<PredefinedPanelsProps> = ({
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (duration === prevDuration || !prevDuration) return;
|
||||||
|
if (customStep) setCustomStep(period.step || "1s");
|
||||||
|
}, [duration, prevDuration]);
|
||||||
|
|
||||||
if (!validExpr) return (
|
if (!validExpr) return (
|
||||||
<Alert variant="error">
|
<Alert variant="error">
|
||||||
<code>"expr"</code> not found. Check the configuration file <b>{filename}</b>.
|
<code>"expr"</code> not found. Check the configuration file <b>{filename}</b>.
|
||||||
|
@ -119,6 +126,7 @@ const PredefinedPanel: FC<PredefinedPanelsProps> = ({
|
||||||
<div className="vm-predefined-panel-header__step">
|
<div className="vm-predefined-panel-header__step">
|
||||||
<StepConfigurator
|
<StepConfigurator
|
||||||
defaultStep={period.step}
|
defaultStep={period.step}
|
||||||
|
value={customStep}
|
||||||
setStep={setCustomStep}
|
setStep={setCustomStep}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,17 +12,17 @@ export interface YaxisState {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GraphState {
|
export interface GraphState {
|
||||||
customStep: number
|
customStep: string
|
||||||
yaxis: YaxisState
|
yaxis: YaxisState
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GraphAction =
|
export type GraphAction =
|
||||||
| { type: "TOGGLE_ENABLE_YAXIS_LIMITS" }
|
| { type: "TOGGLE_ENABLE_YAXIS_LIMITS" }
|
||||||
| { type: "SET_YAXIS_LIMITS", payload: AxisRange }
|
| { type: "SET_YAXIS_LIMITS", payload: AxisRange }
|
||||||
| { type: "SET_CUSTOM_STEP", payload: number}
|
| { type: "SET_CUSTOM_STEP", payload: string}
|
||||||
|
|
||||||
export const initialGraphState: GraphState = {
|
export const initialGraphState: GraphState = {
|
||||||
customStep: parseFloat(getQueryStringValue("g0.step_input", "0") as string),
|
customStep: getQueryStringValue("g0.step_input", "") as string,
|
||||||
yaxis: {
|
yaxis: {
|
||||||
limits: { enable: false, range: { "1": [0, 0] } }
|
limits: { enable: false, range: { "1": [0, 0] } }
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ export type DisplayType = "table" | "chart" | "code";
|
||||||
export interface TimeParams {
|
export interface TimeParams {
|
||||||
start: number; // timestamp in seconds
|
start: number; // timestamp in seconds
|
||||||
end: number; // timestamp in seconds
|
end: number; // timestamp in seconds
|
||||||
step?: number; // seconds
|
step?: string; // seconds
|
||||||
date: string; // end input date
|
date: string; // end input date
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,8 @@ export enum ErrorTypes {
|
||||||
validQuery = "Please enter a valid Query and execute it",
|
validQuery = "Please enter a valid Query and execute it",
|
||||||
traceNotFound = "Not found the tracing information",
|
traceNotFound = "Not found the tracing information",
|
||||||
emptyTitle = "Please enter title",
|
emptyTitle = "Please enter title",
|
||||||
positiveNumber = "Please enter positive number"
|
positiveNumber = "Please enter positive number",
|
||||||
|
validStep = "Please enter a valid step"
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PanelSettings {
|
export interface PanelSettings {
|
||||||
|
|
|
@ -11,11 +11,12 @@ export const limitsDurations = { min: 1, max: 1.578e+11 }; // min: 1 ms, max: 5
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export const supportedTimezones = Intl.supportedValuesOf("timeZone") as string[];
|
export const supportedTimezones = Intl.supportedValuesOf("timeZone") as string[];
|
||||||
|
|
||||||
|
// The list of supported units could be the following -
|
||||||
|
// https://prometheus.io/docs/prometheus/latest/querying/basics/#time-durations
|
||||||
export const supportedDurations = [
|
export const supportedDurations = [
|
||||||
{ long: "days", short: "d", possible: "day" },
|
|
||||||
{ long: "weeks", short: "w", possible: "week" },
|
|
||||||
{ long: "months", short: "M", possible: "mon" },
|
|
||||||
{ long: "years", short: "y", possible: "year" },
|
{ long: "years", short: "y", possible: "year" },
|
||||||
|
{ long: "weeks", short: "w", possible: "week" },
|
||||||
|
{ long: "days", short: "d", possible: "day" },
|
||||||
{ long: "hours", short: "h", possible: "hour" },
|
{ long: "hours", short: "h", possible: "hour" },
|
||||||
{ long: "minutes", short: "m", possible: "min" },
|
{ long: "minutes", short: "m", possible: "min" },
|
||||||
{ long: "seconds", short: "s", possible: "sec" },
|
{ long: "seconds", short: "s", possible: "sec" },
|
||||||
|
@ -27,20 +28,24 @@ const shortDurations = supportedDurations.map(d => d.short);
|
||||||
export const roundToMilliseconds = (num: number): number => Math.round(num*1000)/1000;
|
export const roundToMilliseconds = (num: number): number => Math.round(num*1000)/1000;
|
||||||
|
|
||||||
const roundStep = (step: number) => {
|
const roundStep = (step: number) => {
|
||||||
|
let result = roundToMilliseconds(step);
|
||||||
const integerStep = Math.round(step);
|
const integerStep = Math.round(step);
|
||||||
|
|
||||||
if (step >= 100) {
|
if (step >= 100) {
|
||||||
return integerStep - (integerStep%10); // integer multiple of 10
|
result = integerStep - (integerStep%10); // integer multiple of 10
|
||||||
}
|
}
|
||||||
if (step < 100 && step >= 10) {
|
if (step < 100 && step >= 10) {
|
||||||
return integerStep - (integerStep%5); // integer multiple of 5
|
result = integerStep - (integerStep%5); // integer multiple of 5
|
||||||
}
|
}
|
||||||
if (step < 10 && step >= 1) {
|
if (step < 10 && step >= 1) {
|
||||||
return integerStep; // integer
|
result = integerStep; // integer
|
||||||
}
|
}
|
||||||
if (step < 1 && step > 0.01) {
|
if (step < 1 && step > 0.01) {
|
||||||
return Math.round(step * 40) / 40; // float to thousandths multiple of 5
|
result = Math.round(step * 40) / 40; // float to thousandths multiple of 5
|
||||||
}
|
}
|
||||||
return roundToMilliseconds(step);
|
|
||||||
|
const humanize = getDurationFromMilliseconds(dayjs.duration(result || 0.001, "seconds").asMilliseconds());
|
||||||
|
return humanize.replace(/\s/g, "");
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isSupportedDuration = (str: string): Partial<Record<UnitTypeShort, string>> | undefined => {
|
export const isSupportedDuration = (str: string): Partial<Record<UnitTypeShort, string>> | undefined => {
|
||||||
|
@ -53,10 +58,10 @@ export const isSupportedDuration = (str: string): Partial<Record<UnitTypeShort,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getTimeperiodForDuration = (dur: string, date?: Date): TimeParams => {
|
export const getSecondsFromDuration = (dur: string) => {
|
||||||
const n = (date || dayjs().toDate()).valueOf() / 1000;
|
const shortSupportedDur = supportedDurations.map(d => d.short).join("|");
|
||||||
|
const regexp = new RegExp(`\\d+[${shortSupportedDur}]+`, "g");
|
||||||
const durItems = dur.trim().split(" ");
|
const durItems = dur.match(regexp) || [];
|
||||||
|
|
||||||
const durObject = durItems.reduce((prev, curr) => {
|
const durObject = durItems.reduce((prev, curr) => {
|
||||||
|
|
||||||
|
@ -73,9 +78,15 @@ export const getTimeperiodForDuration = (dur: string, date?: Date): TimeParams =
|
||||||
}
|
}
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
const delta = dayjs.duration(durObject).asSeconds();
|
return dayjs.duration(durObject).asSeconds();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getTimeperiodForDuration = (dur: string, date?: Date): TimeParams => {
|
||||||
|
const n = (date || dayjs().toDate()).valueOf() / 1000;
|
||||||
|
|
||||||
|
const delta = getSecondsFromDuration(dur);
|
||||||
const rawStep = delta / MAX_ITEMS_PER_CHART;
|
const rawStep = delta / MAX_ITEMS_PER_CHART;
|
||||||
const step = roundStep(rawStep) || 0.001;
|
const step = roundStep(rawStep);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
start: n - delta,
|
start: n - delta,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import uPlot, { Axis, Series } from "uplot";
|
import uPlot, { Axis, Series } from "uplot";
|
||||||
import { getMaxFromArray, getMinFromArray } from "../math";
|
import { getMaxFromArray, getMinFromArray } from "../math";
|
||||||
import { roundToMilliseconds } from "../time";
|
import { getSecondsFromDuration, roundToMilliseconds } from "../time";
|
||||||
import { AxisRange } from "../../state/graph/reducer";
|
import { AxisRange } from "../../state/graph/reducer";
|
||||||
import { formatTicks, sizeAxis } from "./helpers";
|
import { formatTicks, sizeAxis } from "./helpers";
|
||||||
import { TimeParams } from "../../types";
|
import { TimeParams } from "../../types";
|
||||||
|
@ -30,7 +30,8 @@ export const getAxes = (series: Series[], unit?: string): Axis[] => Array.from(n
|
||||||
return axis;
|
return axis;
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getTimeSeries = (times: number[], step: number, period: TimeParams): number[] => {
|
export const getTimeSeries = (times: number[], stepDuration: string, period: TimeParams): number[] => {
|
||||||
|
const step = getSecondsFromDuration(stepDuration) || 1;
|
||||||
const allTimes = Array.from(new Set(times)).sort((a, b) => a - b);
|
const allTimes = Array.from(new Set(times)).sort((a, b) => a - b);
|
||||||
let t = period.start;
|
let t = period.start;
|
||||||
const tEnd = roundToMilliseconds(period.end + step);
|
const tEnd = roundToMilliseconds(period.end + step);
|
||||||
|
|
Loading…
Reference in a new issue