mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
vmui: introduce application mode (#1949)
* feat: add a label for the Query field
* fix: change zoom position
* fix: add description and error code to alerts
* fix: correct logic query history
* fix: correct update query history
* feat: add custom step
* update package-lock.json
* feat: introduce application mode
* build vmui
* Revert "build vmui"
This reverts commit c0e2415550
.
* app/vmselect/vmui: `make vmui-update`
Co-authored-by: Aliaksandr Valialkin <valyala@victoriametrics.com>
This commit is contained in:
parent
65bef771f6
commit
9baad51004
8 changed files with 43 additions and 11 deletions
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"files": {
|
||||
"main.css": "./static/css/main.83d9ae2d.chunk.css",
|
||||
"main.js": "./static/js/main.6651c49c.chunk.js",
|
||||
"main.js": "./static/js/main.7fc9cf07.chunk.js",
|
||||
"runtime-main.js": "./static/js/runtime-main.c4b656b8.js",
|
||||
"static/css/2.77671664.chunk.css": "./static/css/2.77671664.chunk.css",
|
||||
"static/js/2.ef1db8c8.chunk.js": "./static/js/2.ef1db8c8.chunk.js",
|
||||
|
@ -14,6 +14,6 @@
|
|||
"static/css/2.77671664.chunk.css",
|
||||
"static/js/2.ef1db8c8.chunk.js",
|
||||
"static/css/main.83d9ae2d.chunk.css",
|
||||
"static/js/main.6651c49c.chunk.js"
|
||||
"static/js/main.7fc9cf07.chunk.js"
|
||||
]
|
||||
}
|
|
@ -1 +1 @@
|
|||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="VM-UI is a metric explorer for Victoria Metrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><link href="./static/css/2.77671664.chunk.css" rel="stylesheet"><link href="./static/css/main.83d9ae2d.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,i,a=r[0],c=r[1],l=r[2],s=0,p=[];s<a.length;s++)i=a[s],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&p.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(r);p.length;)p.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++){var c=t[a];0!==o[c]&&(n=!1)}n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={1:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+"static/js/"+({}[e]||e)+"."+{3:"65648506"}[e]+".chunk.js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,function(r){return e[r]}.bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="./",i.oe=function(e){throw console.error(e),e};var a=this.webpackJsonpvmui=this.webpackJsonpvmui||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var l=0;l<a.length;l++)r(a[l]);var f=c;t()}([])</script><script src="./static/js/2.ef1db8c8.chunk.js"></script><script src="./static/js/main.6651c49c.chunk.js"></script></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="VM-UI is a metric explorer for Victoria Metrics"/><link rel="apple-touch-icon" href="./apple-touch-icon.png"/><link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png"><link rel="manifest" href="./manifest.json"/><title>VM UI</title><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><link href="./static/css/2.77671664.chunk.css" rel="stylesheet"><link href="./static/css/main.83d9ae2d.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,i,a=r[0],c=r[1],l=r[2],s=0,p=[];s<a.length;s++)i=a[s],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&p.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(r);p.length;)p.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++){var c=t[a];0!==o[c]&&(n=!1)}n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={1:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+"static/js/"+({}[e]||e)+"."+{3:"65648506"}[e]+".chunk.js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,function(r){return e[r]}.bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="./",i.oe=function(e){throw console.error(e),e};var a=this.webpackJsonpvmui=this.webpackJsonpvmui||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var l=0;l<a.length;l++)r(a[l]);var f=c;t()}([])</script><script src="./static/js/2.ef1db8c8.chunk.js"></script><script src="./static/js/main.7fc9cf07.chunk.js"></script></body></html>
|
File diff suppressed because one or more lines are too long
1
app/vmselect/vmui/static/js/main.7fc9cf07.chunk.js
Normal file
1
app/vmselect/vmui/static/js/main.7fc9cf07.chunk.js
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,9 +1,10 @@
|
|||
import React, {FC, useState} from "react";
|
||||
import React, {FC, useEffect, useState} from "react";
|
||||
import {Box, TextField, Tooltip, IconButton} from "@mui/material";
|
||||
import SecurityIcon from "@mui/icons-material/Security";
|
||||
import {useAppDispatch, useAppState} from "../../../../state/common/StateContext";
|
||||
import {AuthDialog} from "../Auth/AuthDialog";
|
||||
import {ErrorTypes} from "../../../../types";
|
||||
import {getAppModeEnable, getAppModeParams} from "../../../../utils/app-mode";
|
||||
|
||||
export interface ServerConfiguratorProps {
|
||||
error?: ErrorTypes | string;
|
||||
|
@ -11,6 +12,9 @@ export interface ServerConfiguratorProps {
|
|||
|
||||
const ServerConfigurator: FC<ServerConfiguratorProps> = ({error}) => {
|
||||
|
||||
const appModeEnable = getAppModeEnable();
|
||||
const {serverURL: appServerUrl} = getAppModeParams();
|
||||
|
||||
const {serverUrl} = useAppState();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
|
@ -19,9 +23,13 @@ const ServerConfigurator: FC<ServerConfiguratorProps> = ({error}) => {
|
|||
};
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (appModeEnable) dispatch({type: "SET_SERVER", payload: appServerUrl});
|
||||
}, [appServerUrl]);
|
||||
|
||||
return <>
|
||||
<Box display="grid" gridTemplateColumns="1fr auto" gap="4px" alignItems="center" width="100%" mb={2} minHeight={50}>
|
||||
<TextField variant="outlined" fullWidth label="Server URL" value={serverUrl}
|
||||
<TextField variant="outlined" fullWidth label="Server URL" value={serverUrl || ""} disabled={appModeEnable}
|
||||
error={error === ErrorTypes.validServer || error === ErrorTypes.emptyServer}
|
||||
inputProps={{style: {fontFamily: "Monospace"}}}
|
||||
onChange={onSetServer}/>
|
||||
|
|
|
@ -6,6 +6,10 @@ import {isValidHttpUrl} from "../../../../utils/url";
|
|||
import {useAuthState} from "../../../../state/auth/AuthStateContext";
|
||||
import {ErrorTypes, TimeParams} from "../../../../types";
|
||||
import {useGraphState} from "../../../../state/graph/GraphStateContext";
|
||||
import {getAppModeEnable, getAppModeParams} from "../../../../utils/app-mode";
|
||||
|
||||
const appModeEnable = getAppModeEnable();
|
||||
const {serverURL: appServerUrl} = getAppModeParams();
|
||||
|
||||
export const useFetchQuery = (): {
|
||||
fetchUrl?: string[],
|
||||
|
@ -80,18 +84,19 @@ export const useFetchQuery = (): {
|
|||
};
|
||||
|
||||
const fetchUrl = useMemo(() => {
|
||||
const server = appModeEnable ? appServerUrl : serverUrl;
|
||||
if (!period) return;
|
||||
if (!serverUrl) {
|
||||
if (!server) {
|
||||
setError(ErrorTypes.emptyServer);
|
||||
} else if (query.every(q => !q.trim())) {
|
||||
setError(ErrorTypes.validQuery);
|
||||
} else if (isValidHttpUrl(serverUrl)) {
|
||||
} else if (isValidHttpUrl(server)) {
|
||||
const duration = (period.end - period.start) / 2;
|
||||
const bufferPeriod = {...period, start: period.start - duration, end: period.end + duration};
|
||||
if (customStep.enable) bufferPeriod.step = customStep.value;
|
||||
return query.filter(q => q.trim()).map(q => displayType === "chart"
|
||||
? getQueryRangeUrl(serverUrl, q, bufferPeriod, nocache)
|
||||
: getQueryUrl(serverUrl, q, period));
|
||||
? getQueryRangeUrl(server, q, bufferPeriod, nocache)
|
||||
: getQueryUrl(server, q, period));
|
||||
} else {
|
||||
setError(ErrorTypes.validServer);
|
||||
}
|
||||
|
|
12
app/vmui/packages/vmui/src/utils/app-mode.ts
Normal file
12
app/vmui/packages/vmui/src/utils/app-mode.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
export interface AppParams {
|
||||
serverURL: string
|
||||
}
|
||||
|
||||
const getAppModeParams = (): AppParams => {
|
||||
const dataParams = document.getElementById("root")?.dataset.params || "{}";
|
||||
return JSON.parse(dataParams);
|
||||
};
|
||||
|
||||
const getAppModeEnable = (): boolean => !!Object.keys(getAppModeParams()).length;
|
||||
|
||||
export {getAppModeEnable, getAppModeParams};
|
|
@ -1,5 +1,6 @@
|
|||
import qs from "qs";
|
||||
import get from "lodash.get";
|
||||
import {getAppModeEnable} from "./app-mode";
|
||||
|
||||
const stateToUrlParams = {
|
||||
"time.duration": "range_input",
|
||||
|
@ -8,6 +9,8 @@ const stateToUrlParams = {
|
|||
"displayType": "tab"
|
||||
};
|
||||
|
||||
const appModeEnable = getAppModeEnable();
|
||||
|
||||
// TODO need function for detect types.
|
||||
// const decoder = (value: string) => {
|
||||
// This function does not parse dates
|
||||
|
@ -31,12 +34,16 @@ const stateToUrlParams = {
|
|||
export const setQueryStringWithoutPageReload = (qsValue: string): void => {
|
||||
const w = window;
|
||||
if (w) {
|
||||
const newurl = `${w.location.protocol}//${w.location.host}${w.location.pathname}?${qsValue}`;
|
||||
const newurl = `${w.location.protocol}//${w.location.host}${w.location.pathname}${qsValue ? "?" : ""}${qsValue}`;
|
||||
w.history.pushState({ path: newurl }, "", newurl);
|
||||
}
|
||||
};
|
||||
|
||||
export const setQueryStringValue = (newValue: Record<string, unknown>): void => {
|
||||
if (appModeEnable) {
|
||||
setQueryStringWithoutPageReload("");
|
||||
return;
|
||||
}
|
||||
const queryMap = new Map(Object.entries(stateToUrlParams));
|
||||
const query = get(newValue, "query", "") as string[];
|
||||
const newQsValue: string[] = [];
|
||||
|
|
Loading…
Reference in a new issue