mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-01-05 22:32:20 +01:00
vmui: Improve DownloadConfig button interaction with VMAnomaly (#6397)
Co-authored-by: Dzmitry Lazerka <dlazerka@gmail.com>
This commit is contained in:
parent
2e3c039113
commit
362ee240cd
@ -71,6 +71,7 @@
|
|||||||
"eslint": "^8.44.0",
|
"eslint": "^8.44.0",
|
||||||
"eslint-config-react-app": "^7.0.1",
|
"eslint-config-react-app": "^7.0.1",
|
||||||
"eslint-plugin-react": "^7.29.4",
|
"eslint-plugin-react": "^7.29.4",
|
||||||
|
"http-proxy-middleware": "^3.0.0",
|
||||||
"react-app-rewired": "^2.2.1",
|
"react-app-rewired": "^2.2.1",
|
||||||
"webpack": "^5.88.1"
|
"webpack": "^5.88.1"
|
||||||
},
|
},
|
||||||
|
@ -9,6 +9,9 @@ import useDeviceDetect from "../../hooks/useDeviceDetect";
|
|||||||
import { useAppState } from "../../state/common/StateContext";
|
import { useAppState } from "../../state/common/StateContext";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import "./style.scss";
|
import "./style.scss";
|
||||||
|
import { useQueryState } from "../../state/query/QueryStateContext";
|
||||||
|
import { useTimeState } from "../../state/time/TimeStateContext";
|
||||||
|
import { getStepFromDuration } from "../../utils/time";
|
||||||
|
|
||||||
const AnomalyConfig: FC = () => {
|
const AnomalyConfig: FC = () => {
|
||||||
const { serverUrl } = useAppState();
|
const { serverUrl } = useAppState();
|
||||||
@ -20,6 +23,8 @@ const AnomalyConfig: FC = () => {
|
|||||||
setFalse: setCloseModal,
|
setFalse: setCloseModal,
|
||||||
} = useBoolean(false);
|
} = useBoolean(false);
|
||||||
|
|
||||||
|
const { query } = useQueryState();
|
||||||
|
const { period } = useTimeState();
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [textConfig, setTextConfig] = useState<string>("");
|
const [textConfig, setTextConfig] = useState<string>("");
|
||||||
const [downloadUrl, setDownloadUrl] = useState<string>("");
|
const [downloadUrl, setDownloadUrl] = useState<string>("");
|
||||||
@ -28,15 +33,22 @@ const AnomalyConfig: FC = () => {
|
|||||||
const fetchConfig = async () => {
|
const fetchConfig = async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const url = `${serverUrl}/api/vmanomaly/config.yaml`;
|
const queryParam = encodeURIComponent(query[0] || "");
|
||||||
|
const stepParam = encodeURIComponent(period.step || getStepFromDuration(period.end - period.start, false));
|
||||||
|
|
||||||
|
const url = `${serverUrl}/api/vmanomaly/config.yaml?query=${queryParam}&step=${stepParam}`;
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
|
const contentType = response.headers.get("Content-Type");
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
setError(` ${response.status} ${response.statusText}`);
|
const bodyText = await response.text();
|
||||||
} else {
|
setError(` ${response.status} ${response.statusText}: ${bodyText}`);
|
||||||
|
} else if (contentType == "application/yaml") {
|
||||||
const blob = await response.blob();
|
const blob = await response.blob();
|
||||||
const yamlAsString = await blob.text();
|
const yamlAsString = await blob.text();
|
||||||
setTextConfig(yamlAsString);
|
setTextConfig(yamlAsString);
|
||||||
setDownloadUrl(URL.createObjectURL(blob));
|
setDownloadUrl(URL.createObjectURL(blob));
|
||||||
|
} else {
|
||||||
|
setError("Response Content-Type is not YAML, does `Server URL` point to VMAnomaly server?");
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
@ -88,9 +88,11 @@ const Modal: FC<ModalProps> = ({
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/* tabIndex to fix Ctrl-A */}
|
||||||
<div
|
<div
|
||||||
className="vm-modal-content-body"
|
className="vm-modal-content-body"
|
||||||
onMouseDown={handleMouseDown}
|
onMouseDown={handleMouseDown}
|
||||||
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,7 +12,7 @@ import { useTimeState } from "../state/time/TimeStateContext";
|
|||||||
import { useCustomPanelState } from "../state/customPanel/CustomPanelStateContext";
|
import { useCustomPanelState } from "../state/customPanel/CustomPanelStateContext";
|
||||||
import { isHistogramData } from "../utils/metric";
|
import { isHistogramData } from "../utils/metric";
|
||||||
import { useGraphState } from "../state/graph/GraphStateContext";
|
import { useGraphState } from "../state/graph/GraphStateContext";
|
||||||
import { getSecondsFromDuration, getStepFromDuration } from "../utils/time";
|
import { getStepFromDuration } from "../utils/time";
|
||||||
import { AppType } from "../types/appType";
|
import { AppType } from "../types/appType";
|
||||||
|
|
||||||
interface FetchQueryParams {
|
interface FetchQueryParams {
|
||||||
@ -183,7 +183,7 @@ export const useFetchQuery = ({
|
|||||||
setQueryErrors(expr.map(() => ErrorTypes.validQuery));
|
setQueryErrors(expr.map(() => ErrorTypes.validQuery));
|
||||||
} else if (isValidHttpUrl(serverUrl)) {
|
} else if (isValidHttpUrl(serverUrl)) {
|
||||||
const updatedPeriod = { ...period };
|
const updatedPeriod = { ...period };
|
||||||
updatedPeriod.step = isAnomalyUI ? `${getSecondsFromDuration(customStep)*1000}ms` : customStep;
|
updatedPeriod.step = customStep;
|
||||||
return expr.map(q => displayChart
|
return expr.map(q => displayChart
|
||||||
? getQueryRangeUrl(serverUrl, q, updatedPeriod, nocache, isTracingEnabled)
|
? getQueryRangeUrl(serverUrl, q, updatedPeriod, nocache, isTracingEnabled)
|
||||||
: getQueryUrl(serverUrl, q, updatedPeriod, nocache, isTracingEnabled));
|
: getQueryUrl(serverUrl, q, updatedPeriod, nocache, isTracingEnabled));
|
||||||
|
@ -87,7 +87,7 @@ const ExploreAnomaly: FC = () => {
|
|||||||
setHideError={setHideError}
|
setHideError={setHideError}
|
||||||
stats={queryStats}
|
stats={queryStats}
|
||||||
onRunQuery={handleRunQuery}
|
onRunQuery={handleRunQuery}
|
||||||
hideButtons={{ addQuery: true, prettify: true, autocomplete: true, traceQuery: true, anomalyConfig: true }}
|
hideButtons={{ addQuery: true, prettify: false, autocomplete: false, traceQuery: true, anomalyConfig: true }}
|
||||||
/>
|
/>
|
||||||
{isLoading && <Spinner/>}
|
{isLoading && <Spinner/>}
|
||||||
{(!hideError && error) && <Alert variant="error">{error}</Alert>}
|
{(!hideError && error) && <Alert variant="error">{error}</Alert>}
|
||||||
|
11
app/vmui/packages/vmui/src/setupProxy.js
Normal file
11
app/vmui/packages/vmui/src/setupProxy.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const { createProxyMiddleware } = require('http-proxy-middleware');
|
||||||
|
|
||||||
|
module.exports = function (app) {
|
||||||
|
app.use(
|
||||||
|
"/api",
|
||||||
|
createProxyMiddleware({
|
||||||
|
target: "http://localhost:8490/api",
|
||||||
|
changeOrigin: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
@ -34,7 +34,7 @@ export const humanizeSeconds = (num: number): string => {
|
|||||||
return getDurationFromMilliseconds(dayjs.duration(num, "seconds").asMilliseconds());
|
return getDurationFromMilliseconds(dayjs.duration(num, "seconds").asMilliseconds());
|
||||||
};
|
};
|
||||||
|
|
||||||
export const roundStep = (step: number) => {
|
export const roundStep = (step: number): string => {
|
||||||
let result = roundToMilliseconds(step);
|
let result = roundToMilliseconds(step);
|
||||||
const integerStep = Math.round(step);
|
const integerStep = Math.round(step);
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ export const getSecondsFromDuration = (dur: string) => {
|
|||||||
return dayjs.duration(durObject).asSeconds();
|
return dayjs.duration(durObject).asSeconds();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getStepFromDuration = (dur: number, histogram?: boolean) => {
|
export const getStepFromDuration = (dur: number, histogram?: boolean): string => {
|
||||||
const size = histogram ? MAX_ITEMS_PER_HISTOGRAM : MAX_ITEMS_PER_CHART;
|
const size = histogram ? MAX_ITEMS_PER_HISTOGRAM : MAX_ITEMS_PER_CHART;
|
||||||
return roundStep(dur / size);
|
return roundStep(dur / size);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user