diff --git a/app/vmui/packages/vmui/package.json b/app/vmui/packages/vmui/package.json index 159525955..6682b1052 100644 --- a/app/vmui/packages/vmui/package.json +++ b/app/vmui/packages/vmui/package.json @@ -71,6 +71,7 @@ "eslint": "^8.44.0", "eslint-config-react-app": "^7.0.1", "eslint-plugin-react": "^7.29.4", + "http-proxy-middleware": "^3.0.0", "react-app-rewired": "^2.2.1", "webpack": "^5.88.1" }, diff --git a/app/vmui/packages/vmui/src/components/ExploreAnomaly/AnomalyConfig.tsx b/app/vmui/packages/vmui/src/components/ExploreAnomaly/AnomalyConfig.tsx index ca9a90fc5..8bd78a84f 100644 --- a/app/vmui/packages/vmui/src/components/ExploreAnomaly/AnomalyConfig.tsx +++ b/app/vmui/packages/vmui/src/components/ExploreAnomaly/AnomalyConfig.tsx @@ -9,6 +9,9 @@ import useDeviceDetect from "../../hooks/useDeviceDetect"; import { useAppState } from "../../state/common/StateContext"; import classNames from "classnames"; import "./style.scss"; +import { useQueryState } from "../../state/query/QueryStateContext"; +import { useTimeState } from "../../state/time/TimeStateContext"; +import { getStepFromDuration } from "../../utils/time"; const AnomalyConfig: FC = () => { const { serverUrl } = useAppState(); @@ -20,6 +23,8 @@ const AnomalyConfig: FC = () => { setFalse: setCloseModal, } = useBoolean(false); + const { query } = useQueryState(); + const { period } = useTimeState(); const [isLoading, setIsLoading] = useState(false); const [textConfig, setTextConfig] = useState(""); const [downloadUrl, setDownloadUrl] = useState(""); @@ -28,15 +33,22 @@ const AnomalyConfig: FC = () => { const fetchConfig = async () => { setIsLoading(true); 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 contentType = response.headers.get("Content-Type"); if (!response.ok) { - setError(` ${response.status} ${response.statusText}`); - } else { + const bodyText = await response.text(); + setError(` ${response.status} ${response.statusText}: ${bodyText}`); + } else if (contentType == "application/yaml") { const blob = await response.blob(); const yamlAsString = await blob.text(); setTextConfig(yamlAsString); setDownloadUrl(URL.createObjectURL(blob)); + } else { + setError("Response Content-Type is not YAML, does `Server URL` point to VMAnomaly server?"); } } catch (error) { console.error(error); diff --git a/app/vmui/packages/vmui/src/components/Main/Modal/Modal.tsx b/app/vmui/packages/vmui/src/components/Main/Modal/Modal.tsx index 713996484..87b53c5d8 100644 --- a/app/vmui/packages/vmui/src/components/Main/Modal/Modal.tsx +++ b/app/vmui/packages/vmui/src/components/Main/Modal/Modal.tsx @@ -88,9 +88,11 @@ const Modal: FC = ({ + {/* tabIndex to fix Ctrl-A */}
{children}
diff --git a/app/vmui/packages/vmui/src/hooks/useFetchQuery.ts b/app/vmui/packages/vmui/src/hooks/useFetchQuery.ts index d700c7a4e..6a1f125be 100644 --- a/app/vmui/packages/vmui/src/hooks/useFetchQuery.ts +++ b/app/vmui/packages/vmui/src/hooks/useFetchQuery.ts @@ -12,7 +12,7 @@ import { useTimeState } from "../state/time/TimeStateContext"; import { useCustomPanelState } from "../state/customPanel/CustomPanelStateContext"; import { isHistogramData } from "../utils/metric"; import { useGraphState } from "../state/graph/GraphStateContext"; -import { getSecondsFromDuration, getStepFromDuration } from "../utils/time"; +import { getStepFromDuration } from "../utils/time"; import { AppType } from "../types/appType"; interface FetchQueryParams { @@ -183,7 +183,7 @@ export const useFetchQuery = ({ setQueryErrors(expr.map(() => ErrorTypes.validQuery)); } else if (isValidHttpUrl(serverUrl)) { const updatedPeriod = { ...period }; - updatedPeriod.step = isAnomalyUI ? `${getSecondsFromDuration(customStep)*1000}ms` : customStep; + updatedPeriod.step = customStep; return expr.map(q => displayChart ? getQueryRangeUrl(serverUrl, q, updatedPeriod, nocache, isTracingEnabled) : getQueryUrl(serverUrl, q, updatedPeriod, nocache, isTracingEnabled)); diff --git a/app/vmui/packages/vmui/src/pages/ExploreAnomaly/ExploreAnomaly.tsx b/app/vmui/packages/vmui/src/pages/ExploreAnomaly/ExploreAnomaly.tsx index d7d021a19..164990224 100644 --- a/app/vmui/packages/vmui/src/pages/ExploreAnomaly/ExploreAnomaly.tsx +++ b/app/vmui/packages/vmui/src/pages/ExploreAnomaly/ExploreAnomaly.tsx @@ -87,7 +87,7 @@ const ExploreAnomaly: FC = () => { setHideError={setHideError} stats={queryStats} 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 && } {(!hideError && error) && {error}} diff --git a/app/vmui/packages/vmui/src/setupProxy.js b/app/vmui/packages/vmui/src/setupProxy.js new file mode 100644 index 000000000..b66c03f8f --- /dev/null +++ b/app/vmui/packages/vmui/src/setupProxy.js @@ -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, + }) + ); +}; diff --git a/app/vmui/packages/vmui/src/utils/time.ts b/app/vmui/packages/vmui/src/utils/time.ts index 434964e77..e3958854f 100644 --- a/app/vmui/packages/vmui/src/utils/time.ts +++ b/app/vmui/packages/vmui/src/utils/time.ts @@ -34,7 +34,7 @@ export const humanizeSeconds = (num: number): string => { return getDurationFromMilliseconds(dayjs.duration(num, "seconds").asMilliseconds()); }; -export const roundStep = (step: number) => { +export const roundStep = (step: number): string => { let result = roundToMilliseconds(step); const integerStep = Math.round(step); @@ -87,7 +87,7 @@ export const getSecondsFromDuration = (dur: string) => { 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; return roundStep(dur / size); };