mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-23 12:31:07 +01:00
vmui: add ability hide query (#3359)
* feat: add ability hide query * fix: change logic hide query * fix: remove console.log
This commit is contained in:
parent
3ed238b75b
commit
51bfd1ab80
@ -18,7 +18,7 @@ export interface QueryEditorProps {
|
||||
error?: ErrorTypes | string;
|
||||
options: string[];
|
||||
label: string;
|
||||
size?: "small" | "medium" | undefined;
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
const QueryEditor: FC<QueryEditorProps> = ({
|
||||
@ -31,6 +31,7 @@ const QueryEditor: FC<QueryEditorProps> = ({
|
||||
error,
|
||||
options,
|
||||
label,
|
||||
disabled = false
|
||||
}) => {
|
||||
|
||||
const [focusOption, setFocusOption] = useState(-1);
|
||||
@ -86,6 +87,7 @@ const QueryEditor: FC<QueryEditorProps> = ({
|
||||
|
||||
// Enter
|
||||
if (enter && hasAutocomplete && !shiftKey && !ctrlMetaKey) {
|
||||
if (disabled) return;
|
||||
onChange(foundOptions[focusOption]);
|
||||
setOpenAutocomplete(false);
|
||||
} else if (enter && !shiftKey) {
|
||||
@ -98,6 +100,7 @@ const QueryEditor: FC<QueryEditorProps> = ({
|
||||
};
|
||||
|
||||
const createHandlerOnChangeAutocomplete = (item: string) => () => {
|
||||
if (disabled) return;
|
||||
onChange(item);
|
||||
handleCloseAutocomplete();
|
||||
};
|
||||
@ -127,6 +130,7 @@ const QueryEditor: FC<QueryEditorProps> = ({
|
||||
error={error}
|
||||
onKeyDown={handleKeyDown}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<Popper
|
||||
open={openAutocomplete}
|
||||
|
@ -5,7 +5,7 @@ import "./style.scss";
|
||||
|
||||
interface ButtonProps {
|
||||
variant?: "contained" | "outlined" | "text"
|
||||
color?: "primary" | "secondary" | "success" | "error"
|
||||
color?: "primary" | "secondary" | "success" | "error" | "gray"
|
||||
size?: "small" | "medium" | "large"
|
||||
endIcon?: ReactNode
|
||||
startIcon?: ReactNode
|
||||
|
@ -135,6 +135,14 @@ $button-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
&_contained_gray {
|
||||
color: $color-text-secondary;
|
||||
|
||||
&:before {
|
||||
background-color: $color-text-secondary;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* variant TEXT */
|
||||
&_text_primary {
|
||||
@ -153,6 +161,10 @@ $button-radius: 6px;
|
||||
color: $color-error;
|
||||
}
|
||||
|
||||
&_text_gray {
|
||||
color: $color-text-secondary;
|
||||
}
|
||||
|
||||
|
||||
/* variant OUTLINED */
|
||||
&_outlined_primary {
|
||||
@ -174,4 +186,9 @@ $button-radius: 6px;
|
||||
border: 1px solid $color-success;
|
||||
color: $color-success;
|
||||
}
|
||||
|
||||
&_outlined_gray {
|
||||
border: 1px solid $color-text-secondary;
|
||||
color: $color-text-secondary;
|
||||
}
|
||||
}
|
||||
|
@ -267,3 +267,26 @@ export const DoneIcon = () => (
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const VisibilityIcon = () => (
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
|
||||
|
||||
export const VisibilityOffIcon = () => (
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78 3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
|
@ -17,9 +17,10 @@ interface FetchQueryParams {
|
||||
visible: boolean
|
||||
display?: DisplayType,
|
||||
customStep: number,
|
||||
hideQuery?: number[]
|
||||
}
|
||||
|
||||
export const useFetchQuery = ({ predefinedQuery, visible, display, customStep }: FetchQueryParams): {
|
||||
export const useFetchQuery = ({ predefinedQuery, visible, display, customStep, hideQuery = [] }: FetchQueryParams): {
|
||||
fetchUrl?: string[],
|
||||
isLoading: boolean,
|
||||
graphData?: MetricResult[],
|
||||
@ -111,14 +112,14 @@ export const useFetchQuery = ({ predefinedQuery, visible, display, customStep }:
|
||||
} else if (isValidHttpUrl(serverUrl)) {
|
||||
const updatedPeriod = { ...period };
|
||||
updatedPeriod.step = customStep;
|
||||
return expr.filter(q => q.trim()).map(q => displayChart
|
||||
return expr.filter((q, i) => q.trim() && !hideQuery.includes(i)).map(q => displayChart
|
||||
? getQueryRangeUrl(serverUrl, q, updatedPeriod, nocache, isTracingEnabled)
|
||||
: getQueryUrl(serverUrl, q, updatedPeriod, isTracingEnabled));
|
||||
} else {
|
||||
setError(ErrorTypes.validServer);
|
||||
}
|
||||
},
|
||||
[serverUrl, period, displayType, customStep]);
|
||||
[serverUrl, period, displayType, customStep, hideQuery]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!visible || !fetchUrl?.length) return;
|
||||
|
@ -6,24 +6,28 @@ import usePrevious from "../../../hooks/usePrevious";
|
||||
import { MAX_QUERY_FIELDS } from "../../../constants/graph";
|
||||
import { useQueryDispatch, useQueryState } from "../../../state/query/QueryStateContext";
|
||||
import { useTimeDispatch } from "../../../state/time/TimeStateContext";
|
||||
import { DeleteIcon, PlayIcon, PlusIcon } from "../../../components/Main/Icons";
|
||||
import { DeleteIcon, PlayIcon, PlusIcon, VisibilityIcon, VisibilityOffIcon } from "../../../components/Main/Icons";
|
||||
import Button from "../../../components/Main/Button/Button";
|
||||
import "./style.scss";
|
||||
import Tooltip from "../../../components/Main/Tooltip/Tooltip";
|
||||
import classNames from "classnames";
|
||||
|
||||
export interface QueryConfiguratorProps {
|
||||
error?: ErrorTypes | string;
|
||||
queryOptions: string[]
|
||||
onHideQuery: (queries: number[]) => void
|
||||
}
|
||||
|
||||
const QueryConfigurator: FC<QueryConfiguratorProps> = ({ error, queryOptions }) => {
|
||||
const QueryConfigurator: FC<QueryConfiguratorProps> = ({ error, queryOptions, onHideQuery }) => {
|
||||
|
||||
const { query, queryHistory, autocomplete } = useQueryState();
|
||||
const queryDispatch = useQueryDispatch();
|
||||
const timeDispatch = useTimeDispatch();
|
||||
|
||||
const [stateQuery, setStateQuery] = useState(query || []);
|
||||
const [hideQuery, setHideQuery] = useState<number[]>([]);
|
||||
const prevStateQuery = usePrevious(stateQuery) as (undefined | string[]);
|
||||
|
||||
const updateHistory = () => {
|
||||
queryDispatch({
|
||||
type: "SET_QUERY_HISTORY", payload: stateQuery.map((q, i) => {
|
||||
@ -51,6 +55,10 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({ error, queryOptions })
|
||||
setStateQuery(prev => prev.filter((q, i) => i !== index));
|
||||
};
|
||||
|
||||
const onToggleHideQuery = (index: number) => {
|
||||
setHideQuery(prev => prev.includes(index) ? prev.filter(n => n !== index) : [...prev, index]);
|
||||
};
|
||||
|
||||
const handleChangeQuery = (value: string, index: number) => {
|
||||
setStateQuery(prev => prev.map((q, i) => i === index ? value : q));
|
||||
};
|
||||
@ -76,6 +84,11 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({ error, queryOptions })
|
||||
|
||||
const createHandlerRemoveQuery = (i: number) => () => {
|
||||
onRemoveQuery(i);
|
||||
setHideQuery(prev => prev.map(n => n > i ? n - 1: n));
|
||||
};
|
||||
|
||||
const createHandlerHideQuery = (i: number) => () => {
|
||||
onToggleHideQuery(i);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -84,11 +97,18 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({ error, queryOptions })
|
||||
}
|
||||
}, [stateQuery]);
|
||||
|
||||
useEffect(() => {
|
||||
onHideQuery(hideQuery);
|
||||
}, [hideQuery]);
|
||||
|
||||
return <div className="vm-query-configurator vm-block">
|
||||
<div className="vm-query-configurator-list">
|
||||
{stateQuery.map((q, i) => (
|
||||
<div
|
||||
className="vm-query-configurator-list-row"
|
||||
className={classNames({
|
||||
"vm-query-configurator-list-row": true,
|
||||
"vm-query-configurator-list-row_disabled": hideQuery.includes(i)
|
||||
})}
|
||||
key={i}
|
||||
>
|
||||
<QueryEditor
|
||||
@ -101,8 +121,18 @@ const QueryConfigurator: FC<QueryConfiguratorProps> = ({ error, queryOptions })
|
||||
onEnter={onRunQuery}
|
||||
onChange={createHandlerChangeQuery(i)}
|
||||
label={`Query ${i + 1}`}
|
||||
size={"small"}
|
||||
disabled={hideQuery.includes(i)}
|
||||
/>
|
||||
<Tooltip title={hideQuery.includes(i) ? "Enable query" : "Disable query"}>
|
||||
<div className="vm-query-configurator-list-row__button">
|
||||
<Button
|
||||
variant={"text"}
|
||||
color={"gray"}
|
||||
startIcon={hideQuery.includes(i) ? <VisibilityOffIcon/> : <VisibilityIcon/>}
|
||||
onClick={createHandlerHideQuery(i)}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
{stateQuery.length > 1 && (
|
||||
<Tooltip title="Remove Query">
|
||||
<div className="vm-query-configurator-list-row__button">
|
||||
|
@ -9,10 +9,15 @@
|
||||
|
||||
&-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
grid-template-columns: 1fr auto auto;
|
||||
align-items: center;
|
||||
gap: $padding-small;
|
||||
|
||||
&_disabled {
|
||||
filter: grayscale(100%);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&__button {
|
||||
display: grid;
|
||||
width: 36px;
|
||||
|
@ -29,10 +29,18 @@ const CustomPanel: FC = () => {
|
||||
|
||||
const [displayColumns, setDisplayColumns] = useState<string[]>();
|
||||
const [tracesState, setTracesState] = useState<Trace[]>([]);
|
||||
const [hideQuery, setHideQuery] = useState<number[]>([]);
|
||||
|
||||
const { customStep, yaxis } = useGraphState();
|
||||
const graphDispatch = useGraphDispatch();
|
||||
|
||||
const { queryOptions } = useFetchQueryOptions();
|
||||
const { isLoading, liveData, graphData, error, warning, traces } = useFetchQuery({
|
||||
visible: true,
|
||||
customStep,
|
||||
hideQuery
|
||||
});
|
||||
|
||||
const setYaxisLimits = (limits: AxisRange) => {
|
||||
graphDispatch({ type: "SET_YAXIS_LIMITS", payload: limits });
|
||||
};
|
||||
@ -45,17 +53,15 @@ const CustomPanel: FC = () => {
|
||||
timeDispatch({ type: "SET_PERIOD", payload: { from, to } });
|
||||
};
|
||||
|
||||
const { queryOptions } = useFetchQueryOptions();
|
||||
const { isLoading, liveData, graphData, error, warning, traces } = useFetchQuery({
|
||||
visible: true,
|
||||
customStep
|
||||
});
|
||||
|
||||
const handleTraceDelete = (trace: Trace) => {
|
||||
const updatedTraces = tracesState.filter((data) => data.idValue !== trace.idValue);
|
||||
setTracesState([...updatedTraces]);
|
||||
};
|
||||
|
||||
const handleHideQuery = (queries: number[]) => {
|
||||
setHideQuery(queries);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (traces) {
|
||||
setTracesState([...tracesState, ...traces]);
|
||||
@ -71,6 +77,7 @@ const CustomPanel: FC = () => {
|
||||
<QueryConfigurator
|
||||
error={error}
|
||||
queryOptions={queryOptions}
|
||||
onHideQuery={handleHideQuery}
|
||||
/>
|
||||
{isTracingEnabled && (
|
||||
<div className="vm-custom-panel__trace">
|
||||
@ -80,22 +87,26 @@ const CustomPanel: FC = () => {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{isLoading && <Spinner />}
|
||||
{error && <Alert variant="error">{error}</Alert>}
|
||||
{warning && <Alert variant="warning">{warning}</Alert>}
|
||||
<div className="vm-custom-panel-body vm-block">
|
||||
{isLoading && <Spinner />}
|
||||
<div className="vm-custom-panel-body-header">
|
||||
<DisplayTypeSwitch/>
|
||||
{displayType === "chart" && <GraphSettings
|
||||
yaxis={yaxis}
|
||||
setYaxisLimits={setYaxisLimits}
|
||||
toggleEnableLimits={toggleEnableLimits}
|
||||
/>}
|
||||
{displayType === "table" && <TableSettings
|
||||
data={liveData || []}
|
||||
defaultColumns={displayColumns}
|
||||
onChange={setDisplayColumns}
|
||||
/>}
|
||||
{displayType === "chart" && (
|
||||
<GraphSettings
|
||||
yaxis={yaxis}
|
||||
setYaxisLimits={setYaxisLimits}
|
||||
toggleEnableLimits={toggleEnableLimits}
|
||||
/>
|
||||
)}
|
||||
{displayType === "table" && (
|
||||
<TableSettings
|
||||
data={liveData || []}
|
||||
defaultColumns={displayColumns}
|
||||
onChange={setDisplayColumns}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{graphData && period && (displayType === "chart") && (
|
||||
<GraphView
|
||||
@ -108,7 +119,9 @@ const CustomPanel: FC = () => {
|
||||
setPeriod={setPeriod}
|
||||
/>
|
||||
)}
|
||||
{liveData && (displayType === "code") && <JsonView data={liveData}/>}
|
||||
{liveData && (displayType === "code") && (
|
||||
<JsonView data={liveData}/>
|
||||
)}
|
||||
{liveData && (displayType === "table") && (
|
||||
<TableView
|
||||
data={liveData}
|
||||
|
@ -18,6 +18,7 @@ The following tip changes can be tested by building VictoriaMetrics components f
|
||||
* FEATURE: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): add [range_linear_regression](https://docs.victoriametrics.com/MetricsQL.html#range_linear_regression) function for calculating [simple linear regression](https://en.wikipedia.org/wiki/Simple_linear_regression) over the input time series on the selected time range. This function is useful for predictions and capacity planning. For example, `range_linear_regression(process_resident_memory_bytes)` can predict future memory usage based on the past memory usage.
|
||||
* FEATURE: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): add [range_stddev](https://docs.victoriametrics.com/MetricsQL.html#range_stddev) and [range_stdvar](https://docs.victoriametrics.com/MetricsQL.html#range_stdvar) functions.
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): improve structure project, change state management, reduce bundle size, remove Material-UI. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/3298)
|
||||
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add the ability to hide the query.
|
||||
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): save the value of the switches "Trace request" and "Disable cache" after page reload.
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/#vmui): properly show the tab when navigating from the Prometheus URL in Grafana.
|
||||
|
Loading…
Reference in New Issue
Block a user