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:
Yury Molodov 2022-11-17 17:42:33 +01:00 committed by Aliaksandr Valialkin
parent 478a295208
commit 734172d2d0
No known key found for this signature in database
GPG key ID: A72BEC6CD3D0DED1
9 changed files with 122 additions and 28 deletions

View file

@ -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}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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>
);

View file

@ -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;

View file

@ -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">

View file

@ -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;

View file

@ -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}

View file

@ -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.