- {query.length < 2 &&
-
- }
-
-
-
-
-
-
-
-
-
-
- >;
+ return
+
+ {query.map((q, i) =>
+
+
+ {i === 0 &&
+
+
+
+ }
+ {query.length < 2 &&
+
+
+
+ }
+ {i > 0 &&
+ onRemoveQuery(i)} sx={{height: "49px", width: "49px"}}>
+
+
+ }
+ )}
+
+
+
+
+ ;
};
export default QueryConfigurator;
\ No newline at end of file
diff --git a/app/vmui/packages/vmui/src/components/Home/Configurator/Query/ServerConfigurator.tsx b/app/vmui/packages/vmui/src/components/Home/Configurator/Query/ServerConfigurator.tsx
deleted file mode 100644
index 628ee581fa..0000000000
--- a/app/vmui/packages/vmui/src/components/Home/Configurator/Query/ServerConfigurator.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import React, {FC, useEffect, useState} from "preact/compat";
-import Box from "@mui/material/Box";
-import TextField from "@mui/material/TextField";
-import Tooltip from "@mui/material/Tooltip";
-import IconButton from "@mui/material/IconButton";
-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;
-}
-
-const ServerConfigurator: FC
= ({error}) => {
-
- const appModeEnable = getAppModeEnable();
- const {serverURL: appServerUrl} = getAppModeParams();
-
- const {serverUrl} = useAppState();
- const dispatch = useAppDispatch();
-
- const onSetServer = ({target: {value}}: {target: {value: string}}) => {
- dispatch({type: "SET_SERVER", payload: value});
- };
- const [dialogOpen, setDialogOpen] = useState(false);
-
- useEffect(() => {
- if (appModeEnable) dispatch({type: "SET_SERVER", payload: appServerUrl});
- }, [appServerUrl]);
-
- return <>
-
-
-
-
- setDialogOpen(true)}>
-
-
-
-
-
- setDialogOpen(false)}/>
- >;
-};
-
-export default ServerConfigurator;
\ No newline at end of file
diff --git a/app/vmui/packages/vmui/src/components/Home/Configurator/Settings/GlobalSettings.tsx b/app/vmui/packages/vmui/src/components/Home/Configurator/Settings/GlobalSettings.tsx
new file mode 100644
index 0000000000..3c9178bac3
--- /dev/null
+++ b/app/vmui/packages/vmui/src/components/Home/Configurator/Settings/GlobalSettings.tsx
@@ -0,0 +1,82 @@
+import React, {FC, useState} from "preact/compat";
+import Tooltip from "@mui/material/Tooltip";
+import SettingsIcon from "@mui/icons-material/Settings";
+import Button from "@mui/material/Button";
+import Box from "@mui/material/Box";
+import Modal from "@mui/material/Modal";
+import ServerConfigurator from "./ServerConfigurator";
+import Typography from "@mui/material/Typography";
+import CloseIcon from "@mui/icons-material/Close";
+import IconButton from "@mui/material/IconButton";
+import {useAppDispatch, useAppState} from "../../../../state/common/StateContext";
+import {getAppModeEnable} from "../../../../utils/app-mode";
+
+const modalStyle = {
+ position: "absolute" as const,
+ top: "50%",
+ left: "50%",
+ transform: "translate(-50%, -50%)",
+ bgcolor: "background.paper",
+ p: 3,
+ borderRadius: "4px",
+ width: "80%",
+ maxWidth: "800px"
+};
+
+const title = "Setting Server URL";
+
+const GlobalSettings: FC = () => {
+
+ const appModeEnable = getAppModeEnable();
+ const {serverUrl} = useAppState();
+ const dispatch = useAppDispatch();
+ const [changedServerUrl, setChangedServerUrl] = useState(serverUrl);
+
+ const setServer = () => {
+ if (!appModeEnable) dispatch({type: "SET_SERVER", payload: changedServerUrl});
+ handleClose();
+ };
+
+ const [open, setOpen] = useState(false);
+ const handleOpen = () => setOpen(true);
+ const handleClose = () => setOpen(false);
+
+ return <>
+
+ }
+ onClick={handleOpen}>
+
+
+
+
+
+
+ {title}
+
+
+
+
+
+
+
+
+
+
+
+
+ >;
+};
+
+export default GlobalSettings;
\ No newline at end of file
diff --git a/app/vmui/packages/vmui/src/components/Home/Configurator/Settings/ServerConfigurator.tsx b/app/vmui/packages/vmui/src/components/Home/Configurator/Settings/ServerConfigurator.tsx
new file mode 100644
index 0000000000..548b752c7d
--- /dev/null
+++ b/app/vmui/packages/vmui/src/components/Home/Configurator/Settings/ServerConfigurator.tsx
@@ -0,0 +1,41 @@
+import React, {FC, useEffect, useState} from "preact/compat";
+import TextField from "@mui/material/TextField";
+import {useAppDispatch, useAppState} from "../../../../state/common/StateContext";
+import {ErrorTypes} from "../../../../types";
+import {getAppModeEnable, getAppModeParams} from "../../../../utils/app-mode";
+import {ChangeEvent} from "react";
+
+export interface ServerConfiguratorProps {
+ error?: ErrorTypes | string;
+ setServer: (url: string) => void
+}
+
+const ServerConfigurator: FC = ({error, setServer}) => {
+
+ const appModeEnable = getAppModeEnable();
+ const {serverURL: appServerUrl} = getAppModeParams();
+
+ const {serverUrl} = useAppState();
+ const dispatch = useAppDispatch();
+ const [changedServerUrl, setChangedServerUrl] = useState(serverUrl);
+
+ useEffect(() => {
+ if (appModeEnable) {
+ dispatch({type: "SET_SERVER", payload: appServerUrl});
+ setChangedServerUrl(appServerUrl);
+ }
+ }, [appServerUrl]);
+
+ const onChangeServer = (e: ChangeEvent) => {
+ const value = e.target.value || "";
+ setChangedServerUrl(value);
+ setServer(value);
+ };
+
+ return ;
+};
+
+export default ServerConfigurator;
\ No newline at end of file
diff --git a/app/vmui/packages/vmui/src/components/Home/Configurator/Time/ExecutionControls.tsx b/app/vmui/packages/vmui/src/components/Home/Configurator/Time/ExecutionControls.tsx
index d0303f93b4..ebd0a00687 100644
--- a/app/vmui/packages/vmui/src/components/Home/Configurator/Time/ExecutionControls.tsx
+++ b/app/vmui/packages/vmui/src/components/Home/Configurator/Time/ExecutionControls.tsx
@@ -1,92 +1,100 @@
import React, {FC, useEffect, useState} from "preact/compat";
-import Box from "@mui/material/Box";
-import FormControlLabel from "@mui/material/FormControlLabel";
-import IconButton from "@mui/material/IconButton";
import Tooltip from "@mui/material/Tooltip";
-import EqualizerIcon from "@mui/icons-material/Equalizer";
import {useAppDispatch, useAppState} from "../../../../state/common/StateContext";
-import CircularProgressWithLabel from "../../../common/CircularProgressWithLabel";
-import makeStyles from "@mui/styles/makeStyles";
-import BasicSwitch from "../../../../theme/switch";
+import Button from "@mui/material/Button";
+import Popper from "@mui/material/Popper";
+import Paper from "@mui/material/Paper";
+import ClickAwayListener from "@mui/material/ClickAwayListener";
+import AutorenewIcon from "@mui/icons-material/Autorenew";
+import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
+import List from "@mui/material/List";
+import ListItem from "@mui/material/ListItem";
+import ListItemText from "@mui/material/ListItemText";
-const useStyles = makeStyles({
- colorizing: {
- color: "white"
- }
-});
+interface AutoRefreshOption {
+ seconds: number
+ title: string
+}
+
+const delayOptions: AutoRefreshOption[] = [
+ {seconds: 0, title: "Off"},
+ {seconds: 1, title: "1s"},
+ {seconds: 2, title: "2s"},
+ {seconds: 5, title: "5s"},
+ {seconds: 10, title: "10s"},
+ {seconds: 30, title: "30s"},
+ {seconds: 60, title: "1m"},
+ {seconds: 300, title: "5m"},
+ {seconds: 900, title: "15m"},
+ {seconds: 1800, title: "30m"},
+ {seconds: 3600, title: "1h"},
+ {seconds: 7200, title: "2h"}
+];
export const ExecutionControls: FC = () => {
- const classes = useStyles();
const dispatch = useAppDispatch();
const {queryControls: {autoRefresh}} = useAppState();
- const [delay, setDelay] = useState<(1|2|5)>(5);
- const [lastUpdate, setLastUpdate] = useState();
- const [progress, setProgress] = React.useState(100);
+ const [selectedDelay, setSelectedDelay] = useState(delayOptions[0]);
- const handleChange = () => {
- dispatch({type: "TOGGLE_AUTOREFRESH"});
+ const handleChange = (d: AutoRefreshOption) => {
+ if ((autoRefresh && !d.seconds) || (!autoRefresh && d.seconds)) {
+ dispatch({type: "TOGGLE_AUTOREFRESH"});
+ }
+ setSelectedDelay(d);
+ setAnchorEl(null);
};
useEffect(() => {
+ const delay = selectedDelay.seconds;
let timer: number;
if (autoRefresh) {
- setLastUpdate(new Date().valueOf());
timer = setInterval(() => {
- setLastUpdate(new Date().valueOf());
dispatch({type: "RUN_QUERY_TO_NOW"});
}, delay * 1000) as unknown as number;
+ } else {
+ setSelectedDelay(delayOptions[0]);
}
return () => {
timer && clearInterval(timer);
};
- }, [delay, autoRefresh]);
+ }, [selectedDelay, autoRefresh]);
- useEffect(() => {
- const timer = setInterval(() => {
- if (autoRefresh && lastUpdate) {
- const delta = (new Date().valueOf() - lastUpdate) / 1000; //s
- const nextValue = Math.floor(delta / delay * 100);
- setProgress(nextValue);
- }
- }, 16);
- return () => {
- clearInterval(timer);
- };
- }, [autoRefresh, lastUpdate, delay]);
+ const [anchorEl, setAnchorEl] = useState(null);
+ const open = Boolean(anchorEl);
- const iterateDelays = () => {
- setDelay(prev => {
- switch (prev) {
- case 1:
- return 2;
- case 2:
- return 5;
- case 5:
- return 1;
- default:
- return 5;
- }
- });
- };
-
- return
- {}
- label="Auto-refresh"
- />}
-
- {autoRefresh && <>
- {iterateDelays();}} />
-
-
- {iterateDelays();}}>
-
-
-
-
- >}
- ;
+ return <>
+
+
+
+
+ setAnchorEl(null)}>
+
+
+ {delayOptions.map(d =>
+ handleChange(d)}>
+
+ )}
+
+
+
+ >;
};
\ No newline at end of file
diff --git a/app/vmui/packages/vmui/src/components/Home/Configurator/Time/TimeDurationPopover.tsx b/app/vmui/packages/vmui/src/components/Home/Configurator/Time/TimeDurationPopover.tsx
deleted file mode 100644
index 9feef72e7f..0000000000
--- a/app/vmui/packages/vmui/src/components/Home/Configurator/Time/TimeDurationPopover.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import React, {FC} from "preact/compat";
-import Paper from "@mui/material/Paper";
-import Table from "@mui/material/Table";
-import TableBody from "@mui/material/TableBody";
-import TableCell from "@mui/material/TableCell";
-import TableContainer from "@mui/material/TableContainer";
-import TableHead from "@mui/material/TableHead";
-import TableRow from "@mui/material/TableRow";
-import {supportedDurations} from "../../../../utils/time";
-
-export const TimeDurationPopover: FC = () => {
-
- return
-
-
-
- Long
- Short
-
-
-
- {supportedDurations.map((row, index) => (
-
- {row.long}
- {row.short}
-
- ))}
-
-
- ;
-};
\ No newline at end of file
diff --git a/app/vmui/packages/vmui/src/components/Home/Configurator/Time/TimeDurationSelector.tsx b/app/vmui/packages/vmui/src/components/Home/Configurator/Time/TimeDurationSelector.tsx
index a9440086a0..8d3bf4a085 100644
--- a/app/vmui/packages/vmui/src/components/Home/Configurator/Time/TimeDurationSelector.tsx
+++ b/app/vmui/packages/vmui/src/components/Home/Configurator/Time/TimeDurationSelector.tsx
@@ -1,103 +1,47 @@
-import React, {FC, useEffect, useState} from "preact/compat";
-import {ChangeEvent, MouseEvent, KeyboardEvent} from "react";
-import Box from "@mui/material/Box";
-import Popover from "@mui/material/Popover";
-import TextField from "@mui/material/TextField";
-import Typography from "@mui/material/Typography";
-import {checkDurationLimit} from "../../../../utils/time";
-import {TimeDurationPopover} from "./TimeDurationPopover";
-import {InlineBtn} from "../../../common/InlineBtn";
-import {useAppState} from "../../../../state/common/StateContext";
+import React, {FC} from "preact/compat";
+import List from "@mui/material/List";
+import ListItem from "@mui/material/ListItem";
+import ListItemText from "@mui/material/ListItemText";
+import dayjs from "dayjs";
interface TimeDurationSelector {
- setDuration: (str: string) => void;
+ setDuration: (str: string, from: Date) => void;
}
+interface DurationOption {
+ duration: string,
+ title?: string,
+ from?: () => Date,
+}
+
+const durationOptions: DurationOption[] = [
+ {duration: "5m", title: "Last 5 minutes"},
+ {duration: "15m", title: "Last 15 minutes"},
+ {duration: "30m", title: "Last 30 minutes"},
+ {duration: "1h", title: "Last 1 hour"},
+ {duration: "3h", title: "Last 3 hours"},
+ {duration: "6h", title: "Last 6 hours"},
+ {duration: "12h", title: "Last 12 hours"},
+ {duration: "24h", title: "Last 24 hours"},
+ {duration: "2d", title: "Last 2 days"},
+ {duration: "7d", title: "Last 7 days"},
+ {duration: "30d", title: "Last 30 days"},
+ {duration: "90d", title: "Last 90 days"},
+ {duration: "6m", title: "Last 6 months"},
+ {duration: "1y", title: "Last 1 year"},
+ {duration: "1d", from: () => dayjs().subtract(1, "day").endOf("day").toDate(), title: "Yesterday"},
+ {duration: "1d", from: () => dayjs().endOf("day").toDate(), title: "Today"},
+];
+
const TimeDurationSelector: FC = ({setDuration}) => {
- const {time: {duration}} = useAppState();
+ // setDurationString("5m"))
- const [anchorEl, setAnchorEl] = React.useState(null);
- const [durationString, setDurationString] = useState(duration);
- const [durationStringFocused, setFocused] = useState(false);
- const open = Boolean(anchorEl);
-
- const handleDurationChange = (event: ChangeEvent) => {
- setDurationString(event.target.value);
- };
-
- const handlePopoverOpen = (event: MouseEvent) => {
- setAnchorEl(event.currentTarget);
- };
-
- const handlePopoverClose = () => {
- setAnchorEl(null);
- };
-
- const onKeyUp = (event: KeyboardEvent) => {
- if (event.key !== "Enter") return;
- const target = event.target as HTMLInputElement;
- target.blur();
- setDurationString(target.value);
- };
-
- useEffect(() => {
- setDurationString(duration);
- }, [duration]);
-
- useEffect(() => {
- if (!durationStringFocused) {
- const value = checkDurationLimit(durationString);
- setDurationString(value);
- setDuration(value);
- }
- }, [durationString, durationStringFocused]);
-
- return <>
-
- {
- setFocused(false);
- }}
- onFocus={() => {
- setFocused(true);
- }}
- />
-
-
-
-
- Possible options:
-
-
-
-
- setDurationString("5m")} text="5m"/>,
- setDurationString("1h")} text="1h"/>,
- setDurationString("1h 30m")} text="1h 30m"/>
-
-
- >;
+ return
+ {durationOptions.map(d =>
+ setDuration(d.duration, d.from ? d.from() : new Date())}>
+
+ )}
+
;
};
export default TimeDurationSelector;
\ No newline at end of file
diff --git a/app/vmui/packages/vmui/src/components/Home/Configurator/Time/TimeSelector.tsx b/app/vmui/packages/vmui/src/components/Home/Configurator/Time/TimeSelector.tsx
index 918e4d164b..0dede01684 100644
--- a/app/vmui/packages/vmui/src/components/Home/Configurator/Time/TimeSelector.tsx
+++ b/app/vmui/packages/vmui/src/components/Home/Configurator/Time/TimeSelector.tsx
@@ -1,40 +1,32 @@
-import React, {FC, useEffect, useState} from "preact/compat";
-import Box from "@mui/material/Box";
-import TextField from "@mui/material/TextField";
-import Typography from "@mui/material/Typography";
-import DateTimePicker from "@mui/lab/DateTimePicker";
+import React, {FC, useEffect, useState, useMemo} from "preact/compat";
import {useAppDispatch, useAppState} from "../../../../state/common/StateContext";
import {dateFromSeconds, formatDateForNativeInput} from "../../../../utils/time";
-import {InlineBtn} from "../../../common/InlineBtn";
import makeStyles from "@mui/styles/makeStyles";
import TimeDurationSelector from "./TimeDurationSelector";
import dayjs from "dayjs";
+import QueryBuilderIcon from "@mui/icons-material/QueryBuilder";
+import Box from "@mui/material/Box";
+import TextField from "@mui/material/TextField";
+import DateTimePicker from "@mui/lab/DateTimePicker";
+import Button from "@mui/material/Button";
+import Popper from "@mui/material/Popper";
+import Paper from "@mui/material/Paper";
+import Divider from "@mui/material/Divider";
+import ClickAwayListener from "@mui/material/ClickAwayListener";
+import Tooltip from "@mui/material/Tooltip";
-interface TimeSelectorProps {
- setDuration: (str: string) => void;
-}
+const formatDate = "YYYY-MM-DD HH:mm:ss";
const useStyles = makeStyles({
container: {
display: "grid",
- gridTemplateColumns: "200px 1fr",
- gridGap: "20px",
- height: "100%",
+ gridTemplateColumns: "200px auto 200px",
+ gridGap: "10px",
padding: "20px",
- borderRadius: "4px",
- borderColor: "#b9b9b9",
- borderStyle: "solid",
- borderWidth: "1px"
},
timeControls: {
display: "grid",
- gridTemplateColumns: "1fr",
- gridTemplateRows: "auto 1fr",
- gridGap: "16px 0",
- },
- datePickers: {
- display: "grid",
- gridTemplateColumns: "repeat(auto-fit, 200px)",
+ gridTemplateRows: "auto 1fr auto",
gridGap: "16px 0",
},
datePickerItem: {
@@ -42,7 +34,7 @@ const useStyles = makeStyles({
},
});
-export const TimeSelector: FC = ({setDuration}) => {
+export const TimeSelector: FC = () => {
const classes = useStyles();
@@ -60,46 +52,88 @@ export const TimeSelector: FC = ({setDuration}) => {
setFrom(formatDateForNativeInput(dateFromSeconds(start)));
}, [start]);
- return
- {/*setup duration*/}
-
-
-
- {/*setup end time*/}
-
-
-
- dispatch({type: "SET_FROM", payload: date as unknown as Date})}
- onError={console.log}
- inputFormat="DD/MM/YYYY HH:mm:ss"
- mask="__/__/____ __:__:__"
- renderInput={(params) => }
- maxDate={dayjs(until)}
- />
-
-
- dispatch({type: "SET_UNTIL", payload: date as unknown as Date})}
- onError={console.log}
- inputFormat="DD/MM/YYYY HH:mm:ss"
- mask="__/__/____ __:__:__"
- renderInput={(params) => }
- />
-
-
-
-
- Will be changed to current time for auto-refresh mode.
- dispatch({type: "RUN_QUERY_TO_NOW"})} text="Switch to now"/>
-
-
-
- ;
+ const setDuration = (dur: string, from: Date) => {
+ dispatch({type: "SET_UNTIL", payload: from});
+ setAnchorEl(null);
+ dispatch({type: "SET_DURATION", payload: dur});
+ };
+
+ const formatRange = useMemo(() => {
+ const startFormat = dayjs(dateFromSeconds(start)).format(formatDate);
+ const endFormat = dayjs(dateFromSeconds(end)).format(formatDate);
+ return {
+ start: startFormat,
+ end: endFormat
+ };
+ }, [start, end]);
+
+ const [anchorEl, setAnchorEl] = useState(null);
+ const open = Boolean(anchorEl);
+
+ return <>
+
+
+
+
+ setAnchorEl(null)}>
+
+
+
+
+ dispatch({type: "SET_FROM", payload: date as unknown as Date})}
+ onError={console.log}
+ inputFormat={formatDate}
+ mask="____-__-__ __:__:__"
+ renderInput={(params) => }
+ maxDate={dayjs(until)}
+ PopperProps={{disablePortal: true}}/>
+
+
+ dispatch({type: "SET_UNTIL", payload: date as unknown as Date})}
+ onError={console.log}
+ inputFormat={formatDate}
+ mask="____-__-__ __:__:__"
+ renderInput={(params) => }
+ PopperProps={{disablePortal: true}}/>
+
+
+
+
+
+
+ {/*setup duration*/}
+
+
+
+
+
+
+
+
+ >;
};
diff --git a/app/vmui/packages/vmui/src/components/Home/HomeLayout.tsx b/app/vmui/packages/vmui/src/components/Home/HomeLayout.tsx
index c67e3988d4..3a75562f5f 100644
--- a/app/vmui/packages/vmui/src/components/Home/HomeLayout.tsx
+++ b/app/vmui/packages/vmui/src/components/Home/HomeLayout.tsx
@@ -10,6 +10,8 @@ import QueryConfigurator from "./Configurator/Query/QueryConfigurator";
import {useFetchQuery} from "./Configurator/Query/useFetchQuery";
import JsonView from "./Views/JsonView";
import Header from "../Header/Header";
+import {DisplayTypeSwitch} from "./Configurator/DisplayTypeSwitch";
+import GraphSettings from "./Configurator/Graph/GraphSettings";
const HomeLayout: FC = () => {
@@ -20,18 +22,16 @@ const HomeLayout: FC = () => {
return (
-
-
-
-
-
+
+
+
{isLoading &&
{
}
{
- {error &&
-
- {error}
- }
- {graphData && period && (displayType === "chart") &&
- }
+