mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-23 20:37:12 +01:00
Co-authored-by: Aliaksandr Valialkin <valyala@victoriametrics.com>
This commit is contained in:
parent
c0246b2e17
commit
d19072a2d9
@ -1,6 +1,6 @@
|
||||
@use "src/styles/variables" as *;
|
||||
|
||||
$padding-modal: 22px;
|
||||
$padding-modal: $padding-medium;
|
||||
|
||||
.vm-modal {
|
||||
position: fixed;
|
||||
@ -43,9 +43,6 @@ $padding-modal: 22px;
|
||||
}
|
||||
|
||||
&-content {
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr;
|
||||
align-items: flex-start;
|
||||
background: $color-background-block;
|
||||
box-shadow: 0 0 24px rgba($color-black, 0.07);
|
||||
border-radius: $border-radius-small;
|
||||
|
@ -22,6 +22,7 @@ import { arrayEquals } from "../../../utils/array";
|
||||
import useDeviceDetect from "../../../hooks/useDeviceDetect";
|
||||
import { QueryStats } from "../../../api/types";
|
||||
import { usePrettifyQuery } from "./hooks/usePrettifyQuery";
|
||||
import QueryHistoryList from "../QueryHistory/QueryHistoryList";
|
||||
|
||||
export interface QueryConfiguratorProps {
|
||||
queryErrors: string[];
|
||||
@ -51,18 +52,25 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
|
||||
|
||||
const [stateQuery, setStateQuery] = useState(query || []);
|
||||
const [hideQuery, setHideQuery] = useState<number[]>([]);
|
||||
const [awaitStateQuery, setAwaitStateQuery] = useState(false);
|
||||
const prevStateQuery = usePrevious(stateQuery) as (undefined | string[]);
|
||||
|
||||
const getPrettifiedQuery = usePrettifyQuery();
|
||||
|
||||
const updateHistory = () => {
|
||||
queryDispatch({
|
||||
type: "SET_QUERY_HISTORY", payload: stateQuery.map((q, i) => {
|
||||
type: "SET_QUERY_HISTORY",
|
||||
payload: stateQuery.map((q, i) => {
|
||||
const h = queryHistory[i] || { values: [] };
|
||||
const queryEqual = q === h.values[h.values.length - 1];
|
||||
const newValues = !queryEqual && q ? [...h.values, q] : h.values;
|
||||
|
||||
// limit the history
|
||||
if (newValues.length > 25) newValues.shift();
|
||||
|
||||
return {
|
||||
index: h.values.length - Number(queryEqual),
|
||||
values: !queryEqual && q ? [...h.values, q] : h.values
|
||||
values: newValues
|
||||
};
|
||||
})
|
||||
});
|
||||
@ -99,6 +107,11 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
|
||||
setStateQuery(prev => prev.map((q, i) => i === index ? value : q));
|
||||
};
|
||||
|
||||
const handleSelectHistory = (value: string, index: number) => {
|
||||
handleChangeQuery(value, index);
|
||||
setAwaitStateQuery(true);
|
||||
};
|
||||
|
||||
const handleHistoryChange = (step: number, indexQuery: number) => {
|
||||
const { index, values } = queryHistory[indexQuery];
|
||||
const newIndexHistory = index + step;
|
||||
@ -149,6 +162,13 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
|
||||
onHideQuery(hideQuery);
|
||||
}, [hideQuery]);
|
||||
|
||||
useEffect(() => {
|
||||
if (awaitStateQuery) {
|
||||
handleRunQuery();
|
||||
setAwaitStateQuery(false);
|
||||
}
|
||||
}, [stateQuery, awaitStateQuery]);
|
||||
|
||||
return <div
|
||||
className={classNames({
|
||||
"vm-query-configurator": true,
|
||||
@ -223,6 +243,10 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({
|
||||
<div className="vm-query-configurator-settings">
|
||||
<AdditionalSettings/>
|
||||
<div className="vm-query-configurator-settings__buttons">
|
||||
<QueryHistoryList
|
||||
history={queryHistory}
|
||||
handleSelectQuery={handleSelectHistory}
|
||||
/>
|
||||
{stateQuery.length < MAX_QUERY_FIELDS && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
|
@ -40,7 +40,7 @@
|
||||
&__buttons {
|
||||
flex-grow: 1;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, auto);
|
||||
grid-template-columns: repeat(3, auto);
|
||||
gap: $padding-small;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
@ -0,0 +1,114 @@
|
||||
import React, { FC, useMemo } from "preact/compat";
|
||||
import Button from "../../../components/Main/Button/Button";
|
||||
import { ClockIcon, CopyIcon, PlayCircleOutlineIcon } from "../../../components/Main/Icons";
|
||||
import Tooltip from "../../../components/Main/Tooltip/Tooltip";
|
||||
import { QueryHistory } from "../../../state/query/reducer";
|
||||
import useBoolean from "../../../hooks/useBoolean";
|
||||
import Modal from "../../../components/Main/Modal/Modal";
|
||||
import "./style.scss";
|
||||
import Tabs from "../../../components/Main/Tabs/Tabs";
|
||||
import { useState } from "react";
|
||||
import useCopyToClipboard from "../../../hooks/useCopyToClipboard";
|
||||
import useDeviceDetect from "../../../hooks/useDeviceDetect";
|
||||
import classNames from "classnames";
|
||||
|
||||
interface QueryHistoryProps {
|
||||
history: QueryHistory[];
|
||||
handleSelectQuery: (query: string, index: number) => void
|
||||
}
|
||||
|
||||
const QueryHistoryList: FC<QueryHistoryProps> = ({ history, handleSelectQuery }) => {
|
||||
const { isMobile } = useDeviceDetect();
|
||||
const copyToClipboard = useCopyToClipboard();
|
||||
const {
|
||||
value: openModal,
|
||||
setTrue: handleOpenModal,
|
||||
setFalse: handleCloseModal,
|
||||
} = useBoolean(false);
|
||||
|
||||
const [activeTab, setActiveTab] = useState("0");
|
||||
const tabs = useMemo(() => history.map((item, i) => ({
|
||||
value: `${i}`,
|
||||
label: `Query ${i+1}`,
|
||||
})), [history]);
|
||||
|
||||
const queries = useMemo(() => {
|
||||
const historyItem = history[+activeTab];
|
||||
return historyItem ? historyItem.values.filter(q => q).reverse() : [];
|
||||
}, [activeTab, history]);
|
||||
|
||||
const handleCopyQuery = (value: string) => async () => {
|
||||
await copyToClipboard(value, "Query has been copied");
|
||||
};
|
||||
|
||||
const handleRunQuery = (value: string, index: number) => () => {
|
||||
handleSelectQuery(value, index);
|
||||
handleCloseModal();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tooltip title={"Show history"}>
|
||||
<Button
|
||||
color="primary"
|
||||
variant="text"
|
||||
onClick={handleOpenModal}
|
||||
startIcon={<ClockIcon/>}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
{openModal && (
|
||||
<Modal
|
||||
title={"Query history"}
|
||||
onClose={handleCloseModal}
|
||||
>
|
||||
<div className="vm-query-history">
|
||||
<div
|
||||
className={classNames({
|
||||
"vm-query-history__tabs": true,
|
||||
"vm-section-header__tabs": true,
|
||||
"vm-query-history__tabs_mobile": isMobile,
|
||||
})}
|
||||
>
|
||||
<Tabs
|
||||
activeItem={activeTab}
|
||||
items={tabs}
|
||||
onChange={setActiveTab}
|
||||
/>
|
||||
</div>
|
||||
<div className="vm-query-history-list">
|
||||
{queries.map((query, index) => (
|
||||
<div
|
||||
className="vm-query-history-list-item"
|
||||
key={index}
|
||||
>
|
||||
<span className="vm-query-history-list-item__value">{query}</span>
|
||||
<div className="vm-query-history-list-item__buttons">
|
||||
<Tooltip title={"Execute query"}>
|
||||
<Button
|
||||
size="small"
|
||||
variant="text"
|
||||
onClick={handleRunQuery(query, +activeTab)}
|
||||
startIcon={<PlayCircleOutlineIcon/>}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title={"Copy query"}>
|
||||
<Button
|
||||
size="small"
|
||||
variant="text"
|
||||
onClick={handleCopyQuery(query)}
|
||||
startIcon={<CopyIcon/>}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default QueryHistoryList;
|
@ -0,0 +1,45 @@
|
||||
@use "src/styles/variables" as *;
|
||||
|
||||
.vm-query-history {
|
||||
max-width: 80vw;
|
||||
min-width: 40vw;
|
||||
|
||||
&__tabs {
|
||||
margin: (-$padding-medium) (-$padding-medium) 0;
|
||||
padding: 0 $padding-medium;
|
||||
|
||||
&_mobile {
|
||||
margin: (-$padding-global) (-$padding-medium) 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-list {
|
||||
display: grid;
|
||||
align-items: flex-start;
|
||||
|
||||
&-item {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
gap: $padding-small;
|
||||
align-items: center;
|
||||
margin: 0 (-$padding-medium) 0;
|
||||
padding: $padding-small calc($padding-medium + $padding-small);
|
||||
border-bottom: $border-divider;
|
||||
|
||||
&:first-child {
|
||||
border-top: $border-divider;
|
||||
}
|
||||
|
||||
&__value {
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
font-family: $font-family-monospace;
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
display: flex;
|
||||
gap: $padding-small;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ The following `tip` changes can be tested by building VictoriaMetrics components
|
||||
|
||||
* FEATURE: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): add support for numbers with underscore delimiters such as `1_234_567_890` and `1.234_567_890`. These numbers are easier to read than `1234567890` and `1.234567890`.
|
||||
* FEATURE: [vmbackup](https://docs.victoriametrics.com/vmbackup.html): add support for server-side copy of existing backups. See [these docs](https://docs.victoriametrics.com/vmbackup.html#server-side-copy-of-the-existing-backup) for details.
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add the option to see the latest 25 queries. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4718).
|
||||
* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): add ability to set `member num` label for all the metrics scraped by a particular `vmagent` instance in [a cluster of vmagents](https://docs.victoriametrics.com/vmagent.html#scraping-big-number-of-targets) via `-promscrape.cluster.memberLabel` command-line flag. See [these docs](https://docs.victoriametrics.com/vmagent.html#scraping-big-number-of-targets) and [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4247).
|
||||
* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): do not log `unexpected EOF` when reading incoming metrics, since this error is expected and is handled during metrics' parsing. This reduces the amounts of noisy logs. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4817).
|
||||
* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): retry failed write request on the closed connection immediately, without waiting for backoff. This should improve data delivery speed and reduce amount of error logs emitted by vmagent when using idle connections. See related [issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4139).
|
||||
|
Loading…
Reference in New Issue
Block a user