diff --git a/src/actions/errorHandler.js b/src/actions/errorHandler.js
index dc040567..2da155d8 100644
--- a/src/actions/errorHandler.js
+++ b/src/actions/errorHandler.js
@@ -1,41 +1,69 @@
-export const errorHandler = (url, error) => {
- const { request, response } = error;
-
- if (response?.statusText) {
- const status = response?.status;
- return {
- message: "API " + response.statusText + ", Please adjust API URL",
- status,
- };
- } else if (!url.includes(window.location.protocol)) {
- return {
- message: "Mixed Content Error, your View should be over same protocol as your API",
- status: 500,
- };
- } else if (request) {
- if(error.stack.includes('Network Error')) {
- return {
- message: "Invalid API URL, please adjust API URL",status:500
- }
- }
- return {
- message: "server time out",
- status: response?.status,
- };
- } else if (error.stack.includes("Invalid URL")) {
- return {
- message: "Invalid API URL, please adjust API URL",
- stauts: response?.status,
- };
- } else if (error?.response?.status === 404) {
- return {
- message: "Invalid API URL, please adjust API URL",
- status: response?.status,
- };
- } else {
- return {
- message: "something went wrong with request",
- status: response?.status,
- };
- }
-};
+export const errorHandler = (error) => {
+
+ const LABELS_URL = "/loki/api/v1/labels";
+ const QUERY_URL = "/loki/api/v1/query_range";
+
+ const { request, response } = error;
+ const url = error?.response?.request?.responseURL
+
+
+ let type = () => {
+ switch(url) {
+ case url?.includes(LABELS_URL):
+ return 'labels';
+ case url?.includes(QUERY_URL):
+ return 'query'
+ default: return 'labels'
+ }
+ }
+
+ if (response?.statusText) {
+ const status = response?.status;
+
+ return {
+ message: "API " + response.statusText + ", Please adjust API URL",
+ status,
+ type: type()
+ };
+ } else if (url && !url.includes(window.location.protocol)) {
+
+ return {
+ message: "Mixed Content Error, your View should be over same protocol as your API",
+ status: 500,
+ type : type()
+ };
+ } else if (request) {
+ if (error.stack.includes('Network Error')) {
+ return {
+ message: "Invalid API URL, please adjust API URL",
+ status: 500,
+ type: type()
+ }
+ }
+ return {
+ message: "server time out",
+ status: response?.status,
+ type: type()
+ };
+ } else if (error?.stack?.includes("Invalid URL")) {
+ return {
+ message: "Invalid API URL, please adjust API URL",
+ stauts: response?.status,
+ type: type()
+ };
+ } else if (error?.response?.status === 404) {
+ return {
+ message: "Invalid API URL, please adjust API URL",
+ status: response?.status,
+ type: type()
+ };
+ } else {
+ if (type === 'labels') return;
+
+ return {
+ message: "something went wrong with request",
+ status: response?.status,
+ type: type()
+ };
+ }
+};
diff --git a/src/actions/index.js b/src/actions/index.js
index 5fefe495..43b883f7 100644
--- a/src/actions/index.js
+++ b/src/actions/index.js
@@ -1,19 +1,19 @@
-export * from "./setStartTime";
-export * from "./setStopTime";
-export * from "./setQueryLimit";
-export * from "./setQueryStep";
-export * from "./setRangeOpen";
-export * from "./setTimeRangeLabel";
-export * from "./setApiUrl";
-export * from "./setQuery";
-export * from "./setIsSubmit";
-export * from "./setMatrixData";
-export * from "./setQueryHistory";
-export * from "./setHistoryOpen";
-export * from "./setApiError";
-export * from "./errorHandler";
-export * from "./setLabels";
-export * from "./createAlert";
-export * from "./removeAlert";
-export * from "./setFromTime";
-export * from "./setToTime";
\ No newline at end of file
+export * from "./setStartTime";
+export * from "./setStopTime";
+export * from "./setQueryLimit";
+export * from "./setQueryStep";
+export * from "./setRangeOpen";
+export * from "./setTimeRangeLabel";
+export * from "./setApiUrl";
+export * from "./setQuery";
+export * from "./setIsSubmit";
+export * from "./setMatrixData";
+export * from "./setQueryHistory";
+export * from "./setHistoryOpen";
+export * from "./setApiError";
+export * from "./errorHandler";
+export * from "./setLabels";
+export * from "./createAlert";
+export * from "./removeAlert";
+export * from "./setFromTime";
+export * from "./setToTime";
diff --git a/src/actions/loadLabelValues.js b/src/actions/loadLabelValues.js
index 486e7a03..00e8ec25 100644
--- a/src/actions/loadLabelValues.js
+++ b/src/actions/loadLabelValues.js
@@ -1,69 +1,69 @@
-import axios from "axios";
-import { errorHandler } from "./errorHandler";
-import { setApiError } from "./setApiError";
-import { setLabels } from "./setLabels";
-import setLabelValues from "./setLabelValues";
-import setLoading from "./setLoading";
-
-
-export default function loadLabelValues(label, labelList, apiUrl) {
- if (!label || (label?.length <= 0 && label.lsList.length <= 0)) {
- return () => {};
- };
-
- const url = apiUrl;
-
- const origin = window.location.origin
-
- const headers = {
- "Access-Control-Allow-Origin": origin,
- "Access-Control-Allow-Headers": ["Access-Control-Request-Headers", "Content-Type"],
- "Content-Type": "application/json",
- }
-
- const options = {
- method: "GET",
- headers: headers,
- mode: "cors",
-
- };
-
- return async (dispatch) => {
- dispatch(setLoading(true))
-
- await axios.get(`${url}/loki/api/v1/label/${label.name}/values`, options)
- ?.then(response => {
- if (response?.data?.data) {
- const values = response?.data?.data?.map?.((value) => ({
- name: value,
- selected: false,
- inverted: false
- }));
-
- const lsList = [...labelList];
- lsList.forEach((l) => {
- if (l?.name === label?.name) {
- l.values = [...values];
- }
- });
- dispatch(setLabels(lsList))
- } else if(!response) {
- dispatch(setApiError('URL NOT FOUND'))
- dispatch(setLabelValues([]))
- }
-
- dispatch(setLoading(false));
- dispatch(setApiError(''))
- dispatch(setLabelValues(response?.data?.data));
-
- }).catch(error => {
- dispatch(setLoading(false))
- const { message } = errorHandler(url, error)
- dispatch(setApiError(message || 'API NOT FOUND'))
- dispatch(setLabelValues([]))
- console.err(error)
- })
- }
-
-
-}
+import axios from "axios";
+import { errorHandler } from "./errorHandler";
+import { setApiError } from "./setApiError";
+import { setLabels } from "./setLabels";
+import setLabelValues from "./setLabelValues";
+import setLoading from "./setLoading";
+
+
+export default function loadLabelValues(label, labelList, apiUrl) {
+ if (!label || (label?.length <= 0 && label.lsList.length <= 0)) {
+ return () => {};
+ };
+
+ const url = apiUrl;
+
+ const origin = window.location.origin
+
+ const headers = {
+ "Access-Control-Allow-Origin": origin,
+ "Access-Control-Allow-Headers": ["Access-Control-Request-Headers", "Content-Type"],
+ "Content-Type": "application/json",
+ }
+
+ const options = {
+ method: "GET",
+ headers: headers,
+ mode: "cors",
+
+ };
+
+ return async (dispatch) => {
+ dispatch(setLoading(true))
+
+ await axios.get(`${url}/loki/api/v1/label/${label.name}/values`, options)
+ ?.then(response => {
+ if (response?.data?.data) {
+ const values = response?.data?.data?.map?.((value) => ({
+ name: value,
+ selected: false,
+ inverted: false
+ }));
+
+ const lsList = [...labelList];
+ lsList.forEach((l) => {
+ if (l?.name === label?.name) {
+ l.values = [...values];
+ }
+ });
+ dispatch(setLabels(lsList))
+ } else if(!response) {
+ dispatch(setApiError('URL NOT FOUND'))
+ dispatch(setLabelValues([]))
+ }
+
+ dispatch(setLoading(false));
+ dispatch(setApiError(''))
+ dispatch(setLabelValues(response?.data?.data));
+
+ }).catch(error => {
+ dispatch(setLoading(false))
+ const { message } = errorHandler(url, error,'lavelValues')
+ dispatch(setApiError(message || 'API NOT FOUND'))
+ dispatch(setLabelValues([]))
+ console.error(error)
+ })
+ }
+
+
+}
diff --git a/src/actions/LoadLabels.js b/src/actions/loadLabels.js
similarity index 79%
rename from src/actions/LoadLabels.js
rename to src/actions/loadLabels.js
index 7f5a1c1b..764f8484 100644
--- a/src/actions/LoadLabels.js
+++ b/src/actions/loadLabels.js
@@ -1,61 +1,57 @@
-import axios from "axios";
-import { setLabels } from "./setLabels";
-import setLoading from "./setLoading";
-import { setApiError } from "./setApiError";
-import { errorHandler } from "./errorHandler";
-import { setLabelsBrowserOpen } from "./setLabelsBrowserOpen";
-
-export default function loadLabels(apiUrl) {
- const origin = window.location.origin;
- const url = apiUrl;
- const headers = {
- "Access-Control-Allow-Origin": origin,
- "Access-Control-Allow-Headers": [
- "Access-Control-Request-Headers",
- "Content-Type",
- ],
- "Content-Type": "application/json",
- };
-
- const options = {
- method: "GET",
- headers: headers,
- mode: "cors",
- };
-
- return function (dispatch) {
- axios
- .get(`${url.trim()}/loki/api/v1/labels`, options)
- ?.then((response) => {
- if (response) {
- if (response?.data?.data === [])
- console.log("no labels found");
- if (response?.data?.data?.length > 0) {
- const labels = response?.data?.data
- .sort()
- .map((label) => ({
- name: label,
- selected: false,
- values: [],
- }));
- dispatch(setLabels(labels || []));
- dispatch(setApiError(""));
- }
- } else {
- dispatch(setLoading(false));
- dispatch(
- setApiError("API Not Found, Please adjust API URL")
- );
- dispatch(setLabelsBrowserOpen(true));
- dispatch(setLabels([]));
- }
- })
- .catch((error) => {
- console.log(error);
- dispatch(setLoading(false));
- const { message, status } = errorHandler(url, error);
- dispatch(setApiError(`Status: ${status}, ${message}`));
- dispatch(setLabels([]));
- });
- };
-}
+import axios from "axios";
+import { setLabels } from "./setLabels";
+import setLoading from "./setLoading";
+import { setApiError } from "./setApiError";
+
+export default function loadLabels(apiUrl) {
+ const origin = window.location.origin;
+ const url = apiUrl;
+ const headers = {
+ "Access-Control-Allow-Origin": origin,
+ "Access-Control-Allow-Headers": [
+ "Access-Control-Request-Headers",
+ "Content-Type",
+ ],
+ "Content-Type": "application/json",
+ };
+
+ const options = {
+ method: "GET",
+ headers: headers,
+ mode: "cors",
+ };
+
+ return function (dispatch) {
+ axios
+ .get(`${url.trim()}/loki/api/v1/labels`, options)
+ ?.then((response) => {
+ if (response) {
+ if (response?.data?.data === [])
+ if (response?.data?.data?.length > 0) {
+ const labels = response?.data?.data
+ .sort()
+ .map((label) => ({
+ name: label,
+ selected: false,
+ values: [],
+ }));
+ dispatch(setLabels(labels || []));
+
+ dispatch(setApiError(""));
+ }
+ } else {
+ dispatch(setLoading(false));
+ dispatch(
+ setApiError("")
+ );
+ dispatch(setLabels([]));
+
+ }
+ })
+ .catch((error) => {
+ console.log(error);
+ dispatch(setLoading(false));
+ dispatch(setLabels([]));
+ });
+ };
+}
diff --git a/src/actions/loadLogs.js b/src/actions/loadLogs.js
index fb8efc37..dda20106 100644
--- a/src/actions/loadLogs.js
+++ b/src/actions/loadLogs.js
@@ -1,135 +1,134 @@
-import axios from "axios";
-import setLogs from "./setLogs";
-import setLoading from "./setLoading";
-import store from "../store/store";
-import setMatrixData from "./setMatrixData";
-import { nanoid } from "nanoid";
-import { setStartTime, setStopTime } from "./";
-import { findRangeByLabel } from "../components/StatusBar/components/daterangepicker/utils";
-
-export default function loadLogs() {
- const localStore = store.getState();
- const {
- query,
- limit,
- step,
- apiUrl,
- label: rangeLabel,
- from,
- to,
- } = localStore;
- let { start: startTs, stop: stopTs } = localStore;
-
- function getTimeParsed(time) {
- return time.getTime() + "000000";
- }
-
- const parsedStart = getTimeParsed(startTs);
- const parsedStop = getTimeParsed(stopTs);
-
- const parsedTime =
- "&start=" + (from || parsedStart) + "&end=" + (to || parsedStop);
-
- if (findRangeByLabel(rangeLabel)) {
- ({ dateStart: startTs, dateEnd: stopTs } =
- findRangeByLabel(rangeLabel));
- }
-
- store.dispatch(setStartTime(startTs));
- store.dispatch(setStopTime(stopTs));
-
- const origin = window.location.origin;
- const url = apiUrl;
-
- const queryStep = `&step=${step || 120}`;
-
- const encodedQuery = `${encodeURIComponent(query)}`;
-
- const getUrl = `${url}/loki/api/v1/query_range?query=${encodedQuery}&limit=${limit}${parsedTime}${queryStep}`;
-
- const options = {
- method: "GET",
- headers: {
- "Content-Type": "application/javascript",
- "Access-Control-Allow-Origin": origin,
- },
- };
-
- const fromNanoSec = (ts) => parseInt(ts / 1000000);
- const toMiliseC = (ts) => parseInt(ts * 1000);
- const getTimestamp = (type) => (ts) =>
- type === "streams"
- ? fromNanoSec(ts)
- : type === "matrix"
- ? toMiliseC(ts)
- : ts;
- const mapStreams = (streams, messages, type) => {
- streams.forEach((stream) => {
- stream.values.forEach((log, i) => {
- let [ts, text] = log;
- messages.push({
- type,
- timestamp: getTimestamp(type)(ts),
- text,
- tags:
- type === "streams"
- ? stream.stream
- : type === "matrix"
- ? stream.metric
- : {},
- showTs: true,
- showLabels: false,
- id: nanoid(),
- });
- });
- });
- };
-
- //const mapMatrix
- return async function (dispatch) {
- dispatch(setLoading(true));
- dispatch(setLogs([]));
- dispatch(setMatrixData([]));
-
- await axios
- .get(getUrl, options)
- ?.then((response) => {
- if (response?.data?.data) {
- let messages = [];
- const result = response?.data?.data?.result; // array
- const type = response?.data?.data?.resultType;
- if (type === "streams") {
- mapStreams(result, messages, type);
- dispatch(setMatrixData([]));
- const messSorted = messages?.sort((a, b) =>
- a.timestamp < b.timestamp ? 1 : -1
- );
- if (messSorted) {
- dispatch(setLogs(messSorted || []));
-
- dispatch(setLoading(false));
- }
- }
-
- if (type === "matrix") {
- const idResult =
- result?.map((m) => ({ ...m, id: nanoid() })) || [];
- dispatch(setMatrixData(idResult || []));
- dispatch(setLoading(false));
- }
- dispatch(setLoading(false));
- } else {
- dispatch(setLogs([]));
- dispatch(setMatrixData([]));
- dispatch(setLoading(false));
- }
- dispatch(setLoading(false));
- })
- .catch((error) => {
- dispatch(setLogs([]));
- dispatch(setMatrixData([]));
- dispatch(setLoading(false));
- console.log(error);
- });
- };
-}
+import axios from "axios";
+import setLogs from "./setLogs";
+import setLoading from "./setLoading";
+import store from "../store/store";
+import setMatrixData from "./setMatrixData";
+import { nanoid } from "nanoid";
+import { setStartTime, setStopTime } from "./";
+import { findRangeByLabel } from "../components/StatusBar/components/daterangepicker/utils";
+
+
+export default function loadLogs() {
+ const localStore = store.getState();
+ const {
+ query,
+ limit,
+ step,
+ apiUrl,
+ label: rangeLabel,
+ from,
+ to,
+ } = localStore;
+ let { start: startTs, stop: stopTs } = localStore;
+
+ function getTimeParsed(time) {
+ return time.getTime() + "000000";
+ }
+
+ const parsedStart = getTimeParsed(startTs);
+ const parsedStop = getTimeParsed(stopTs);
+
+ const parsedTime = "&start=" + (from || parsedStart) + "&end=" + (to || parsedStop);
+
+ if (findRangeByLabel(rangeLabel)) {
+ ({ dateStart: startTs, dateEnd: stopTs } =
+ findRangeByLabel(rangeLabel));
+ }
+
+ store.dispatch(setStartTime(startTs));
+ store.dispatch(setStopTime(stopTs));
+ const origin = window.location.origin;
+ const url = apiUrl;
+ const queryStep = `&step=${step || 120}`;
+ const encodedQuery = `${encodeURIComponent(query)}`;
+ const getUrl = `${url}/loki/api/v1/query_range?query=${encodedQuery}&limit=${limit}${parsedTime}${queryStep}`;
+
+ const options = {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/javascript",
+ "Access-Control-Allow-Origin": origin,
+ },
+ };
+
+ const fromNanoSec = (ts) => parseInt(ts / 1000000);
+ const toMiliseC = (ts) => parseInt(ts * 1000);
+ const getTimestamp = (type) => (ts) =>
+ type === "streams"
+ ? fromNanoSec(ts)
+ : type === "matrix"
+ ? toMiliseC(ts)
+ : ts;
+ const mapStreams = (streams, messages, type) => {
+ streams.forEach((stream) => {
+ stream.values.forEach((log, i) => {
+ let [ts, text] = log;
+ messages.push({
+ type,
+ timestamp: getTimestamp(type)(ts),
+ text,
+ tags:
+ type === "streams"
+ ? stream.stream
+ : type === "matrix"
+ ? stream.metric
+ : {},
+ showTs: true,
+ showLabels: false,
+ id: nanoid(),
+ });
+ });
+ });
+ };
+
+ //const mapMatrix
+ return async function (dispatch) {
+ dispatch(setLoading(true));
+ dispatch(setLogs([]));
+ dispatch(setMatrixData([]));
+
+ await axios
+ .get(getUrl, options)
+ ?.then((response) => {
+ if (response?.data?.data) {
+ let messages = [];
+ const result = response?.data?.data?.result; // array
+ const type = response?.data?.data?.resultType;
+ if (type === "streams") {
+ mapStreams(result, messages, type);
+ dispatch(setMatrixData([]));
+ const messSorted = messages?.sort((a, b) =>
+ a.timestamp < b.timestamp ? 1 : -1
+ );
+ if (messSorted) {
+ dispatch(setLogs(messSorted || []));
+
+ dispatch(setLoading(false));
+ }
+ }
+
+ if (type === "matrix") {
+ const idResult =
+ result?.map((m) => ({ ...m, id: nanoid() })) || [];
+ dispatch(setMatrixData(idResult || []));
+ dispatch(setLoading(false));
+ }
+ dispatch(setLoading(false));
+ } else {
+ dispatch(setLogs([]));
+ dispatch(setMatrixData([]));
+ dispatch(setLoading(false));
+ }
+ dispatch(setLoading(false));
+ })
+ .catch((error) => {
+
+ dispatch(setLogs([]));
+ dispatch(setMatrixData([]));
+
+ dispatch(setLoading(false));
+
+
+ });
+ };
+}
diff --git a/src/actions/setApiWarning.js b/src/actions/setApiWarning.js
new file mode 100644
index 00000000..d82f2361
--- /dev/null
+++ b/src/actions/setApiWarning.js
@@ -0,0 +1,8 @@
+export default function setApiWarning(apiWarning){
+ return function(dispatch){
+ dispatch({
+ type:'SET_API_WARNING',
+ apiWarning
+ })
+ }
+}
\ No newline at end of file
diff --git a/src/components/DataView/ValueTags.js b/src/components/DataView/ValueTags.js
index 3b1d871e..d79a2608 100644
--- a/src/components/DataView/ValueTags.js
+++ b/src/components/DataView/ValueTags.js
@@ -29,7 +29,7 @@ export default function ValueTags({ tags }) {
const updatedLabels = store.getState().labels;
const updatedLabel = updatedLabels.find(
(label) => label.name === key
- );
+ );
const labelValue = updatedLabel.values.find(
(tag) => tag.name === value
);
diff --git a/src/components/DataView/styled/index.js b/src/components/DataView/styled/index.js
index 61b37034..7ed2ed64 100644
--- a/src/components/DataView/styled/index.js
+++ b/src/components/DataView/styled/index.js
@@ -1,85 +1,85 @@
-import styled from "@emotion/styled";
-import { THEME_COLORS } from '../theme/theme';
-import { CircularProgress } from "@mui/material";
-import darkTheme from "../../../theme/dark";
-
-const theme = darkTheme;
-
-export const DataViewStyled = styled.div`
- background: ${theme.viewBg};
- margin: 6px 8px;
- overflow-y: scroll;
- overflow-x: hidden;
- position: relative;
- flex: 1;
- border-radius: 3px;
- //padding: 0.5rem;
-
- &::-webkit-scrollbar {
- width: 10px;
- }
-
- &::-webkit-scrollbar-thumb {
- border-radius: 10px;
- background: ${theme.scrollbarThumb};
- }
-`;
-
-export const EmptyViewContainer = styled.div`
- color: white;
- display: flex;
- align-items: center;
- justify-content: center;
- width: 100%;
- height: 175px;
- font-size: 1em;
- color: ${theme.textOff};
- text-align: center;
-`;
-
-export const DataViewCont = styled.div`
- display: flex;
- min-height: min-content;
- flex-direction: column;
-`;
-
-export const LogRow = styled.div`
- padding: 0.3rem;
- color: white;
- font-size: 13px;
- cursor: pointer;
- margin-bottom: 4px;
- padding-left: 0.5rem;
- margin-left: 0.25rem;
- transition: 0.2s all;
- &:hover {
- background: black;
- }
-
- p {
- display: inline-block;
- }
-
- border-left: 4px solid ${(props) => props.rowColor};
-`;
-
-export const RowLogContent = styled.span`
- font-size: 0.95em;
- font-family: monospace;
- color: ${theme.textWhite};
- line-height: 1.5;
-`;
-
-export const RowTimestamp = styled.span`
- position: relative;
- color: ${theme.textColor};
- margin-right: 0.25rem;
-`;
-
-export const Loader = styled(CircularProgress)`
- position: absolute;
- top: 50px;
- left: 0;
- right: 0;
- margin: auto;
-`;
+import styled from "@emotion/styled";
+import { THEME_COLORS } from '../theme/theme';
+import { CircularProgress } from "@mui/material";
+import darkTheme from "../../../theme/dark";
+
+const theme = darkTheme;
+
+export const DataViewStyled = styled.div`
+ background: ${theme.viewBg};
+ margin: 6px 8px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ position: relative;
+ flex: 1;
+ border-radius: 3px;
+ //padding: 0.5rem;
+
+ &::-webkit-scrollbar {
+ width: 10px;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ border-radius: 10px;
+ background: ${theme.scrollbarThumb};
+ }
+`;
+
+export const EmptyViewContainer = styled.div`
+ color: white;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 175px;
+ font-size: 1em;
+ color: ${theme.textOff};
+ text-align: center;
+`;
+
+export const DataViewCont = styled.div`
+ display: flex;
+ min-height: min-content;
+ flex-direction: column;
+`;
+
+export const LogRow = styled.div`
+ padding: 0.3rem;
+ color: white;
+ font-size: 12px;
+ cursor: pointer;
+ margin-bottom: 4px;
+ padding-left: 0.5rem;
+ margin-left: 0.25rem;
+ transition: 0.2s all;
+ &:hover {
+ background: black;
+ }
+
+ p {
+ display: inline-block;
+ }
+
+ border-left: 4px solid ${(props) => props.rowColor};
+`;
+
+export const RowLogContent = styled.span`
+ font-size: 12px;
+ font-family: monospace;
+ color: ${theme.textWhite};
+ line-height: 1.5;
+`;
+
+export const RowTimestamp = styled.span`
+ position: relative;
+ color: ${theme.textColor};
+ margin-right: 0.25rem;
+`;
+
+export const Loader = styled(CircularProgress)`
+ position: absolute;
+ top: 50px;
+ left: 0;
+ right: 0;
+ margin: auto;
+`;
diff --git a/src/components/LabelBrowser/QueryBar.js b/src/components/LabelBrowser/QueryBar.js
index c6f34596..51242be7 100644
--- a/src/components/LabelBrowser/QueryBar.js
+++ b/src/components/LabelBrowser/QueryBar.js
@@ -1,179 +1,177 @@
-import React, { useState, useEffect } from "react";
-import { useSelector, useDispatch } from "react-redux";
-import { setIsSubmit, setQuery } from "../../actions";
-import loadLogs from "../../actions/loadLogs";
-import setLoading from "../../actions/setLoading";
-import { setLabelsBrowserOpen } from "../../actions/setLabelsBrowserOpen";
-import localService from "../../services/localService";
-import setQueryHistory from "../../actions/setQueryHistory";
-
-import setHistoryOpen from "../../actions/setHistoryOpen";
-import localUrl from "../../services/localUrl";
-import setLinksHistory from "../../actions/setLinksHistory";
-import QueryEditor from "../../plugins/queryeditor";
-
-import loadLabels from "../../actions/LoadLabels";
-import { decodeQuery } from "../../helpers/UpdateStateFromQueryParams";
-import { css } from "@emotion/css";
-import { MobileTopQueryMenu, QueryBarContainer } from "./components/styled";
-import HistoryButton from "./components/HistoryButton/HistoryButton";
-import ShowLabelsButton from "./components/ShowLabelsButton/ShowLabelsButton";
-import ShowLogsButton from "./components/ShowLogsButton/ShowLogsButton";
-import queryInit from "./helpers/queryInit";
-import onQueryValid from "./helpers/onQueryValid";
-import debugLog from "./helpers/debugLog";
-
-export const QueryBar = () => {
- const dispatch = useDispatch();
- const historyService = localService().historyStore();
- const labelsBrowserOpen = useSelector((store) => store.labelsBrowserOpen);
- const debug = useSelector((store) => store.debugMode);
- const query = useSelector((store) => store.query);
- const apiUrl = useSelector((store) => store.apiUrl);
- const isSubmit = useSelector((store) => store.isSubmit);
- const historyOpen = useSelector((store) => store.historyOpen);
- const isEmbed = useSelector( ( store ) => store.isEmbed)
-
- const [queryInput, setQueryInput] = useState(query);
- const [queryValid, setQueryValid] = useState(false);
- const [queryValue, setQueryValue] = useState(queryInit(query));
-
- const queryHistory = useSelector((store) => store.queryHistory);
- const saveUrl = localUrl();
- useEffect(() => {
- const dLog = debugLog(query);
- debug && dLog.logicQueryBar();
-
- if (onQueryValid(query && isSubmit === "true")) {
- debug && dLog.queryBarDispatch();
-
- dispatch(setLoading(true));
- dispatch(loadLogs());
-
- setTimeout(() => {
- dispatch(setIsSubmit(false));
- }, 200);
- } else if (!onQueryValid(query) && isSubmit === "true") {
-
- dispatch(setIsSubmit(false));
- }
- }, []);
-
- useEffect(() => {
- setQueryInput(query);
- setQueryValue([{ children: [{ text: query }] }]);
- setQueryValid(onQueryValid(query));
- }, [query]);
-
- const onValueDisplay = (e) => {
- e.preventDefault();
- const isOpen = labelsBrowserOpen ? false : true;
- if (isOpen) dispatch(loadLabels(apiUrl));
- dispatch(setLabelsBrowserOpen(isOpen));
- };
-
- function handleQueryChange(e) {
- setQueryValue(e);
-
- const multiline = e.map((text) => text.children[0].text).join("\n");
- dispatch(setQuery(multiline));
- }
-
- const handleInputKeyDown = (e) => {
- if (e.code === "Enter" && e.ctrlKey) {
- dispatch(setLoading(true));
- onSubmit(e);
- }
- };
-
- const onSubmit = (e) => {
- e.preventDefault();
-
- dispatch(setQuery(queryInput));
-
- if (onQueryValid(queryInput)) {
- try {
- const historyUpdated = historyService.add({
- data: queryInput,
- url: window.location.hash,
- });
- dispatch(setQueryHistory(historyUpdated));
- dispatch(setLabelsBrowserOpen(false));
- decodeQuery(query, apiUrl);
- dispatch(setLoading(true));
- dispatch(loadLogs());
- const storedUrl = saveUrl.add({
- data: window.location.href,
- description: "From Query Submit",
- });
- dispatch(setLinksHistory(storedUrl));
- } catch (e) {
- console.log(e);
- }
- } else {
- console.log("Please make a log query", query);
- }
- };
- function handleHistoryClick(e) {
- dispatch(setHistoryOpen(!historyOpen));
- }
- return (
- !isEmbed && (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-
- );
-};
+import React, { useState, useEffect } from "react";
+import { useSelector, useDispatch } from "react-redux";
+import { setQuery } from "../../actions";
+import loadLogs from "../../actions/loadLogs";
+import setLoading from "../../actions/setLoading";
+import { setLabelsBrowserOpen } from "../../actions/setLabelsBrowserOpen";
+import localService from "../../services/localService";
+import setQueryHistory from "../../actions/setQueryHistory";
+
+import setHistoryOpen from "../../actions/setHistoryOpen";
+import localUrl from "../../services/localUrl";
+import setLinksHistory from "../../actions/setLinksHistory";
+import QueryEditor from "../../plugins/queryeditor";
+
+import { decodeQuery } from "../../helpers/UpdateStateFromQueryParams";
+import { css } from "@emotion/css";
+import { MobileTopQueryMenu, QueryBarContainer } from "./components/styled";
+import HistoryButton from "./components/HistoryButton/HistoryButton";
+import ShowLabelsButton from "./components/ShowLabelsButton/ShowLabelsButton";
+import ShowLogsButton from "./components/ShowLogsButton/ShowLogsButton";
+import queryInit from "./helpers/queryInit";
+import onQueryValid from "./helpers/onQueryValid";
+import debugLog from "./helpers/debugLog";
+import { sendLabels } from "../../hooks/useLabels";
+import loadLabels from "../../actions/loadLabels";
+
+export const QueryBar = () => {
+ const dispatch = useDispatch();
+ const historyService = localService().historyStore();
+ const labelsBrowserOpen = useSelector((store) => store.labelsBrowserOpen);
+ const debug = useSelector((store) => store.debugMode);
+ const query = useSelector((store) => store.query);
+ const apiUrl = useSelector((store) => store.apiUrl);
+ const historyOpen = useSelector((store) => store.historyOpen);
+ const isEmbed = useSelector((store) => store.isEmbed)
+ const [queryInput, setQueryInput] = useState(query);
+ const [queryValid, setQueryValid] = useState(false);
+ const [queryValue, setQueryValue] = useState(queryInit(query));
+ const labels = useSelector(store => store.labels)
+ const queryHistory = useSelector((store) => store.queryHistory);
+ const saveUrl = localUrl();
+ useEffect(() => {
+ const dLog = debugLog(query);
+ debug && dLog.logicQueryBar();
+ const labels = sendLabels(apiUrl)
+ if (isEmbed) dispatch(loadLogs())
+ if (query.length > 0) {
+ debug && dLog.queryBarDispatch();
+ dispatch(setLoading(true));
+ return labels.then(data => {
+ decodeQuery(query, apiUrl, data)
+
+ })
+ }
+
+ }, []);
+
+ useEffect(() => {
+ setQueryInput(query);
+ setQueryValue([{ children: [{ text: query }] }]);
+ setQueryValid(onQueryValid(query));
+ }, [query]);
+
+ const onValueDisplay = (e) => {
+ e.preventDefault();
+ const isOpen = labelsBrowserOpen ? false : true;
+ if (isOpen) {
+ dispatch(loadLabels(apiUrl));
+
+ }
+
+ dispatch(setLabelsBrowserOpen(isOpen));
+ };
+
+ function handleQueryChange(e) {
+ setQueryValue(e);
+
+ const multiline = e.map((text) => text.children[0].text).join("\n");
+ dispatch(setQuery(multiline));
+ }
+
+ const handleInputKeyDown = (e) => {
+ if (e.code === "Enter" && e.ctrlKey) {
+ dispatch(setLoading(true));
+ onSubmit(e);
+ }
+ };
+
+ const onSubmit = (e) => {
+ e.preventDefault();
+ dispatch(setQuery(queryInput));
+ if (onQueryValid(queryInput)) {
+ try {
+ const historyUpdated = historyService.add({
+ data: queryInput,
+ url: window.location.hash,
+ });
+ dispatch(setQueryHistory(historyUpdated));
+ dispatch(setLabelsBrowserOpen(false));
+ decodeQuery(queryInput, apiUrl, labels)
+ dispatch(setLoading(true));
+ dispatch(loadLogs());
+ const storedUrl = saveUrl.add({
+ data: window.location.href,
+ description: "From Query Submit",
+ });
+ dispatch(setLinksHistory(storedUrl));
+ } catch (e) {
+ console.log(e);
+ }
+ } else {
+ console.log("Please make a log query", query);
+ }
+ };
+ function handleHistoryClick(e) {
+ dispatch(setHistoryOpen(!historyOpen));
+ }
+ return (
+ !isEmbed && (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+
+ );
+};
diff --git a/src/components/LabelBrowser/ValuesList.js b/src/components/LabelBrowser/ValuesList.js
index 03842023..9b6f9bbf 100644
--- a/src/components/LabelBrowser/ValuesList.js
+++ b/src/components/LabelBrowser/ValuesList.js
@@ -1,222 +1,227 @@
-import React, { useState, useEffect } from "react";
-import { Legend } from "./Legend";
-import { useSelector, useDispatch } from "react-redux";
-import RefreshIcon from "@mui/icons-material/Refresh";
-import loadLabels from "../../actions/LoadLabels";
-import { queryBuilder } from "./helpers/querybuilder";
-import { setQuery } from "../../actions";
-import loadLabelValues from "../../actions/loadLabelValues";
-
-import Tooltip from "@mui/material/Tooltip";
-import store from "../../store/store";
-import styled from "@emotion/styled";
-
-const ErrorContainer = styled.div`
- padding: 20px;
- display: flex;
- align-items: center;
- justify-content: center;
-`;
-
-const LabelErrorStyled = styled.div`
- padding: 10px;
- color: orangered;
- border: 1px solid orangered;
- border-radius: 3px;
- font-size: 1em;
-`;
-
-export const LabelsFetchError = () => {
- const labelError = useSelector((store) => store.apiErrors);
-
- return (
-
- {labelError !== "" && (
-
- {labelError}
-
- )}
-
- );
-};
-
-export const ValuesList = (props) => {
- const [labelsSelected, setLabelsSelected] = useState([]);
- const labels = useSelector((state) => {
- const selected = state.labels.filter((f) => f.selected);
- if (JSON.stringify(selected) !== JSON.stringify(labelsSelected)) {
- setLabelsSelected(selected);
- }
- return state.labels;
- });
-
- const [labelList, setLabelList] = useState(labels);
-
- const dispatch = useDispatch();
- const debug = useSelector((store) => store.debug);
- const apiUrl = useSelector((store) => store.apiUrl);
- //if(debug) console.log('🚧 LOGIC/LabelBrowser/ValuesList', apiUrl)
- const labelsBrowserOpen = useSelector((store) => store.labelsBrowserOpen);
-
- const CLEAR = "clear";
-
- useEffect(() => {
- dispatch(loadLabels(apiUrl));
- // setLabelList(labels)
- }, [apiUrl]);
-
- useEffect(() => {
- setLabelList(labels); // LABELS
- }, [labels]);
-
- const handleRefresh = (e) => {
- e.preventDefault();
- dispatch(loadLabels(apiUrl));
- };
-
- const onLabelOpen = (e, value) => {
- e.preventDefault();
- value.selected = !value.selected;
- // setLabel(value);
- const selected = labelList.filter((f) => f.selected);
- setLabelsSelected(selected);
-
- // setFilteredPlaceholder(value);
-
- const query = queryBuilder(labelList);
- dispatch(setQuery(query));
-
- //this.setState({ ...this.state, query });
-
- dispatch(loadLabelValues(value, labelList, apiUrl));
- // loads label values into labelList
- };
-
- const onLabelValueClick = (e, value) => {
- e.preventDefault();
- value.selected = !value.selected;
- value.inverted = false;
- onLabelValueChange();
- };
-
- const selectedList = () => {
- return labelsSelected.length > 0;
- };
- const onLabelValueChange = () => {
- const query = queryBuilder(labels);
- dispatch(setQuery(query));
- };
-
- const styleValue = (value) => {
- if (value.selected) {
- return {
- borderColor: "#11abab",
- color: "#11abab",
- };
- } else return {};
- };
- return (
- labelsBrowserOpen && (
-
-
- {labelList.length > 0 ? (
-
-
-
-
-
- {labelList &&
- labelList?.map((value, key) => (
-
- onLabelOpen(e, value)
- }
- >
- {value.name}
-
- ))}
-
-
- ) : (
-
- )}
-
- {selectedList() && (
-
-
- {labelsSelected.map((labelSelected, skey) => (
-
-
-
- {labelSelected.name} (
- {labelSelected.values.length})
-
-
- onLabelOpen(
- e,
- labelSelected
- )
- }
- >
- {CLEAR}
-
-
-
- {labelSelected?.values?.map(
- (value, key) => (
-
-
- onLabelValueClick(
- e,
- value
- )
- }
- >
- {value.name}
-
-
- )
- )}
-
-
- ))}
-
-
- )}
-
-
- )
- );
-};
+import React, { useState, useEffect } from "react";
+import { Legend } from "./Legend";
+import { useSelector, useDispatch } from "react-redux";
+import RefreshIcon from "@mui/icons-material/Refresh";
+
+import { queryBuilder } from "./helpers/querybuilder";
+import { setQuery } from "../../actions";
+import loadLabelValues from "../../actions/loadLabelValues";
+
+import Tooltip from "@mui/material/Tooltip";
+import styled from "@emotion/styled";
+import loadLabels from "../../actions/loadLabels";
+
+const ErrorContainer = styled.div`
+ padding: 20px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+`;
+
+const LabelErrorStyled = styled.div`
+ padding: 10px;
+ color: orangered;
+ border: 1px solid orangered;
+ border-radius: 3px;
+ font-size: 1em;
+`;
+
+export const LabelsFetchError = () => {
+ const labelError = useSelector((store) => store.apiErrors);
+
+ return (
+
+ {labelError !== "" && (
+
+ {labelError}
+
+ )}
+
+ );
+};
+
+export const ValuesList = (props) => {
+ const [labelsSelected, setLabelsSelected] = useState([]);
+ const labels = useSelector((state) => {
+ const selected = state.labels.filter((f) => f.selected);
+ if (JSON.stringify(selected) !== JSON.stringify(labelsSelected)) {
+ setLabelsSelected(selected);
+ }
+ return state.labels;
+ });
+
+ const [labelList, setLabelList] = useState(labels);
+
+ const dispatch = useDispatch();
+ const debug = useSelector((store) => store.debugMode);
+ const apiUrl = useSelector((store) => store.apiUrl);
+ if (debug) console.log('🚧 LOGIC/LabelBrowser/ValuesList', apiUrl)
+ const labelsBrowserOpen = useSelector((store) => store.labelsBrowserOpen);
+ const CLEAR = "clear";
+ useEffect(() => {
+ dispatch(loadLabels(apiUrl));
+ }, [apiUrl]);
+
+ useEffect(() => {
+ setLabelList(labels); // LABELS
+ }, [labels]);
+
+ const handleRefresh = (e) => {
+ e.preventDefault();
+ dispatch(loadLabels(apiUrl));
+ };
+
+ const onLabelOpen = (e, value) => {
+ e.preventDefault();
+ value.selected = !value.selected;
+ const selected = labelList.filter((f) => f.selected);
+ setLabelsSelected(selected);
+
+ const query = queryBuilder(labelList);
+ dispatch(setQuery(query));
+
+ //this.setState({ ...this.state, query });
+
+ dispatch(loadLabelValues(value, labelList, apiUrl));
+ // loads label values into labelList
+ };
+
+ const onLabelValueClick = (e, value) => {
+ e.preventDefault();
+ value.selected = !value.selected;
+ value.inverted = false;
+ onLabelValueChange();
+ };
+
+ const selectedList = () => {
+ return labelsSelected.length > 0;
+ };
+ const onLabelValueChange = () => {
+ const query = queryBuilder(labels);
+ dispatch(setQuery(query));
+ };
+
+ const styleValue = (value) => {
+ if (value.selected) {
+ return {
+ borderColor: "#11abab",
+ color: "#11abab",
+ };
+ } else return {};
+ };
+ const isString = (value) => {
+ return typeof value === 'string'
+ }
+ return (
+ labelsBrowserOpen && (
+
+
+ {labelList.length > 0 ? (
+
+
+
+
+
+ {labelList &&
+ labelList?.map((value, key) => (
+
+ onLabelOpen(e, value)
+ }
+ >
+ {value.name}
+
+ ))}
+
+
+ ) : (
+
+ )}
+
+ {selectedList() && (
+
+
+ {labelsSelected.map((labelSelected, skey) => (
+
+
+
+
+ {labelSelected.name} (
+ {labelSelected.values.length})
+
+
+ onLabelOpen(
+ e,
+ labelSelected
+ )
+ }
+ >
+ {CLEAR}
+
+
+
+
+ {labelSelected?.values?.map(
+ (value, key) => (
+
+ isString(value.name) ? (
+
+
+
+ onLabelValueClick(
+ e,
+ value
+ )
+ }
+ >
+
+ {value.name}
+
+
+ ) : (unknown)
+
+ )
+ )}
+
+
+ ))}
+
+
+ )}
+
+
+ )
+ );
+};
diff --git a/src/components/LabelBrowser/components/ShowLabelsButton/ShowLabelsButton.js b/src/components/LabelBrowser/components/ShowLabelsButton/ShowLabelsButton.js
index e4d3a03a..7851497f 100644
--- a/src/components/LabelBrowser/components/ShowLabelsButton/ShowLabelsButton.js
+++ b/src/components/LabelBrowser/components/ShowLabelsButton/ShowLabelsButton.js
@@ -1,24 +1,30 @@
-import { ShowLabelsBtn } from "../styled";
-import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
-import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight";
-
-
-
-export default function ShowLabelsButton({ onValueDisplay, labelsBrowserOpen, isMobile }) {
- const LOG_BROWSER = "Labels";
-
- return (
-
- {labelsBrowserOpen ? (
-
- ) : (
-
- )}{" "}
- {LOG_BROWSER}
-
- );
-}
\ No newline at end of file
+import { ShowLabelsBtn } from "../styled";
+import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
+import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight";
+import { useSelector } from "react-redux";
+
+export default function ShowLabelsButton({ onValueDisplay, labelsBrowserOpen, isMobile }) {
+
+ const LOG_BROWSER = "Labels";
+ const labels = useSelector(store => store.labels)
+
+ return (
+
+ 0 ? 'Show / Hide Labels' : 'Labels Not Available'}
+ onClick={onValueDisplay}
+ browserActive={labelsBrowserOpen}
+ isMobile={isMobile}
+
+
+ >
+ {labelsBrowserOpen ? (
+
+ ) : (
+
+ )}{" "}
+ {LOG_BROWSER}
+
+
+ );
+}
diff --git a/src/components/LabelBrowser/components/styled/index.js b/src/components/LabelBrowser/components/styled/index.js
index 78d4d5ce..c9218a7f 100644
--- a/src/components/LabelBrowser/components/styled/index.js
+++ b/src/components/LabelBrowser/components/styled/index.js
@@ -1,80 +1,87 @@
-import styled from "@emotion/styled";
-
-import HistoryIcon from "@mui/icons-material/History";
-import darkTheme from "../../../../theme/dark";
-import { BtnSmall } from "../../../../theme/styles/Button";
-
-// get theme from main state
-
-const theme = darkTheme;
-
-export const HistoryIconStyled = styled(HistoryIcon)`
- color: ${(props) => props.color};
-`;
-export const HistoryButtonStyled = styled(BtnSmall)`
- background: none;
- color: ${theme.buttonText};
- margin-left: 5px;
- background: ${theme.buttonHover};
- span {
- margin-left: 5px;
- }
- @media screen and (max-width: 864px) {
- display: ${(props) => (props.isMobile ? "flex" : "none")};
- }
-`;
-
-export const ShowLabelsBtn = styled(BtnSmall)`
- background: ${(props) =>
- props.browserActive ? theme.buttonDefault : theme.buttonHover};
- text-overflow: ellipsis;
- transition: 0.25s all;
- justify-content: flex-start;
- color: ${theme.buttonText};
- &:hover {
- background: ${theme.buttonHover};
- }
- @media screen and (max-width: 864px) {
- display: ${(props) => (props.isMobile ? "flex" : "none")};
-
- margin: 0;
- }
-`;
-
-export const QueryBarContainer = styled.div`
- display: flex;
- padding: 3px 6px;
- margin: 5px 0px;
- margin-left: 0px;
- background: ${theme.widgetContainer};
- flex-wrap: wrap;
- border-radius: 3px;
-`;
-export const ShowLogsBtn = styled(BtnSmall)`
- background: ${theme.primaryDark};
- color: ${theme.buttonText};
- margin-left: 5px;
- transition: 0.25s all;
- justify-content: center;
- &:hover {
- background: ${theme.primaryLight};
- }
- &:disabled {
- background: ${theme.buttonDefault};
- cursor: not-allowed;
- }
- @media screen and (max-width: 864px) {
- display: ${(props) => (props.isMobile ? "flex" : "none")};
-
- margin: 0;
- }
-`;
-
-export const MobileTopQueryMenu = styled.div`
- display: none;
- @media screen and (max-width: 864px) {
- display: flex;
- justify-content: space-between;
- margin: 10px;
- }
-`;
+import styled from "@emotion/styled";
+
+import HistoryIcon from "@mui/icons-material/History";
+import darkTheme from "../../../../theme/dark";
+import { BtnSmall } from "../../../../theme/styles/Button";
+
+// get theme from main state
+
+const theme = darkTheme;
+
+export const HistoryIconStyled = styled(HistoryIcon)`
+ color: ${(props) => props.color};
+ height:18px;
+ width:18px;
+`;
+export const HistoryButtonStyled = styled(BtnSmall)`
+ background: none;
+ color: ${theme.buttonText};
+ margin-left: 5px;
+ background: ${theme.buttonHover};
+ span {
+ margin-left: 5px;
+ }
+ @media screen and (max-width: 864px) {
+ display: ${(props) => (props.isMobile ? "flex" : "none")};
+ }
+`;
+
+export const ShowLabelsBtn = styled(BtnSmall)`
+ background: ${(props) =>
+ props.browserActive ? theme.buttonDefault : theme.buttonHover};
+ text-overflow: ellipsis;
+ transition: 0.25s all;
+ justify-content: flex-start;
+ color: ${theme.buttonText};
+ &:hover {
+ background: ${theme.buttonHover};
+ }
+ &:disabled {
+ cursor:auto;
+ color:${theme.buttonDefault};
+ background:${theme.buttonInactive};
+ }
+ @media screen and (max-width: 864px) {
+ display: ${(props) => (props.isMobile ? "flex" : "none")};
+
+ margin: 0;
+ }
+`;
+
+export const QueryBarContainer = styled.div`
+ display: flex;
+ padding: 3px 6px;
+ margin: 5px 0px;
+ margin-left: 0px;
+ background: ${theme.widgetContainer};
+ flex-wrap: wrap;
+ border-radius: 3px;
+`;
+export const ShowLogsBtn = styled(BtnSmall)`
+ background: ${theme.primaryDark};
+ color: ${theme.buttonText};
+ margin-left: 10px;
+ transition: 0.25s all;
+ justify-content: center;
+ &:hover {
+ background: ${theme.primaryLight};
+ }
+ &:disabled {
+ background: ${theme.buttonDefault};
+ cursor: not-allowed;
+ }
+ @media screen and (max-width: 864px) {
+ display: ${(props) => (props.isMobile ? "flex" : "none")};
+
+ margin: 0;
+ }
+`;
+
+export const MobileTopQueryMenu = styled.div`
+ display: none;
+ @media screen and (max-width: 864px) {
+ display: flex;
+ justify-content: space-between;
+ margin: 10px;
+ }
+`;
diff --git a/src/components/LabelBrowser/helpers/querybuilder.js b/src/components/LabelBrowser/helpers/querybuilder.js
index 5af1c501..9e2a4e98 100644
--- a/src/components/LabelBrowser/helpers/querybuilder.js
+++ b/src/components/LabelBrowser/helpers/querybuilder.js
@@ -1,38 +1,39 @@
-import { setQuery } from "../../../actions";
-import store from "../../../store/store";
-
-export function queryBuilder(labels) {
- const actualQuery = store.getState().query
- const preTags = actualQuery.split("{")[0]
- const postTags = actualQuery.split("}")[1]
- const selectedLabels = [];
- for (const label of labels) {
- if (label.selected && label.values && label.values.length > 0) {
- const selectedValues = label.values
- .filter((value) => value.selected && !value.inverted)
- .map((value) => value.name);
- const invertedSelectedValues = label.values
- .filter((value) => value.selected && value.inverted)
- .map((value) => value.name);
-
- if (selectedValues.length > 1) {
- selectedLabels.push(
- `${label.name}=~"${selectedValues.join("|")}"`
- );
- } else if (selectedValues.length === 1) {
- selectedLabels.push(`${label.name}="${selectedValues[0]}"`);
- }
- invertedSelectedValues.forEach(value => {
- selectedLabels.push(`${label.name}!="${value}"`)
- });
-
- }
- }
- return [preTags,"{", selectedLabels.join(","), "}",postTags].join("");
-}
-export function queryBuilderWithLabels() {
- const labels = store.getState().labels;
-
- const query = queryBuilder(labels)
- store.dispatch(setQuery(query));
-}
+import { setQuery } from "../../../actions";
+import store from "../../../store/store";
+
+export function queryBuilder(labels) {
+ const actualQuery = store.getState().query
+ const preTags = actualQuery.split("{")[0]
+ const postTags = actualQuery.split("}")[1]
+ const selectedLabels = [];
+ for (const label of labels) {
+ if (label.selected && label.values && label.values.length > 0) {
+ const selectedValues = label.values
+ .filter((value) => value.selected && !value.inverted)
+ .map((value) => value.name);
+ const invertedSelectedValues = label.values
+ .filter((value) => value.selected && value.inverted)
+ .map((value) => value.name);
+
+ if (selectedValues.length > 1) {
+ selectedLabels.push(
+ `${label.name}=~"${selectedValues.join("|")}"`
+ );
+ } else if (selectedValues.length === 1) {
+ selectedLabels.push(`${label.name}="${selectedValues[0]}"`);
+ }
+ invertedSelectedValues.forEach(value => {
+ selectedLabels.push(`${label.name}!="${value}"`)
+ });
+
+ }
+ }
+ return [preTags,"{", selectedLabels.join(","), "}",postTags].join("");
+}
+
+export function queryBuilderWithLabels() {
+ const labels = store.getState().labels;
+
+ const query = queryBuilder(labels)
+ store.dispatch(setQuery(query));
+}
diff --git a/src/components/LabelBrowser/helpers/useLabelsFromQuery.js b/src/components/LabelBrowser/helpers/useLabelsFromQuery.js
new file mode 100644
index 00000000..dc77a8fa
--- /dev/null
+++ b/src/components/LabelBrowser/helpers/useLabelsFromQuery.js
@@ -0,0 +1,16 @@
+import { useEffect, useState } from "react";
+import { useSelector } from "react-redux";
+
+export default function useLabelsFromQuery() {
+ const actualQuery = useSelector((store) => store.query);
+ const [labels, setLabels] = useState([]);
+
+ function getLabels(query) {
+ return query.split(/[{}]/);
+ }
+useEffect(()=>{
+setLabels(getLabels(actualQuery))
+},[actualQuery])
+
+ return labels;
+}
diff --git a/src/components/LabelBrowser/index.js b/src/components/LabelBrowser/index.js
index 02cd8c87..91ff6f7d 100644
--- a/src/components/LabelBrowser/index.js
+++ b/src/components/LabelBrowser/index.js
@@ -1,12 +1,16 @@
-import { QueryBar } from "./QueryBar";
-import { ValuesList } from "./ValuesList";
-
-export default function LabelBrowser() {
- return (
-
-
-
-
-
- );
-}
+import { QueryBar } from "./QueryBar";
+import { ValuesList } from "./ValuesList";
+import { useSelector } from "react-redux";
+export default function LabelBrowser() {
+ const labelsBrowserOpen = useSelector(store => store.labelsBrowserOpen)
+
+ return (
+
+
+ {labelsBrowserOpen && (
+
+ )}
+
+
+ );
+}
diff --git a/src/components/MainView.js b/src/components/MainView.js
index 4f3eceed..04245c2c 100644
--- a/src/components/MainView.js
+++ b/src/components/MainView.js
@@ -1,31 +1,31 @@
-import { Notification } from "../plugins/notifications";
-
-import DataView from "./DataView/DataView";
-import StatusBar from "./StatusBar";
-import { UpdateStateFromQueryParams } from "../helpers/UpdateStateFromQueryParams";
-import LabelBrowser from "./LabelBrowser";
-import SettingsDialog from "../plugins/settingsdialog/SettingsDialog";
-import { useSelector } from 'react-redux';
-
-export default function MainView() {
- UpdateStateFromQueryParams();
- const settingsDialogOpen = useSelector( store => store.settingsDialogOpen)
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
+import { Notification } from "../plugins/notifications";
+
+import DataView from "./DataView/DataView";
+import StatusBar from "./StatusBar";
+import { UpdateStateFromQueryParams } from "../helpers/UpdateStateFromQueryParams";
+import LabelBrowser from "./LabelBrowser";
+import SettingsDialog from "../plugins/settingsdialog/SettingsDialog";
+import { useSelector } from 'react-redux';
+
+export default function MainView() {
+ UpdateStateFromQueryParams();
+ const settingsDialogOpen = useSelector( store => store.settingsDialogOpen)
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/StatusBar/components/apiselector/ApiSelector.js b/src/components/StatusBar/components/apiselector/ApiSelector.js
index c8045cf4..9b56455b 100644
--- a/src/components/StatusBar/components/apiselector/ApiSelector.js
+++ b/src/components/StatusBar/components/apiselector/ApiSelector.js
@@ -1,86 +1,88 @@
-import { useDispatch, useSelector } from "react-redux";
-import { useState, useEffect } from "react";
-import loadLabels from "../../../../actions/LoadLabels";
-import { setLabelsBrowserOpen } from "../../../../actions/setLabelsBrowserOpen";
-import setMatrixData from "../../../../actions/setMatrixData";
-import loadLogs from "../../../../actions/loadLogs";
-import { setApiUrl } from "../../../../actions";
-import LinkIcon from "@mui/icons-material/Link";
-import setLogs from "../../../../actions/setLogs";
-import {
- ApiSelectorButton,
- ApiSelectorInput,
- ApiSelectorStyled,
-} from "../../styled";
-
-export function ApiSelector() {
- const apiUrl = useSelector((store) => store.apiUrl);
- const apiError = useSelector((store) => store.apiErrors);
- const [editedUrl, setEditedUrl] = useState(apiUrl);
- const query = useSelector((store) => store.query);
- const [apiSelectorOpen, setApiSelectorOpen] = useState(false);
- const dispatch = useDispatch();
- const API_URL = "API URL";
- useEffect(() => {
- setEditedUrl(apiUrl);
- }, []);
-
- useEffect(() => {
- setEditedUrl(apiUrl);
- }, [apiUrl]);
-
- useEffect(() => {
- if (apiError.length > 0) {
- setApiSelectorOpen(true);
- dispatch(setLogs([]));
- dispatch(setMatrixData([]));
- } else {
- setApiSelectorOpen(false);
- dispatch(loadLogs());
- }
- }, [apiError]);
-
- const handleApiUrlOpen = (e = null) => {
- e?.preventDefault();
- apiSelectorOpen ? setApiSelectorOpen(false) : setApiSelectorOpen(true);
- };
-
- const handleIntputChange = (e) => {
- e.preventDefault();
- setEditedUrl(e.target.value);
- };
- const onUrlSubmit = (e) => {
- dispatch(setApiUrl(editedUrl));
- dispatch(loadLabels(editedUrl));
- if (query?.length > 3) {
- dispatch(setLabelsBrowserOpen(false));
- }
- };
-
- return (
-
-
-
-
- ●
-
-
- {apiSelectorOpen ? (
-
-
{API_URL}
-
-
- {"save"}
-
-
- ) : null}
-
- );
-}
+import { useDispatch, useSelector } from "react-redux";
+import { useState, useEffect } from "react";
+
+import { setLabelsBrowserOpen } from "../../../../actions/setLabelsBrowserOpen";
+import setMatrixData from "../../../../actions/setMatrixData";
+import loadLogs from "../../../../actions/loadLogs";
+import { setApiUrl } from "../../../../actions";
+import LinkIcon from "@mui/icons-material/Link";
+import setLogs from "../../../../actions/setLogs";
+import {
+ ApiSelectorButton,
+ ApiSelectorInput,
+ ApiSelectorStyled,
+} from "../../styled";
+import loadLabels from "../../../../actions/loadLabels";
+
+export function ApiSelector() {
+ const apiUrl = useSelector((store) => store.apiUrl);
+ const apiError = useSelector((store) => store.apiErrors);
+ const [editedUrl, setEditedUrl] = useState(apiUrl);
+
+ const [apiSelectorOpen, setApiSelectorOpen] = useState(false);
+ const dispatch = useDispatch();
+ const API_URL = "API URL";
+ useEffect(() => {
+ setEditedUrl(apiUrl);
+ }, []);
+
+ useEffect(() => {
+ setEditedUrl(apiUrl);
+ dispatch(loadLabels(apiUrl))
+ }, [apiUrl]);
+
+ useEffect(() => {
+ if (apiError.length > 0) {
+ setApiSelectorOpen(true);
+ dispatch(setLogs([]));
+ dispatch(setMatrixData([]));
+ } else {
+ setApiSelectorOpen(false);
+ dispatch(loadLogs());
+ }
+ }, [apiError]);
+
+ const handleApiUrlOpen = (e = null) => {
+ e?.preventDefault();
+ apiSelectorOpen ? setApiSelectorOpen(false) : setApiSelectorOpen(true);
+ };
+
+ const handleIntputChange = (e) => {
+ e.preventDefault();
+ setEditedUrl(e.target.value);
+ };
+ const onUrlSubmit = (e) => {
+ dispatch(setApiUrl(editedUrl));
+ setEditedUrl(editedUrl);
+ dispatch(loadLabels(editedUrl))
+ dispatch(setLabelsBrowserOpen(false));
+
+ };
+
+ return (
+
+
+
+
+ ●
+
+
+ {apiSelectorOpen ? (
+
+
{API_URL}
+
+
+ {"save"}
+
+
+ ) : null}
+
+ );
+}
diff --git a/src/components/StatusBar/components/daterangepicker/components/AbsoluteSelector.js b/src/components/StatusBar/components/daterangepicker/components/AbsoluteSelector.js
index 4a9e3065..7dc57f7f 100644
--- a/src/components/StatusBar/components/daterangepicker/components/AbsoluteSelector.js
+++ b/src/components/StatusBar/components/daterangepicker/components/AbsoluteSelector.js
@@ -1,151 +1,151 @@
-import styled from "@emotion/styled";
-import DateRangeIcon from "@mui/icons-material/DateRange";
-import darkTheme from "../../../../../theme/dark";
-import { BtnSmall } from "../../../../../theme/styles/Button";
-const theme = darkTheme;
-
-const SelectorsContainer = styled.div`
- display: ${(props) => (props.isDisplay ? "flex" : "none")};
- flex-direction: column;
- margin: 20px;
- margin-top: 30px;
- .time-selectors {
- display: ${(props) => (props.isDisplay ? "flex" : "none")};
- flex-direction: column;
- margin-bottom: 15px;
- .label {
- font-size: 0.85em;
- color: ${theme.inputLabelColor};
- width: 50px;
- margin-left: 5px;
- margin-bottom: 5px;
- white-space: nowrap;
- }
- .input-group {
- display: flex;
- margin-bottom: 20px;
- .date-time-ranged {
- font-size:14px;
- width: 170px;
- line-height: 20px;
- border:1px solid ${theme.buttonHover};
- color: ${theme.textColor};
- margin: 0;
- padding:0px 8px;
- margin-right: 5px;
- &:focus{
- border:1px solid ${theme.buttonDefault};
- }
- }
- }
- }
-`;
-
-const AbsoluteSubmitButton = styled(BtnSmall)`
- color: ${theme.buttonText};
- background: ${theme.primaryDark};
- padding: 6px;
- justify-content: center;
- margin-top:10px;
- margin-bottom: 10px;
- cursor: pointer;
- &:hover {
- background: ${theme.primaryLight};
- }
-`;
-
-const CalendarBtn = styled(BtnSmall)`
-
- color: ${theme.buttonText};
- background: ${theme.buttonDefault};
- padding:8px;
- &:hover {
- background: ${theme.buttonHover};
- color: ${theme.textColor};
- }
-`;
-
-export default function AbsoluteSelector({
- getEditedStartDate,
- getEditedEndDate,
- handleStart,
- handleStop,
- onTimeRangeSet,
- setCalendarOpen,
- isFullCalendar,
- setStopCalendar,
- setStartCalendar,
- startCalendarOpen,
- stopCalendarOpen,
- isHorizontal,
- styles,
- isMobile,
-}) {
- function handleStartOpen() {
- if (isFullCalendar) {
- setCalendarOpen((open) => (open ? false : true));
- } else {
- setCalendarOpen((open) =>
- open && startCalendarOpen ? false : true
- );
- setStopCalendar(() => false);
- setStartCalendar((open) => (open ? false : true));
- }
- }
-
- function handleStopOpen() {
- if (isFullCalendar) {
- setCalendarOpen((open) => (open ? false : true));
- } else {
- setCalendarOpen((open) =>
- open && stopCalendarOpen ? false : true
- );
- setStartCalendar(() => false);
- setStopCalendar((open) => (open ? false : true));
- }
- }
-
- return (
-
-
-
-
{"From"}
-
- handleStart(e, false)}
- onBlur={(e) => handleStart(e, true)}
- />
-
-
-
-
-
-
-
-
{"To"}
-
- handleStop(e, false)}
- onBlur={(e) => handleStop(e, true)}
- />
-
-
-
-
-
- {
- onTimeRangeSet(e);
- }}
- >
- {"Apply Time Range"}
-
-
- );
-}
+import styled from "@emotion/styled";
+import DateRangeIcon from "@mui/icons-material/DateRange";
+import darkTheme from "../../../../../theme/dark";
+import { BtnSmall } from "../../../../../theme/styles/Button";
+const theme = darkTheme;
+
+const SelectorsContainer = styled.div`
+ display: ${(props) => (props.isDisplay ? "flex" : "none")};
+ flex-direction: column;
+ margin: 20px;
+ margin-top: 30px;
+ .time-selectors {
+ display: ${(props) => (props.isDisplay ? "flex" : "none")};
+ flex-direction: column;
+ margin-bottom: 15px;
+ .label {
+ font-size: 12px;
+ color: ${theme.inputLabelColor};
+ width: 50px;
+ margin-left: 5px;
+ margin-bottom: 5px;
+ white-space: nowrap;
+ }
+ .input-group {
+ display: flex;
+ margin-bottom: 20px;
+ .date-time-ranged {
+ font-size:14px;
+ width: 170px;
+ line-height: 20px;
+ border:1px solid ${theme.buttonHover};
+ color: ${theme.textColor};
+ margin: 0;
+ padding:0px 8px;
+ margin-right: 5px;
+ &:focus{
+ border:1px solid ${theme.buttonDefault};
+ }
+ }
+ }
+ }
+`;
+
+const AbsoluteSubmitButton = styled(BtnSmall)`
+ color: ${theme.buttonText};
+ background: ${theme.primaryDark};
+ padding: 6px;
+ justify-content: center;
+ margin-top:10px;
+ margin-bottom: 10px;
+ cursor: pointer;
+ &:hover {
+ background: ${theme.primaryLight};
+ }
+`;
+
+const CalendarBtn = styled(BtnSmall)`
+
+ color: ${theme.buttonText};
+ background: ${theme.buttonDefault};
+ padding:8px;
+ &:hover {
+ background: ${theme.buttonHover};
+ color: ${theme.textColor};
+ }
+`;
+
+export default function AbsoluteSelector({
+ getEditedStartDate,
+ getEditedEndDate,
+ handleStart,
+ handleStop,
+ onTimeRangeSet,
+ setCalendarOpen,
+ isFullCalendar,
+ setStopCalendar,
+ setStartCalendar,
+ startCalendarOpen,
+ stopCalendarOpen,
+ isHorizontal,
+ styles,
+ isMobile,
+}) {
+ function handleStartOpen() {
+ if (isFullCalendar) {
+ setCalendarOpen((open) => (open ? false : true));
+ } else {
+ setCalendarOpen((open) =>
+ open && startCalendarOpen ? false : true
+ );
+ setStopCalendar(() => false);
+ setStartCalendar((open) => (open ? false : true));
+ }
+ }
+
+ function handleStopOpen() {
+ if (isFullCalendar) {
+ setCalendarOpen((open) => (open ? false : true));
+ } else {
+ setCalendarOpen((open) =>
+ open && stopCalendarOpen ? false : true
+ );
+ setStartCalendar(() => false);
+ setStopCalendar((open) => (open ? false : true));
+ }
+ }
+
+ return (
+
+
+
+
{"From"}
+
+ handleStart(e, false)}
+ onBlur={(e) => handleStart(e, true)}
+ />
+
+
+
+
+
+
+
+
{"To"}
+
+ handleStop(e, false)}
+ onBlur={(e) => handleStop(e, true)}
+ />
+
+
+
+
+
+ {
+ onTimeRangeSet(e);
+ }}
+ >
+ {"Apply Time Range"}
+
+
+ );
+}
diff --git a/src/components/StatusBar/components/daterangepicker/components/Ranges.js b/src/components/StatusBar/components/daterangepicker/components/Ranges.js
index 6e55dec6..4edc5066 100644
--- a/src/components/StatusBar/components/daterangepicker/components/Ranges.js
+++ b/src/components/StatusBar/components/daterangepicker/components/Ranges.js
@@ -1,59 +1,59 @@
-import styled from "@emotion/styled";
-import { isSameRange } from "../utils";
-
-const StyledList = styled.div`
- display: flex;
- flex-direction: column;
- padding: 10px;
- max-height: 250px;
- overflow-y: auto;
- flex: 1;
- margin-top: 10px;
- margin-bottom: 10px;
- padding: 5px;
- button {
- background: none;
- text-align: left;
- border: none;
- padding: 10px;
- line-height: 1.5;
- border-radius: 3px;
- font-size: 0.85em;
- cursor: pointer;
- &:hover {
- background: #11111155;
- }
- }
-`;
-
-const Ranges = (props) => {
- return (
-
- {props.ranges.map((range, idx) => (
-
- ))}
-
- );
-};
-
-export default Ranges;
+import styled from "@emotion/styled";
+import { isSameRange } from "../utils";
+
+const StyledList = styled.div`
+ display: flex;
+ flex-direction: column;
+ padding: 10px;
+ max-height: 250px;
+ overflow-y: auto;
+ flex: 1;
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 5px;
+ button {
+ background: none;
+ text-align: left;
+ border: none;
+ padding: 10px;
+ line-height: 1.5;
+ border-radius: 3px;
+ font-size: 12px;
+ cursor: pointer;
+ &:hover {
+ background: #11111155;
+ }
+ }
+`;
+
+const Ranges = (props) => {
+ return (
+
+ {props.ranges.map((range, idx) => (
+
+ ))}
+
+ );
+};
+
+export default Ranges;
diff --git a/src/components/StatusBar/components/daterangepicker/defaults.js b/src/components/StatusBar/components/daterangepicker/defaults.js
index 9138cefb..c7a965a3 100644
--- a/src/components/StatusBar/components/daterangepicker/defaults.js
+++ b/src/components/StatusBar/components/daterangepicker/defaults.js
@@ -1,55 +1,51 @@
-import {
- addDays,
- startOfWeek,
- endOfWeek,
- addWeeks,
- startOfMonth,
- endOfMonth,
- addMonths,
- addMinutes,
- addHours,
- addSeconds,
- startOfDay,
- endOfDay,
- getHours
-} from "date-fns";
-
-const getDefaultRanges = (date) => [
- {
- label: "Today",
- dateStart: startOfDay,
- dateEnd: endOfDay
- },
- {
- label: "Yesterday",
- dateStart: addDays(date, -1),
- dateEnd: addDays(date, -1)
- },
- {
- label: "This Week",
- dateStart: startOfWeek(date),
- dateEnd: endOfWeek(date)
- },
- {
- label: "Last Week",
- dateStart: startOfWeek(addWeeks(date, -1)),
- dateEnd: endOfWeek(addWeeks(date, -1))
- },
- {
- label: "Last 7 Days",
- dateStart: addWeeks(date, -1),
- dateEnd: date
- },
- {
- label: "This Month",
- dateStart: startOfMonth(date),
- dateEnd: endOfMonth(date)
- },
- {
- label: "Last Month",
- dateStart: startOfMonth(addMonths(date, -1)),
- dateEnd: endOfMonth(addMonths(date, -1))
- }
-];
-
+import {
+ addDays,
+ startOfWeek,
+ endOfWeek,
+ addWeeks,
+ startOfMonth,
+ endOfMonth,
+ addMonths,
+ startOfDay,
+ endOfDay,
+} from "date-fns";
+
+const getDefaultRanges = (date) => [
+ {
+ label: "Today",
+ dateStart: startOfDay,
+ dateEnd: endOfDay
+ },
+ {
+ label: "Yesterday",
+ dateStart: addDays(date, -1),
+ dateEnd: addDays(date, -1)
+ },
+ {
+ label: "This Week",
+ dateStart: startOfWeek(date),
+ dateEnd: endOfWeek(date)
+ },
+ {
+ label: "Last Week",
+ dateStart: startOfWeek(addWeeks(date, -1)),
+ dateEnd: endOfWeek(addWeeks(date, -1))
+ },
+ {
+ label: "Last 7 Days",
+ dateStart: addWeeks(date, -1),
+ dateEnd: date
+ },
+ {
+ label: "This Month",
+ dateStart: startOfMonth(date),
+ dateEnd: endOfMonth(date)
+ },
+ {
+ label: "Last Month",
+ dateStart: startOfMonth(addMonths(date, -1)),
+ dateEnd: endOfMonth(addMonths(date, -1))
+ }
+];
+
export const defaultRanges = getDefaultRanges(new Date());
\ No newline at end of file
diff --git a/src/components/StatusBar/components/daterangepicker/index.js b/src/components/StatusBar/components/daterangepicker/index.js
index 137da478..b684b014 100644
--- a/src/components/StatusBar/components/daterangepicker/index.js
+++ b/src/components/StatusBar/components/daterangepicker/index.js
@@ -1,289 +1,286 @@
-import React, { useState, useEffect } from "react";
-
-import {
- addMonths,
- isSameDay,
- isWithinInterval,
- isAfter,
- isBefore,
- isDate,
- isSameMonth,
- addYears,
- max,
- min,
- format,
- isValid,
-} from "date-fns";
-
-import Nav from "./components/Nav";
-import {
- findRangeByLabel,
- getDefaultRanges,
- getValidatedMonths,
- parseOptionalDate,
-} from "./utils";
-import { DATE_TIME_RANGE, MARKERS } from "./consts";
-import { theme } from "./components/styles";
-import { ThemeProvider } from "@emotion/react";
-import {
- setRangeOpen,
- setStartTime,
- setTimeRangeLabel,
- setStopTime,
-} from "../../../../actions";
-
-import { useSelector, useDispatch } from "react-redux";
-import useOutsideRef from "./hooks/useOutsideRef";
-
-import store from "../../../../store/store";
-
-import AccessTimeOutlinedIcon from "@mui/icons-material/AccessTimeOutlined";
-import { Tooltip } from "@mui/material";
-import loadLogs from "../../../../actions/loadLogs";
-import { setLabelsBrowserOpen } from "../../../../actions/setLabelsBrowserOpen";
-
-
-
-import TimeLabel from "./components/TimeLabel";
-import { DatePickerButton } from "../../styled";
-
-
-export function DateRangePickerMain(props) {
- const today = Date.now();
- const { isOpen, minDate, maxDate } = props;
-
- const startTs = useSelector((store) => store.start);
- const stopTs = useSelector((store) => store.stop);
- const initialDateRange = () => {
- try {
- const ls = JSON.parse(localStorage.getItem(DATE_TIME_RANGE));
- if (ls?.label !== "" && typeof ls.label !== "undefined") {
- const range = findRangeByLabel(ls?.label);
- ls.dateStart = range.dateStart;
- ls.dateEnd = range.dateEnd;
- } else {
- ls.dateStart = new Date(ls.dateStart);
- ls.dateEnd = new Date(ls.dateEnd);
- }
- return ls;
- } catch (e) {
- if (isDate(startTs) && isDate(stopTs)) {
- return { dateStart: startTs, dateEnd: stopTs };
- }
- }
- };
-
- const minDateValid = parseOptionalDate(minDate, addYears(today, -10));
- const maxDateValid = parseOptionalDate(maxDate, addYears(today, 10));
- const [intialFirstMonth, initialSecondMonth] = getValidatedMonths(
- initialDateRange() || {},
- minDateValid,
- maxDateValid
- );
- const [dateRange, setDateRange] = useState({ ...initialDateRange() });
- const [hoverDay, setHoverDay] = useState();
- const [firstMonth, setFirstMonth] = useState(intialFirstMonth || today);
- const [secondMonth, setSecondMonth] = useState(
- initialSecondMonth || addMonths(firstMonth, 1)
- );
- const [timeLabel, setTimeLabel] = useState("");
- const dispatch = useDispatch();
-
- const rangeOpen = useSelector((store) => store.rangeOpen);
- const range = useSelector((store) => ({
- dateStart: store.start,
- dateEnd: store.stop,
- label: store.label,
- }));
-
- useEffect(() => {
- setTimeLabel(range.label);
- }, [range]);
-
- const { dateStart, dateEnd } = dateRange;
-
- const { ref } = useOutsideRef(true);
-
-
- const setFirstMonthValidated = (date) => {
- if (isBefore(date, secondMonth)) {
- setFirstMonth(date);
- }
- };
-
- const setSecondMonthValidated = (date) => {
- if (isAfter(date, firstMonth)) {
- setSecondMonth(date);
- }
- };
-
- const setDateRangeValidated = (range) => {
- let { label, dateStart: newStart, dateEnd: newEnd } = range;
- if (newStart && newEnd) {
- range.label = label;
- range.dateStart = newStart = max([newStart, minDateValid]);
- range.dateEnd = newEnd = min([newEnd, maxDateValid]);
- setDateRange(range);
- saveDateRange(range);
- onChange(range);
- setFirstMonth(newStart);
- setSecondMonth(
- isSameMonth(newStart, newEnd) ? addMonths(newStart, 1) : newEnd
- );
- }
- };
- const saveDateRange = (range) => {
- localStorage.setItem(DATE_TIME_RANGE, JSON.stringify(range));
- };
- const onDayClick = (day) => {
- if (dateStart && !dateEnd && !isBefore(day, dateStart)) {
- const newRange = { dateStart, dateEnd: day };
- onChange(newRange);
- saveDateRange(newRange);
- setDateRange(newRange);
- dispatch(setTimeRangeLabel(""));
- onClose();
- } else {
- setDateRange({ dateStart: day, dateEnd: undefined });
- }
- setHoverDay(day);
- };
-
- const onMonthNavigate = (marker, action) => {
- if (marker === MARKERS.FIRST_MONTH) {
- const firstNew = addMonths(firstMonth, action);
- if (isBefore(firstNew, secondMonth)) setFirstMonth(firstNew);
- } else {
- const secondNew = addMonths(secondMonth, action);
- if (isBefore(firstMonth, secondNew)) setSecondMonth(secondNew);
- }
- };
-
- const onDayHover = (date) => {
- if (dateStart && !dateEnd) {
- if (!hoverDay || !isSameDay(date, hoverDay)) {
- setHoverDay(date);
- }
- }
- };
- const onClose = (e = null) => {
- const { query } = store.getState();
- e?.preventDefault();
- if (onQueryValid(query)) {
- dispatch(setLabelsBrowserOpen(false));
- dispatch(loadLogs());
- } else {
- console.log("Please make a log query", query);
- }
- dispatch(setRangeOpen(false));
- isOpen(e);
- };
- const onQueryValid = (query) => {
- return query !== "{" && query !== "}" && query !== "{}" && query !== ""; // TODO: make a proper query validation
- };
- // helpers
- const inHoverRange = (day) => {
- return (
- dateStart &&
- !dateEnd &&
- hoverDay &&
- isAfter(hoverDay, dateStart) &&
- isWithinInterval(day, {
- start: dateStart,
- end: hoverDay,
- })
- );
- };
-
-
- const helpers = {
- inHoverRange,
- };
-
- const handlers = {
- onDayClick,
- onDayHover,
- onMonthNavigate,
- };
-
- function onChange({ dateStart, dateEnd, label }) {
- const isStart = isDate(dateStart);
- const isEnd = isDate(dateEnd);
- const isLabel = typeof label !== "undefined";
- if (isStart) dispatch(setStartTime(dateStart));
- if (isEnd) dispatch(setStopTime(dateEnd));
- if (isLabel) dispatch(setTimeRangeLabel(label));
- }
-
- const openButtonHandler = (e) => {
- e.preventDefault();
- if (rangeOpen === true) {
- onClose(e);
-
- } else {
- dispatch(setRangeOpen(true));
-
- }
- };
-
- return (
-
-
: ""}
- >
-
-
-
-
- {timeLabel
- ? timeLabel
- : (isValid(dateRange.dateStart)
- ? format(
- dateRange.dateStart,
- "yyyy/MM/dd HH:mm:ss"
- )
- : dateRange.dateStart) +
- "-" +
- (isValid(dateRange.dateEnd)
- ? format(
- dateRange.dateEnd,
- "yyyy/MM/dd HH:mm:ss"
- )
- : typeof dateRange.dateEnd !== "undefined"
- ? dateRange.dateEnd
- : "")}
-
-
-
- {rangeOpen ? (
-
-
-
-
-
- ) : null}
-
- );
-}
-export const DateRangePicker = DateRangePickerMain;
-
-//shouldnt be at same div!!
-
-
+import React, { useState, useEffect } from "react";
+
+import {
+ addMonths,
+ isSameDay,
+ isWithinInterval,
+ isAfter,
+ isBefore,
+ isDate,
+ isSameMonth,
+ addYears,
+ max,
+ min,
+ format,
+ isValid,
+} from "date-fns";
+
+import Nav from "./components/Nav";
+import {
+ findRangeByLabel,
+ getDefaultRanges,
+ getValidatedMonths,
+ parseOptionalDate,
+} from "./utils";
+import { DATE_TIME_RANGE, MARKERS } from "./consts";
+import { theme } from "./components/styles";
+import { ThemeProvider } from "@emotion/react";
+import {
+ setRangeOpen,
+ setStartTime,
+ setTimeRangeLabel,
+ setStopTime,
+} from "../../../../actions";
+
+import { useSelector, useDispatch } from "react-redux";
+import useOutsideRef from "./hooks/useOutsideRef";
+
+import store from "../../../../store/store";
+
+import AccessTimeOutlinedIcon from "@mui/icons-material/AccessTimeOutlined";
+import { Tooltip } from "@mui/material";
+import loadLogs from "../../../../actions/loadLogs";
+import { setLabelsBrowserOpen } from "../../../../actions/setLabelsBrowserOpen";
+
+
+
+import TimeLabel from "./components/TimeLabel";
+import { DatePickerButton } from "../../styled";
+
+
+export function DateRangePickerMain(props) {
+ const today = Date.now();
+ const { isOpen, minDate, maxDate } = props;
+
+ const startTs = useSelector((store) => store.start);
+ const stopTs = useSelector((store) => store.stop);
+ const initialDateRange = () => {
+ try {
+ const ls = JSON.parse(localStorage.getItem(DATE_TIME_RANGE));
+ if (ls?.label !== "" && typeof ls.label !== "undefined") {
+ const range = findRangeByLabel(ls?.label);
+ ls.dateStart = range.dateStart;
+ ls.dateEnd = range.dateEnd;
+ } else {
+ ls.dateStart = new Date(ls.dateStart);
+ ls.dateEnd = new Date(ls.dateEnd);
+ }
+ return ls;
+ } catch (e) {
+ if (isDate(startTs) && isDate(stopTs)) {
+ return { dateStart: startTs, dateEnd: stopTs };
+ }
+ }
+ };
+
+ const minDateValid = parseOptionalDate(minDate, addYears(today, -10));
+ const maxDateValid = parseOptionalDate(maxDate, addYears(today, 10));
+ const [intialFirstMonth, initialSecondMonth] = getValidatedMonths(
+ initialDateRange() || {},
+ minDateValid,
+ maxDateValid
+ );
+ const [dateRange, setDateRange] = useState({ ...initialDateRange() });
+ const [hoverDay, setHoverDay] = useState();
+ const [firstMonth, setFirstMonth] = useState(intialFirstMonth || today);
+ const [secondMonth, setSecondMonth] = useState(
+ initialSecondMonth || addMonths(firstMonth, 1)
+ );
+ const [timeLabel, setTimeLabel] = useState("");
+ const dispatch = useDispatch();
+
+ const rangeOpen = useSelector((store) => store.rangeOpen);
+ const range = useSelector((store) => ({
+ dateStart: store.start,
+ dateEnd: store.stop,
+ label: store.label,
+ }));
+
+ useEffect(() => {
+ setTimeLabel(range.label);
+ }, [range]);
+
+ const { dateStart, dateEnd } = dateRange;
+
+ const { ref } = useOutsideRef(true);
+
+
+ const setFirstMonthValidated = (date) => {
+ if (isBefore(date, secondMonth)) {
+ setFirstMonth(date);
+ }
+ };
+
+ const setSecondMonthValidated = (date) => {
+ if (isAfter(date, firstMonth)) {
+ setSecondMonth(date);
+ }
+ };
+
+ const setDateRangeValidated = (range) => {
+ let { label, dateStart: newStart, dateEnd: newEnd } = range;
+ if (newStart && newEnd) {
+ range.label = label;
+ range.dateStart = newStart = max([newStart, minDateValid]);
+ range.dateEnd = newEnd = min([newEnd, maxDateValid]);
+ setDateRange(range);
+ saveDateRange(range);
+ onChange(range);
+ setFirstMonth(newStart);
+ setSecondMonth(
+ isSameMonth(newStart, newEnd) ? addMonths(newStart, 1) : newEnd
+ );
+ }
+ };
+ const saveDateRange = (range) => {
+ localStorage.setItem(DATE_TIME_RANGE, JSON.stringify(range));
+ };
+ const onDayClick = (day) => {
+ if (dateStart && !dateEnd && !isBefore(day, dateStart)) {
+ const newRange = { dateStart, dateEnd: day };
+ onChange(newRange);
+ saveDateRange(newRange);
+ setDateRange(newRange);
+ dispatch(setTimeRangeLabel(""));
+ onClose();
+ } else {
+ setDateRange({ dateStart: day, dateEnd: undefined });
+ }
+ setHoverDay(day);
+ };
+
+ const onMonthNavigate = (marker, action) => {
+ if (marker === MARKERS.FIRST_MONTH) {
+ const firstNew = addMonths(firstMonth, action);
+ if (isBefore(firstNew, secondMonth)) setFirstMonth(firstNew);
+ } else {
+ const secondNew = addMonths(secondMonth, action);
+ if (isBefore(firstMonth, secondNew)) setSecondMonth(secondNew);
+ }
+ };
+
+ const onDayHover = (date) => {
+ if (dateStart && !dateEnd) {
+ if (!hoverDay || !isSameDay(date, hoverDay)) {
+ setHoverDay(date);
+ }
+ }
+ };
+ const onClose = (e = null) => {
+ const { query } = store.getState();
+ e?.preventDefault();
+ if (query.length > 0) {
+ dispatch(setLabelsBrowserOpen(false));
+ dispatch(loadLogs());
+ } else {
+ console.log("Please make a log query", query);
+ }
+ dispatch(setRangeOpen(false));
+ isOpen(e);
+ };
+
+ const inHoverRange = (day) => {
+ return (
+ dateStart &&
+ !dateEnd &&
+ hoverDay &&
+ isAfter(hoverDay, dateStart) &&
+ isWithinInterval(day, {
+ start: dateStart,
+ end: hoverDay,
+ })
+ );
+ };
+
+
+ const helpers = {
+ inHoverRange,
+ };
+
+ const handlers = {
+ onDayClick,
+ onDayHover,
+ onMonthNavigate,
+ };
+
+ function onChange({ dateStart, dateEnd, label }) {
+ const isStart = isDate(dateStart);
+ const isEnd = isDate(dateEnd);
+ const isLabel = typeof label !== "undefined";
+ if (isStart) dispatch(setStartTime(dateStart));
+ if (isEnd) dispatch(setStopTime(dateEnd));
+ if (isLabel) dispatch(setTimeRangeLabel(label));
+ }
+
+ const openButtonHandler = (e) => {
+ e.preventDefault();
+ if (rangeOpen === true) {
+ onClose(e);
+
+ } else {
+ dispatch(setRangeOpen(true));
+
+ }
+ };
+
+ return (
+
+
: ""}
+ >
+
+
+
+
+ {timeLabel
+ ? timeLabel
+ : (isValid(dateRange.dateStart)
+ ? format(
+ dateRange.dateStart,
+ "yyyy/MM/dd HH:mm:ss"
+ )
+ : dateRange.dateStart) +
+ "-" +
+ (isValid(dateRange.dateEnd)
+ ? format(
+ dateRange.dateEnd,
+ "yyyy/MM/dd HH:mm:ss"
+ )
+ : typeof dateRange.dateEnd !== "undefined"
+ ? dateRange.dateEnd
+ : "")}
+
+
+
+ {rangeOpen ? (
+
+
+
+
+
+ ) : null}
+
+ );
+}
+export const DateRangePicker = DateRangePickerMain;
+
+//shouldnt be at same div!!
+
+
diff --git a/src/components/StatusBar/components/timepickerbutton/TimePickerButton.js b/src/components/StatusBar/components/timepickerbutton/TimePickerButton.js
index 665fb03f..2ffe6f52 100644
--- a/src/components/StatusBar/components/timepickerbutton/TimePickerButton.js
+++ b/src/components/StatusBar/components/timepickerbutton/TimePickerButton.js
@@ -1,21 +1,20 @@
-import { TimePickerButtonStyled } from "./styled";
-import { useDispatch, useSelector } from "react-redux";
-import setTimePickerOpen from "./actions/setTimePickerOpen";
-import AccessTimeIcon from "@mui/icons-material/AccessTime";
-import { setRangeOpen } from "../../../../actions";
-
-export default function TimePickerButton() {
- const dispatch = useDispatch();
- const timePickerOpen = useSelector((store) => store.rangeOpen);
-
- function openTimePicker() {
- const shouldOpen = timePickerOpen ? false : true;
-
- dispatch(setRangeOpen(shouldOpen));
- }
- return (
-
-
-
- );
-}
+import { TimePickerButtonStyled } from "./styled";
+import { useDispatch, useSelector } from "react-redux";
+import AccessTimeIcon from "@mui/icons-material/AccessTime";
+import { setRangeOpen } from "../../../../actions";
+
+export default function TimePickerButton() {
+ const dispatch = useDispatch();
+ const timePickerOpen = useSelector((store) => store.rangeOpen);
+
+ function openTimePicker() {
+ const shouldOpen = timePickerOpen ? false : true;
+
+ dispatch(setRangeOpen(shouldOpen));
+ }
+ return (
+
+
+
+ );
+}
diff --git a/src/components/StatusBar/index.js b/src/components/StatusBar/index.js
index 6ada0aa1..915f2ba5 100644
--- a/src/components/StatusBar/index.js
+++ b/src/components/StatusBar/index.js
@@ -1,33 +1,33 @@
-import { ApiSelector } from "./components/apiselector/ApiSelector";
-import { StatusBarSelectors } from "./components/statusbarselectors/StatusBarSelectors";
-import Logo from "./assets/cloki-logo.png";
-import { StatusBarCont, StatusCont } from "./styled";
-import ClokiMenu from "../../plugins/settingsmenu/Menu";
-import { useSelector } from "react-redux";
-
-
-export default function StatusBar() {
-const isEmbed = useSelector(store => store.isEmbed)
- return ( !isEmbed && (
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-
- );
-}
+import { ApiSelector } from "./components/apiselector/ApiSelector";
+import { StatusBarSelectors } from "./components/statusbarselectors/StatusBarSelectors";
+import Logo from "./assets/cloki-logo.png";
+import { StatusBarCont, StatusCont } from "./styled";
+import ClokiMenu from "../../plugins/settingsmenu/Menu";
+import { useSelector } from "react-redux";
+
+
+export default function StatusBar() {
+const isEmbed = useSelector(store => store.isEmbed)
+ return ( !isEmbed && (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+
+ );
+}
diff --git a/src/components/StatusBar/styled/index.js b/src/components/StatusBar/styled/index.js
index 7660b6c4..75459380 100644
--- a/src/components/StatusBar/styled/index.js
+++ b/src/components/StatusBar/styled/index.js
@@ -1,133 +1,133 @@
-import styled from "@emotion/styled";
-import darkTheme from "../../../theme/dark";
-import { BtnSmall } from "../../../theme/styles/Button";
-import { InputSmall } from "../../../theme/styles/Input";
-const theme = darkTheme;
-export const MenuButton = styled(BtnSmall)`
- background: none;
- border: none;
- display: flex;
- height: 26px;
- color: ${(props) =>
- props.isActive ? theme.inputTextFocus : theme.textColor};
- cursor: pointer;
-`;
-
-export const StatusBarCont = styled.div`
- display: flex;
- justify-content: space-between;
- padding: 5px 10px;
-`;
-
-export const StatusCont = styled.div`
- display: flex;
- align-items: center;
- .selector {
- margin-left: 10px;
- .label {
- flex: 1;
- color: ${theme.inputLabelColor};
- padding: 4px 8px;
- font-size: 0.85em;
- text-transform: uppercase;
- background: ${theme.inputLabelBg};
- border-radius: 4px;
- white-space: nowrap;
- }
- }
- input {
- color: ${theme.textColor};
- background: ${theme.inputBg};
- border: none;
- outline: none;
- padding: 4px 8px;
- font-size: 1em;
- border-radius: 3px;
- line-height: 1.5;
- margin: 0px 5px;
- &:focus {
- color: orange;
- }
- &.limit {
- width: 50px;
- }
-
- &.date-time-range {
- width: 120px;
- }
- }
-`;
-export const ApiSelectorStyled = styled.div`
- display: flex;
- align-items: center;
- margin-left: 20px;
- display: flex;
- align-items: center;
- transition: 0.2s all;
- height: 26px;
-
- .selector {
- margin-left: 10px;
- .label {
- flex: 1;
- color: ${theme.inputLabelColor};
- padding: 4px 8px;
- font-size: 0.85em;
- text-transform: uppercase;
- background: ${theme.inputLabelBg};
- border-radius: 4px;
- white-space: nowrap;
- }
- }
- & div {
- display: flex;
- align-items: center;
- }
- @media screen and (max-width: 850px) {
- display: none;
- }
-`;
-
-export const ApiSelectorButton = styled(BtnSmall)`
- background: ${theme.buttonDefault};
- color: ${theme.textColor};
- text-overflow: ellipsis;
- transition: 0.2s all;
- &:hover {
- background: ${theme.buttonHover};
- }
-`;
-export const ApiSelectorInput = styled(InputSmall)`
- color: ${theme.textColor};
- background: ${theme.inputBg};
- &:focus {
- color: orange;
- }
-`;
-export const UrlCopyButton = styled(BtnSmall)`
- background: ${theme.buttonDefault};
- color: ${({ isActive }) => (isActive ? "orange" : theme.textColor)};
- cursor: ${({ isActive }) => (isActive ? "pointer" : "not-allowed")};
- text-overflow: ellipsis;
- transition: 0.2s all;
- span {
- margin-left: 4px;
- color: ${theme.textColor};
- }
- &:hover {
- background: ${theme.buttonHover};
- }
-`;
-
-export const DatePickerButton = styled(BtnSmall)`
- background: ${theme.buttonDefault};
- color: ${theme.textColor};
- height: 26px;
- margin-left: 10px;
- span {
- margin-left: 5px;
- }
- &:hover {
- color: orange;
- }
-`;
+import styled from "@emotion/styled";
+import darkTheme from "../../../theme/dark";
+import { BtnSmall } from "../../../theme/styles/Button";
+import { InputSmall } from "../../../theme/styles/Input";
+const theme = darkTheme;
+export const MenuButton = styled(BtnSmall)`
+ background: none;
+ border: none;
+ display: flex;
+ height: 26px;
+ color: ${(props) =>
+ props.isActive ? theme.inputTextFocus : theme.textColor};
+ cursor: pointer;
+`;
+
+export const StatusBarCont = styled.div`
+ display: flex;
+ justify-content: space-between;
+ padding: 0px 7px;
+`;
+
+export const StatusCont = styled.div`
+ display: flex;
+ align-items: center;
+ .selector {
+ margin-left: 10px;
+ .label {
+ flex: 1;
+ color: ${theme.inputLabelColor};
+ padding: 4px 8px;
+ font-size: 12px;
+ text-transform: uppercase;
+ background: ${theme.inputLabelBg};
+ border-radius: 4px;
+ white-space: nowrap;
+ }
+ }
+ input {
+ color: ${theme.textColor};
+ background: ${theme.inputBg};
+ border: none;
+ outline: none;
+ padding: 4px 8px;
+ font-size: 1em;
+ border-radius: 3px;
+ line-height: 1.5;
+ margin: 0px 5px;
+ &:focus {
+ color: orange;
+ }
+ &.limit {
+ width: 50px;
+ }
+
+ &.date-time-range {
+ width: 120px;
+ }
+ }
+`;
+export const ApiSelectorStyled = styled.div`
+ display: flex;
+ align-items: center;
+ margin-left: 20px;
+ display: flex;
+ align-items: center;
+ transition: 0.2s all;
+ height: 26px;
+
+ .selector {
+ margin-left: 10px;
+ .label {
+ flex: 1;
+ color: ${theme.inputLabelColor};
+ padding: 4px 8px;
+ font-size: 12px;
+ text-transform: uppercase;
+ background: ${theme.inputLabelBg};
+ border-radius: 4px;
+ white-space: nowrap;
+ }
+ }
+ & div {
+ display: flex;
+ align-items: center;
+ }
+ @media screen and (max-width: 850px) {
+ display: none;
+ }
+`;
+
+export const ApiSelectorButton = styled(BtnSmall)`
+ background: ${theme.buttonDefault};
+ color: ${theme.textColor};
+ text-overflow: ellipsis;
+ transition: 0.2s all;
+ &:hover {
+ background: ${theme.buttonHover};
+ }
+`;
+export const ApiSelectorInput = styled(InputSmall)`
+ color: ${theme.textColor};
+ background: ${theme.inputBg};
+ &:focus {
+ color: orange;
+ }
+`;
+export const UrlCopyButton = styled(BtnSmall)`
+ background: ${theme.buttonDefault};
+ color: ${({ isActive }) => (isActive ? "orange" : theme.textColor)};
+ cursor: ${({ isActive }) => (isActive ? "pointer" : "not-allowed")};
+ text-overflow: ellipsis;
+ transition: 0.2s all;
+ span {
+ margin-left: 4px;
+ color: ${theme.textColor};
+ }
+ &:hover {
+ background: ${theme.buttonHover};
+ }
+`;
+
+export const DatePickerButton = styled(BtnSmall)`
+ background: ${theme.buttonDefault};
+ color: ${theme.textColor};
+ height: 26px;
+ margin-left: 10px;
+ span {
+ margin-left: 5px;
+ }
+ &:hover {
+ color: orange;
+ }
+`;
diff --git a/src/helpers/UpdateStateFromQueryParams.js b/src/helpers/UpdateStateFromQueryParams.js
index 91067275..db404fac 100644
--- a/src/helpers/UpdateStateFromQueryParams.js
+++ b/src/helpers/UpdateStateFromQueryParams.js
@@ -1,303 +1,314 @@
-import * as moment from "moment";
-import { useEffect } from "react";
-import { useDispatch, useSelector } from "react-redux";
-import { useLocation } from "react-router-dom";
-import {
- setApiUrl,
- setIsSubmit,
- setLabels,
- setQuery,
- setQueryLimit,
- setQueryStep,
- setStartTime,
- setStopTime,
-
-} from "../actions";
-
-
-import loadLabels from "../actions/LoadLabels";
-import loadLabelValues from "../actions/loadLabelValues";
-import setFromTime from "../actions/setFromTime";
-import setIsEmbed from "../actions/setIsEmbed";
-import { setLabelsBrowserOpen } from "../actions/setLabelsBrowserOpen";
-import setToTime from "../actions/setToTime";
-import { setUrlLocation } from "../actions/setUrlLocation";
-import { setUrlQueryParams } from "../actions/setUrlQueryParams";
-import { environment } from "../environment/env.dev";
-import store from "../store/store";
-export function UpdateStateFromQueryParams() {
- const { hash } = useLocation();
-
- const dispatch = useDispatch();
- const urlQueryParams = useSelector((store) => store.urlQueryParams);
- const start = useSelector((store) => store.start);
- const stop = useSelector((store) => store.stop);
- const limit = useSelector((store) => store.limit);
- const from = useSelector((store) => store.from);
- const to = useSelector((store)=> store.to);
- const step = useSelector((store) => store.step);
- const apiUrl = useSelector((store) => store.apiUrl);
- const isSubmit = useSelector((store) => store.isSubmit);
- const isEmbed = useSelector((store) => store.isEmbed);
- const query = useSelector((store) => store.query);
-
- const STORE_KEYS = {
- apiUrl,
- query,
- start,
- limit,
- step,
- end: stop,
- from,
- to,
- isSubmit,
- isEmbed,
- };
-
- const STORE_ACTIONS = {
- apiUrl: setApiUrl,
- query: setQuery,
- start: setStartTime,
- limit: setQueryLimit,
- step: setQueryStep,
- end: setStopTime,
- from: setFromTime,
- to: setToTime,
- isSubmit: setIsSubmit,
- isEmbed: setIsEmbed,
-
- };
-
- const STRING_VALUES = ["limit", "step", "apiUrl"];
-
- const QUERY_VALUE = "query";
-
- const TIME_VALUES = ["start", "end",];
-
- const BOOLEAN_VALUES = ["isSubmit", "isEmbed"];
-
- const encodeTs = (ts) => {
- return ts.getTime() + "000000";
- };
-
- useEffect(() => {
- const urlFromHash = new URLSearchParams(hash.replace("#", ""));
-
- // !if there is some params set them first on UI
-
- if (hash.length > 0) {
- const startParams = urlQueryParams;
-
- for (let [key, value] of urlFromHash.entries()) {
- startParams[key] = value;
- }
- if (Object.keys(startParams).length > 0) {
- dispatch(setUrlQueryParams({ ...urlQueryParams, startParams }));
-
- dispatch(setUrlLocation(hash));
- Object.keys(startParams).forEach((param) => {
- if (
- STRING_VALUES.includes(param) &&
- startParams[param] !== ""
- ) {
- dispatch(STORE_ACTIONS[param](startParams[param]));
- } else if (
- QUERY_VALUE === param &&
- startParams[param] !== ""
- ) {
- const parsedQuery = decodeURIComponent(
- startParams[param]
- );
- dispatch(STORE_ACTIONS[param](parsedQuery));
- } else if (
- TIME_VALUES.includes(param) &&
- startParams[param] !== ""
- ) {
- const croppedTime = startParams[param] / 1000000;
- const paramDate = new Date(
- moment(croppedTime).format(
- "YYYY-MM-DDTHH:mm:ss.SSSZ"
- )
- );
- dispatch(STORE_ACTIONS[param](paramDate));
- } else if (
- BOOLEAN_VALUES.includes(param) &&
- typeof param === "boolean"
- ) {
- dispatch(STORE_ACTIONS[param](startParams[param]));
- }
- if (QUERY_VALUE === param) {
- }
- });
- decodeQuery(decodeURIComponent(startParams.query), apiUrl);
- dispatch(setLabelsBrowserOpen(false));
- }
- } else {
- dispatch(setApiUrl(environment.apiUrl));
-
- const allParams = STRING_VALUES.concat(TIME_VALUES);
- allParams.push(QUERY_VALUE);
- allParams.push(BOOLEAN_VALUES);
- allParams.forEach((param) => {
- if (STRING_VALUES.includes(param, "PARAM")) {
- urlFromHash.set(param, STORE_KEYS[param].toString());
- } else if (TIME_VALUES.includes(param)) {
- const time_value = STORE_KEYS[param]?.getTime() * 1000000;
-
- urlFromHash.set(param, time_value.toString());
- } else if (QUERY_VALUE === param) {
- const parsed = encodeURIComponent(
- STORE_KEYS[param]
- ).toString();
- urlFromHash.set(param, parsed.toString());
- } else if (
- BOOLEAN_VALUES === param &&
- typeof param === "boolean"
- ) {
- urlFromHash.set(param, param.toString());
- }
- });
- const newQuery = STORE_KEYS[query];
- decodeQuery(newQuery, apiUrl);
-
- window.location.hash = urlFromHash;
- }
- }, []);
-
- useEffect(() => {
- if (hash.length > 0) {
- const paramsFromHash = new URLSearchParams(hash.replace("#", ""));
- let previousParams = {};
- for (let [key, value] of paramsFromHash.entries()) {
- previousParams[key] = value;
- }
-
- Object.keys(STORE_KEYS).forEach((store_key) => {
- if (
- STRING_VALUES.includes(store_key) &&
- previousParams[store_key] !== STORE_KEYS[store_key]
- ) {
- const updated = STORE_KEYS[store_key].toString().trim();
- paramsFromHash.set(store_key, updated);
- } else if (
- QUERY_VALUE === store_key &&
- previousParams[store_key] !==
- encodeURIComponent(STORE_KEYS[store_key])
- ) {
- const queryUpdated = encodeURIComponent(
- STORE_KEYS[store_key].toString()
- );
- paramsFromHash.set(store_key, queryUpdated);
- } else if (
- TIME_VALUES.includes(store_key) &&
- previousParams[store_key] !==
- encodeTs(STORE_KEYS[store_key])
- ) {
- const encodedTs = encodeTs(STORE_KEYS[store_key]);
- paramsFromHash.set(store_key, encodedTs);
- } else if (
- BOOLEAN_VALUES === store_key &&
- previousParams[store_key] !== STORE_KEYS[store_key]
- ) {
- paramsFromHash.set(store_key, STORE_KEYS[store_key]);
- }
- });
- window.location.hash = paramsFromHash;
- }
- }, [STORE_KEYS]);
-}
-
-export async function decodeQuery(query, apiUrl) {
- await store.dispatch(loadLabels(apiUrl));
- const queryArr = query
- ?.match(/[^{\}]+(?=})/g, "$1")
- ?.map((m) => m.split(","))
- ?.flat();
- const labelsFromQuery = [];
- queryArr?.forEach((label) => {
- const regexQuery = label.match(/([^{}=,~!]+)/gm);
- if (!regexQuery) {
- return;
- }
- if (label.includes("!=")) {
- const labelObj = {
- name: regexQuery[0],
- values: [],
- };
- const valueObj = {
- name: regexQuery[1]?.replaceAll('"', ""),
- selected: true,
- inverted: true,
- };
- labelObj.values.push(valueObj);
- labelsFromQuery.push(labelObj);
- } else if (label.includes("=~")) {
- const values = regexQuery[1]?.split("|");
- const labelObj = {
- name: regexQuery[0],
- values: [],
- };
- values.forEach((value) => {
- const valueObj = {
- name: value?.replaceAll('"', ""),
- selected: true,
- inverted: false,
- };
- labelObj.values.push(valueObj);
- });
- labelsFromQuery.push(labelObj);
- } else {
- const labelObj = {
- name: regexQuery[0],
- values: [],
- };
- const valueObj = {
- name: regexQuery[1]?.replaceAll('"', ""),
- selected: true,
- inverted: false,
- };
- labelObj.values.push(valueObj);
- labelsFromQuery.push(labelObj);
- }
- });
- const newLabels = store.getState().labels;
- newLabels?.forEach((label) => {
- if (label.selected && label.values > 0) {
- label.selected = false;
- label.values.forEach((value) => {
- if (value.selected) {
- value.selected = false;
- }
- });
- }
- });
-
- if (labelsFromQuery.length > 0) {
- labelsFromQuery.forEach(async (label) => {
- const cleanLabel = newLabels?.find(
- (item) => item?.name === label?.name
- );
- if (!cleanLabel) {
- return;
- }
- await store.dispatch(
- loadLabelValues(cleanLabel, newLabels, apiUrl)
- );
- const labelsWithValues = store.getState().labels;
- const labelWithValues = labelsWithValues.find(
- (item) => item?.name === label?.name
- );
- let values = labelWithValues.values;
- values = label.values.concat(values);
- values = values
- .sort((a, b) => a.name.localeCompare(b.name))
- .filter((value, index, arr) => {
- return value.name !== arr[index - 1]?.name;
- })
- .filter((value) => !!value);
- labelWithValues.values = values;
- labelWithValues.selected = true;
- store.dispatch(setLabels(labelsWithValues));
- });
- }
-}
+import * as moment from "moment";
+import { useEffect } from "react";
+import { useDispatch, useSelector } from "react-redux";
+import { useLocation } from "react-router-dom";
+import {
+ setApiUrl,
+ setIsSubmit,
+ setLabels,
+ setQuery,
+ setQueryLimit,
+ setQueryStep,
+ setStartTime,
+ setStopTime,
+
+} from "../actions";
+
+
+import loadLabelValues from "../actions/loadLabelValues";
+import setFromTime from "../actions/setFromTime";
+import setIsEmbed from "../actions/setIsEmbed";
+import { setLabelsBrowserOpen } from "../actions/setLabelsBrowserOpen";
+import setToTime from "../actions/setToTime";
+import { setUrlLocation } from "../actions/setUrlLocation";
+import { setUrlQueryParams } from "../actions/setUrlQueryParams";
+import { environment } from "../environment/env.dev";
+import store from "../store/store";
+export function UpdateStateFromQueryParams() {
+ const { hash } = useLocation();
+
+ const dispatch = useDispatch();
+ const urlQueryParams = useSelector((store) => store.urlQueryParams);
+ const start = useSelector((store) => store.start);
+ const stop = useSelector((store) => store.stop);
+ const limit = useSelector((store) => store.limit);
+ const from = useSelector((store) => store.from);
+ const to = useSelector((store)=> store.to);
+ const step = useSelector((store) => store.step);
+ const labels = useSelector((store) => store.labels)
+ const apiUrl = useSelector((store) => store.apiUrl);
+ const isSubmit = useSelector((store) => store.isSubmit);
+ const isEmbed = useSelector((store) => store.isEmbed);
+ const query = useSelector((store) => store.query);
+
+ const STORE_KEYS = {
+ apiUrl,
+ query,
+ start,
+ limit,
+ step,
+ end: stop,
+ from,
+ to,
+ isSubmit,
+ isEmbed,
+ };
+
+ const STORE_ACTIONS = {
+ apiUrl: setApiUrl,
+ query: setQuery,
+ start: setStartTime,
+ limit: setQueryLimit,
+ step: setQueryStep,
+ end: setStopTime,
+ from: setFromTime,
+ to: setToTime,
+ isSubmit: setIsSubmit,
+ isEmbed: setIsEmbed,
+
+ };
+
+ const STRING_VALUES = ["limit", "step", "apiUrl"];
+
+ const QUERY_VALUE = "query";
+
+ const TIME_VALUES = ["start", "end",];
+
+ const BOOLEAN_VALUES = ["isSubmit", "isEmbed"];
+
+ const encodeTs = (ts) => {
+ return ts.getTime() + "000000";
+ };
+
+ useEffect(() => {
+ const urlFromHash = new URLSearchParams(hash.replace("#", ""));
+
+ // !if there is some params set them first on UI
+
+ if (hash.length > 0) {
+ const startParams = urlQueryParams;
+
+ for (let [key, value] of urlFromHash.entries()) {
+ startParams[key] = value;
+ }
+ if (Object.keys(startParams).length > 0) {
+ dispatch(setUrlQueryParams({ ...urlQueryParams, startParams }));
+
+ dispatch(setUrlLocation(hash));
+ Object.keys(startParams).forEach((param) => {
+ if (
+ STRING_VALUES.includes(param) &&
+ startParams[param] !== ""
+ ) {
+
+ dispatch(STORE_ACTIONS[param](startParams[param]));
+ if(param === 'apiUrl') {
+
+
+ }
+ } else if (
+ QUERY_VALUE === param &&
+ startParams[param] !== ""
+ ) {
+ const parsedQuery = decodeURIComponent(
+ startParams[param]
+ );
+ dispatch(STORE_ACTIONS[param](parsedQuery));
+ } else if (
+ TIME_VALUES.includes(param) &&
+ startParams[param] !== ""
+ ) {
+ const croppedTime = startParams[param] / 1000000;
+ const paramDate = new Date(
+ moment(croppedTime).format(
+ "YYYY-MM-DDTHH:mm:ss.SSSZ"
+ )
+ );
+ dispatch(STORE_ACTIONS[param](paramDate));
+ } else if (
+ BOOLEAN_VALUES.includes(param) &&
+ typeof param === "boolean"
+ ) {
+ dispatch(STORE_ACTIONS[param](startParams[param]));
+ }
+ if (QUERY_VALUE === param) {
+ }
+ });
+
+ decodeQuery(decodeURIComponent(startParams.query),apiUrl,labels);
+ dispatch(setLabelsBrowserOpen(false));
+
+ }
+ } else {
+ dispatch(setApiUrl(environment.apiUrl));
+
+ const allParams = STRING_VALUES.concat(TIME_VALUES);
+ allParams.push(QUERY_VALUE);
+ allParams.push(BOOLEAN_VALUES);
+ allParams.forEach((param) => {
+ if (STRING_VALUES.includes(param, "PARAM")) {
+ urlFromHash.set(param, STORE_KEYS[param].toString());
+ } else if (TIME_VALUES.includes(param)) {
+ const time_value = STORE_KEYS[param]?.getTime() * 1000000;
+
+ urlFromHash.set(param, time_value.toString());
+ } else if (QUERY_VALUE === param) {
+ const parsed = encodeURIComponent(
+ STORE_KEYS[param]
+ ).toString();
+ urlFromHash.set(param, parsed.toString());
+ } else if (
+ BOOLEAN_VALUES === param &&
+ typeof param === "boolean"
+ ) {
+ urlFromHash.set(param, param.toString());
+ }
+ });
+ const newQuery = STORE_KEYS[query];
+
+ decodeQuery(newQuery, apiUrl, labels);
+
+ window.location.hash = urlFromHash;
+ }
+ }, []);
+
+ useEffect(() => {
+ if (hash.length > 0) {
+ const paramsFromHash = new URLSearchParams(hash.replace("#", ""));
+ let previousParams = {};
+ for (let [key, value] of paramsFromHash.entries()) {
+ previousParams[key] = value;
+ }
+
+ Object.keys(STORE_KEYS).forEach((store_key) => {
+ if (
+ STRING_VALUES.includes(store_key) &&
+ previousParams[store_key] !== STORE_KEYS[store_key]
+ ) {
+ const updated = STORE_KEYS[store_key].toString().trim();
+ paramsFromHash.set(store_key, updated);
+ } else if (
+ QUERY_VALUE === store_key &&
+ previousParams[store_key] !==
+ encodeURIComponent(STORE_KEYS[store_key])
+ ) {
+ const queryUpdated = encodeURIComponent(
+ STORE_KEYS[store_key].toString()
+ );
+ paramsFromHash.set(store_key, queryUpdated);
+ } else if (
+ TIME_VALUES.includes(store_key) &&
+ previousParams[store_key] !==
+ encodeTs(STORE_KEYS[store_key])
+ ) {
+ const encodedTs = encodeTs(STORE_KEYS[store_key]);
+ paramsFromHash.set(store_key, encodedTs);
+ } else if (
+ BOOLEAN_VALUES === store_key &&
+ previousParams[store_key] !== STORE_KEYS[store_key]
+ ) {
+ paramsFromHash.set(store_key, STORE_KEYS[store_key]);
+ }
+ });
+ window.location.hash = paramsFromHash;
+ }
+ }, [STORE_KEYS]);
+}
+
+export function decodeQuery(query, apiUrl, labels=[]) {
+
+ const queryArr = query
+ ?.match(/[^{\}]+(?=})/g, "$1")
+ ?.map((m) => m.split(","))
+ ?.flat();
+ const labelsFromQuery = [];
+ queryArr?.forEach((label) => {
+ const regexQuery = label.match(/([^{}=,~!]+)/gm);
+ if (!regexQuery) {
+ return;
+ }
+ if (label.includes("!=")) {
+ const labelObj = {
+ name: regexQuery[0],
+ values: [],
+ };
+ const valueObj = {
+ name: regexQuery[1]?.replaceAll('"', ""),
+ selected: true,
+ inverted: true,
+ };
+ labelObj.values.push(valueObj);
+ labelsFromQuery.push(labelObj);
+ } else if (label.includes("=~")) {
+ const values = regexQuery[1]?.split("|");
+ const labelObj = {
+ name: regexQuery[0],
+ values: [],
+ };
+ values.forEach((value) => {
+ const valueObj = {
+ name: value?.replaceAll('"', ""),
+ selected: true,
+ inverted: false,
+ };
+ labelObj.values.push(valueObj);
+ });
+ labelsFromQuery.push(labelObj);
+ } else {
+ const labelObj = {
+ name: regexQuery[0],
+ values: [],
+ };
+ const valueObj = {
+ name: regexQuery[1]?.replaceAll('"', ""),
+ selected: true,
+ inverted: false,
+ };
+ labelObj.values.push(valueObj);
+ labelsFromQuery.push(labelObj);
+
+ }
+ });
+
+ const newLabels = labels
+
+ newLabels?.forEach((label) => {
+ if (label.selected && label.values > 0) {
+ label.selected = false;
+ label.values.forEach((value) => {
+ if (value.selected) {
+ value.selected = false;
+ }
+ });
+ }
+ });
+
+ if (labelsFromQuery.length > 0) {
+ labelsFromQuery.forEach(async (label) => {
+ const cleanLabel = newLabels?.find(
+ (item) => item?.name === label?.name
+ );
+ if (!cleanLabel) {
+ return;
+ }
+ await store.dispatch(
+ loadLabelValues(cleanLabel, newLabels, apiUrl)
+ );
+ const labelsWithValues = store.getState().labels;
+ const labelWithValues = labelsWithValues.find(
+ (item) => item?.name === label?.name
+ );
+ let values = labelWithValues.values;
+ values = label.values.concat(values);
+ values = values
+ .sort((a, b) => a.name.localeCompare(b.name))
+ .filter((value, index, arr) => {
+ return value.name !== arr[index - 1]?.name;
+ })
+ .filter((value) => !!value);
+ labelWithValues.values = values;
+ labelWithValues.selected = true;
+ store.dispatch(setLabels(labelsWithValues));
+ });
+ }
+}
diff --git a/src/helpers/error.interceptor.js b/src/helpers/error.interceptor.js
index 621ab2d5..1a4cbf46 100644
--- a/src/helpers/error.interceptor.js
+++ b/src/helpers/error.interceptor.js
@@ -1,21 +1,75 @@
-import store from '../store/store'
-import { errorHandler, setApiError } from "../actions/";
-const errorInterceptor = (axiosInstance) => {
- axiosInstance.interceptors.response.use(
- (response) => {
- //Response Successful
- return response;
- },
- (error) => {
- if (error?.response?.status === 401) {
- //Unauthorized
- //redirect to Login
- } else {
- const url = error?.response?.config?.url || ""
- const {message,status} = errorHandler(url, error)
- store.dispatch(setApiError(message || status + 'Error'))
- }
- }
- );
-};
-export default errorInterceptor;
+import store from '../store/store'
+import { errorHandler, createAlert } from "../actions/";
+import setApiWarning from '../actions/setApiWarning';
+
+const errorInterceptor = (axiosInstance) => {
+ axiosInstance.interceptors.response.use(
+ (response) => {
+
+ return response;
+ },
+
+ (error) => {
+
+ if (error.response) {
+
+ const handler = errorHandler(error)
+
+ if (error?.response?.status === 401) {
+
+ }
+ else if (handler.status === 500 && handler.type === 'labels') {
+
+ if (store.getState().notifications.length < 1 && store.getState().debugMode === true) {
+ store.dispatch(createAlert({
+ type: "error",
+ message: (handler.message + " for " + handler.type || handler.status + handler.type + 'Error')
+ }))
+ }
+ }
+
+ else if (handler.status === 404 && handler.type === 'labels') {
+
+ if (store.getState().notifications.length < 1) {
+ store.dispatch(createAlert({
+ type: "error",
+ message: (handler.message || handler.status + handler.type + 'Error')
+ }))
+ }
+
+ }
+ else {
+
+ if (store.getState().notifications.length < 1) {
+ store.dispatch(createAlert({
+ type: "error",
+ message: (handler.message + " for " + handler.type || handler.status + handler.type + 'Error')
+ }))
+ }
+ }
+ } else {
+
+ const error_parsed = JSON.parse(JSON.stringify(error));
+ const networkError = {
+ url: error_parsed.config.url,
+ message: error_parsed.message,
+ name: error_parsed.name
+ }
+
+ store.dispatch(setApiWarning({ type: 'labels', message: 'Labels not available', }))
+ const { url } = networkError
+
+ const apiWarning = store.getState().apiWarning
+ if (apiWarning && url.includes('query')) {
+ apiWarning.num++
+ store.dispatch(createAlert({
+ type: 'error',
+ message: `API not found, please adjust API URL`
+ }))
+ }
+
+ }
+ }
+ );
+};
+export default errorInterceptor;
diff --git a/src/hooks/useLabels.js b/src/hooks/useLabels.js
new file mode 100644
index 00000000..acee6c05
--- /dev/null
+++ b/src/hooks/useLabels.js
@@ -0,0 +1,47 @@
+
+import axios from "axios";
+export const sendLabels = async (apiUrl) => {
+ const origin = window.location.origin;
+ const url = apiUrl;
+ const headers = {
+ "Access-Control-Allow-Origin": origin,
+ "Access-Control-Allow-Headers": [
+ "Access-Control-Request-Headers",
+ "Content-Type",
+ ],
+ "Content-Type": "application/json",
+ };
+
+ const options = {
+ method: "GET",
+ headers: headers,
+ mode: "cors",
+ };
+
+ const res = await axios
+ .get(`${url.trim()}/loki/api/v1/labels`, options)
+ .then((response) => {
+ if (response) {
+ if (response?.data?.data === []) console.log("no labels found");
+ if (response?.data?.data?.length > 0) {
+ const labels = response?.data?.data.sort().map((label) => ({
+ name: label,
+ selected: false,
+ values: [],
+ }));
+
+
+ return labels || []
+
+ }
+ } else {
+
+ return []
+ }
+ })
+ .catch((e) => console.log(e));
+
+return res
+
+};
+
diff --git a/src/plugins/charts/UseTooltip.js b/src/plugins/charts/UseTooltip.js
index 284a4760..4f9ae024 100644
--- a/src/plugins/charts/UseTooltip.js
+++ b/src/plugins/charts/UseTooltip.js
@@ -1,114 +1,114 @@
-import * as moment from "moment";
-import {
- highlightItems,
- isFloat,
- isLAbelSelected,
- makeTolltipItems,
-} from "./helpers";
-
-const $q = window.jQuery;
-
-export default function UseTooltip(plot) {
- let previousPoint = null;
- $q("#tooltip").remove();
- previousPoint = null;
- $q(this).bind("plothover", function (event, pos, item) {
- let labels = ``;
- plot.unhighlight();
- if (item) {
- let plotData = plot.getData();
- const [plotTime, _] = item.datapoint;
- const selectedPlots = JSON.parse(
- localStorage.getItem("labelsSelected")
- );
- const itemValue = isFloat(parseFloat(item.datapoint[1]))
- ? parseFloat(item.datapoint[1]).toFixed(3)
- : item.datapoint[1];
-
- const isSelectedPlots = selectedPlots.length > 0;
- const labelsList = [];
- for (let i = 0; i < plotData.length; i++) {
- const plotIsVisible = isSelectedPlots
- ? isLAbelSelected(plotData[i])
- : true;
- const plotTimes = plotData[i].data
- .map((d) => d)
- .map((e) => e[0]);
- const plotPoints = plotData[i].data.map((d) => d);
-
- if (plotTimes.includes(plotTime) && plotIsVisible) {
- const plotIndex = plotTimes.indexOf(plotTime);
-
- const [_, value] = plotPoints.find(
- ([time, _]) => time === plotTime
- );
- labelsList.push({
- color: plotData[i].color,
- label: plotData[i].label,
- value: value,
- plot,
- plotIndex,
- item,
- i,
- });
- }
- }
-
- highlightItems(labelsList);
- const labelsFormatted = makeTolltipItems(labelsList);
- if (previousPoint !== item.datapoint) {
- previousPoint = item.datapoint;
- $q("#tooltip").remove();
- const tooltipTemplate = `
-
-
${moment(item.datapoint[0]).format(
- "YYYY-MM-DDTHH:mm:ss.SSSZ"
- )}
-
-
- Value: ${itemValue}
-
-
- ${labelsFormatted}
-
- `;
- const labelLength = item.series.label.length;
- showTooltip(
- item.pageX,
- item.pageY,
- tooltipTemplate,
- labelLength
- );
- }
- } else {
- $q("#tooltip").remove();
- previousPoint = null;
- }
- });
-}
-
-function showTooltip(x, y, contents, length) {
- let wWidth = window.innerWidth;
- let posX = x + 20;
- if (x * 2 > wWidth) {
- posX = x - length * 8;
- }
-
- // use ref for tooltip as made with chart!
-
- $q(`` + contents + `
`)
- .css({
- position: "absolute",
- display: "none",
- top: y,
- left: posX,
- padding: "6px",
- "font-size": "12px",
- size: "10",
- "border-radius": "6px 6px 6px 6px",
- "background-color": "#333",
- color: "#aaa",
- })
- .appendTo("body")
- .fadeIn(125);
-}
+import * as moment from "moment";
+import {
+ highlightItems,
+ isFloat,
+ isLAbelSelected,
+ makeTolltipItems,
+} from "./helpers";
+
+const $q = window.jQuery;
+
+export default function UseTooltip(plot) {
+ let previousPoint = null;
+ $q("#tooltip").remove();
+ previousPoint = null;
+ $q(this).bind("plothover", function (event, pos, item) {
+
+ plot.unhighlight();
+ if (item) {
+ let plotData = plot.getData();
+ const [plotTime, _] = item.datapoint;
+ const selectedPlots = JSON.parse(
+ localStorage.getItem("labelsSelected")
+ );
+ const itemValue = isFloat(parseFloat(item.datapoint[1]))
+ ? parseFloat(item.datapoint[1]).toFixed(3)
+ : item.datapoint[1];
+
+ const isSelectedPlots = selectedPlots.length > 0;
+ const labelsList = [];
+ for (let i = 0; i < plotData.length; i++) {
+ const plotIsVisible = isSelectedPlots
+ ? isLAbelSelected(plotData[i])
+ : true;
+ const plotTimes = plotData[i].data
+ .map((d) => d)
+ .map((e) => e[0]);
+ const plotPoints = plotData[i].data.map((d) => d);
+
+ if (plotTimes.includes(plotTime) && plotIsVisible) {
+ const plotIndex = plotTimes.indexOf(plotTime);
+
+ const [_, value] = plotPoints.find(
+ ([time, _]) => time === plotTime
+ );
+ labelsList.push({
+ color: plotData[i].color,
+ label: plotData[i].label,
+ value: value,
+ plot,
+ plotIndex,
+ item,
+ i,
+ });
+ }
+ }
+
+ highlightItems(labelsList);
+ const labelsFormatted = makeTolltipItems(labelsList);
+ if (previousPoint !== item.datapoint) {
+ previousPoint = item.datapoint;
+ $q("#tooltip").remove();
+ const tooltipTemplate = `
+
+
${moment(item.datapoint[0]).format(
+ "YYYY-MM-DDTHH:mm:ss.SSSZ"
+ )}
+
+
+ Value: ${itemValue}
+
+
+ ${labelsFormatted}
+
+ `;
+ const labelLength = item.series.label.length;
+ showTooltip(
+ item.pageX,
+ item.pageY,
+ tooltipTemplate,
+ labelLength
+ );
+ }
+ } else {
+ $q("#tooltip").remove();
+ previousPoint = null;
+ }
+ });
+}
+
+function showTooltip(x, y, contents, length) {
+ let wWidth = window.innerWidth;
+ let posX = x + 20;
+ if (x * 2 > wWidth) {
+ posX = x - length * 8;
+ }
+
+ // use ref for tooltip as made with chart!
+
+ $q(`` + contents + `
`)
+ .css({
+ position: "absolute",
+ display: "none",
+ top: y,
+ left: posX,
+ padding: "6px",
+ "font-size": "12px",
+ size: "10",
+ "border-radius": "6px 6px 6px 6px",
+ "background-color": "#333",
+ color: "#aaa",
+ })
+ .appendTo("body")
+ .fadeIn(125);
+}
diff --git a/src/plugins/charts/index.js b/src/plugins/charts/index.js
index 47f773d8..44bcf4bb 100644
--- a/src/plugins/charts/index.js
+++ b/src/plugins/charts/index.js
@@ -1,327 +1,327 @@
-import "./jquery-loader";
-import ReactFlot from "react-flot";
-import "react-flot/flot/jquery.flot.time.min";
-
-import "react-flot/flot/jquery.flot.selection.min";
-
-import "react-flot/flot/jquery.flot.crosshair.min";
-
-import loadLogs from "../../actions/loadLogs";
-import { useDispatch } from "react-redux";
-import { setStartTime, setStopTime, setTimeRangeLabel } from "../../actions";
-import * as moment from "moment";
-import { useState, useEffect, useRef } from "react";
-import { format } from "date-fns";
-import ChartTools from "./ChartTools";
-import ChartLabelsList from "./ChartLabelList";
-import {
- getTypeFromLocal,
- formatTs,
- getSeriesFromChartType,
- setChartTypeSeries,
- setTypeToLocal,
- formatDateRange,
- formatLabel,
- getNewData,
-} from "./helpers";
-import UseTooltip from "./UseTooltip";
-import { CHART_OPTIONS } from "./consts";
-
-export default function ClokiChart({ matrixData }) {
- const chartRef = useRef(null);
-
- const $q = window.jQuery;
- $q.fn.UseTooltip = UseTooltip;
-
- const dispatch = useDispatch();
- const [isSpliced, setIsSpliced] = useState(true);
- const [chartData, setChartData] = useState(getDataParsed(isSpliced));
- const [allData] = useState(getDataParsed(false));
- const [labels, setLabels] = useState([]);
- const [element, setElement] = useState(chartRef.current);
-
- const [chartOptions, setChartOptions] = useState(CHART_OPTIONS);
-
- const [chartType, setChartType] = useState(getTypeFromLocal() || "line");
-
- function getDataParsed(spliced) {
- const parsed = [...matrixData].map((m) => ({
- data: formatTs(m.values),
- label: formatLabel(m.metric),
- isVisible: true,
- id: m.id,
- }));
-
- if (spliced) {
- const splicedData = parsed.splice(0, 20);
- return splicedData;
- } else {
- return parsed;
- }
- }
-
- /**
- *
- * Set chart types
- */
-
- function plotChartData(data, type, element) {
- const chartSeries = setChartTypeSeries(type);
- const { timeformat, min, max } = formatDateRange(data);
- return $q.plot(
- element,
- data,
- $q.extend(true, {}, chartOptions, {
- ...chartSeries,
- xaxis: { timeformat, min, max, },
- })
- );
- }
-
- function onSetChartType(type) {
- const element = $q(chartRef.current);
- const data = isSpliced ? chartData : allData;
- const newData = getNewData(data, type);
-
- try {
- let plot = plotChartData(newData, type, element);
- const colorLabels = plot.getData();
- setLabels(colorLabels);
- $q(chartRef.current).UseTooltip(plot);
- setChartType(type);
- setTypeToLocal(type);
- } catch (e) {
- console.log(data, e);
- }
- }
-
- function setRanges(event, ranges) {
- const element = $q(chartRef.current);
- const data = isSpliced ? chartData : allData;
- event.preventDefault();
-
- let newData = [];
- const lSelected =
- JSON.parse(localStorage.getItem("labelsSelected")) || [];
- if (lSelected.length > 0) {
- const { lines, bars, points } = getSeriesFromChartType(chartType);
- const ids = lSelected.map((m) => m.id);
- const dataMapped = data.map((series) => {
- if (!ids.includes(series.id)) {
- return {
- ...series,
- lines: { ...series.lines, show: false },
- bars: { ...series.bars, show: false },
- points: { ...series.points, show: false },
- isVisible: false,
- };
- } else {
- return {
- ...series,
- bars,
- lines,
- points,
- isVisible: true,
- };
- }
- });
- newData = dataMapped;
- } else {
- newData = data;
- }
-
- try {
- let plot = $q.plot(
- element,
- newData,
- $q.extend(true, {}, chartOptions, {
- xaxis: {
- min: ranges.xaxis.from - 100000,
- max: ranges.xaxis.to + 100000,
- timeformat: formatDateRange(newData).timerange,
-
- },
- })
- );
- $q(chartRef.current).UseTooltip(plot);
- setTimeout(() => {
- const fromTime = ranges.xaxis.from;
- const toTime = ranges.xaxis.to;
-
- const fromTs = new Date(
- moment(parseInt(fromTime)).format(
- "YYYY-MM-DDTHH:mm:ss.SSSZ"
- )
- );
- const toTs = new Date(
- moment(parseInt(toTime)).format("YYYY-MM-DDTHH:mm:ss.SSSZ")
- );
- const fromLabel = format(fromTs, "yyyy/MM/dd HH:mm:ss");
- const toLabel = format(toTs, "yyyy/MM/dd HH:mm:ss");
-
- const timeRangeLabel = `${fromLabel}-${toLabel}`;
- dispatch(setStopTime(toTs));
- dispatch(setStartTime(fromTs));
-
- dispatch(setTimeRangeLabel(timeRangeLabel));
- dispatch(loadLogs());
- }, 400);
- } catch (e) {
- console.log("error on chart redraw", e);
- }
- }
-
- /**
- *
- *Isolate Series clicking label
- */
-
- function onLabelClick(e, v) {
- let newList = [];
- const lSelected =
- JSON.parse(localStorage.getItem("labelsSelected")) || [];
-
- if (lSelected.some(({ id }) => id === v.id)) {
- const filtered = lSelected.filter((f) => f.id !== v.id);
- localStorage.setItem("labelsSelected", JSON.stringify(filtered));
- newList = filtered;
- } else {
- newList = lSelected.concat(v);
- localStorage.setItem("labelsSelected", JSON.stringify(newList));
- }
-
- if (newList.length > 0) {
- const ids = newList.map((m) => m.id);
- const { lines, bars, points } = getSeriesFromChartType(chartType);
- let dataSelected = e.map((series) => {
- if (!ids.includes(series.id)) {
- return {
- ...series,
- lines: { ...series.lines, show: false },
- bars: { ...series.bars, show: false },
- points: { ...series.points, show: false },
- };
- } else {
- return {
- ...series,
- bars,
- lines,
- points,
- };
- }
- });
- const { timeformat, min, max } = formatDateRange(dataSelected);
-
- let plot = $q.plot(
- element,
- dataSelected,
-
- $q.extend(true, {}, chartOptions, {
- series: getSeriesFromChartType(chartType),
- xaxis: { timeformat, min, max, },
- })
- );
-
- const colorLabels = plot.getData();
- setLabels(colorLabels);
- $q(chartRef.current).UseTooltip(plot);
- } else {
- const data = isSpliced ? chartData : allData;
- const { lines, bars, points } = getSeriesFromChartType(chartType);
- const newData = data.map((series) => {
- return {
- ...series,
- bars,
- lines,
- points,
- isVisible: true,
- };
- });
- const { timeformat, min, max } = formatDateRange(newData);
-
- let plot = $q.plot(
- element,
- newData,
- $q.extend(true, {}, chartOptions, {
- series: getSeriesFromChartType(chartType),
- xaxis: { timeformat, min, max, },
- })
- );
-
- const colorLabels = plot.getData();
- setLabels(colorLabels);
- $q(chartRef.current).UseTooltip(plot);
- }
- }
-
- useEffect(() => {
- setElement(chartRef.current);
- setLabels(chartData.map(({ label }) => label));
- $q(chartRef.current).bind("plotselected", setRanges);
- setChartData(getDataParsed(isSpliced));
- localStorage.setItem("labelsSelected", JSON.stringify([]));
- }, []);
-
- useEffect(() => {
- setChartOptions(chartOptions);
- setElement(chartRef.current);
- drawChartFromData();
- }, [matrixData, isSpliced]);
-
- function drawChartFromData() {
- const data = isSpliced ? chartData : allData;
- const element = $q(chartRef.current);
- let newData = getNewData(data);
- try {
- const { timeformat, min, max } = formatDateRange(newData);
- let plot = $q.plot(
- element,
- newData,
- $q.extend(true, {}, chartOptions, {
- series: getSeriesFromChartType(chartType),
- xaxis: { timeformat, min, max, },
- })
- );
-
- const colorLabels = plot.getData();
- setLabels(colorLabels);
- $q(chartRef.current).UseTooltip(plot);
- } catch (e) {
- console.log(e);
- }
- }
-
- const handleNoLimitData = (e) => {
- setIsSpliced(false);
- };
-
- const handleLimitData = (e) => {
- setIsSpliced(true);
- };
-
- return (
-
- );
-}
+import "./jquery-loader";
+import ReactFlot from "react-flot";
+import "react-flot/flot/jquery.flot.time.min";
+
+import "react-flot/flot/jquery.flot.selection.min";
+
+import "react-flot/flot/jquery.flot.crosshair.min";
+
+import loadLogs from "../../actions/loadLogs";
+import { useDispatch } from "react-redux";
+import { setStartTime, setStopTime, setTimeRangeLabel } from "../../actions";
+import * as moment from "moment";
+import { useState, useEffect, useRef } from "react";
+import { format } from "date-fns";
+import ChartTools from "./ChartTools";
+import ChartLabelsList from "./ChartLabelList";
+import {
+ getTypeFromLocal,
+ formatTs,
+ getSeriesFromChartType,
+ setChartTypeSeries,
+ setTypeToLocal,
+ formatDateRange,
+ formatLabel,
+ getNewData,
+} from "./helpers";
+import UseTooltip from "./UseTooltip";
+import { CHART_OPTIONS } from "./consts";
+
+export default function ClokiChart({ matrixData }) {
+ const chartRef = useRef(null);
+
+ const $q = window.jQuery;
+ $q.fn.UseTooltip = UseTooltip;
+
+ const dispatch = useDispatch();
+ const [isSpliced, setIsSpliced] = useState(true);
+ const [chartData, setChartData] = useState(getDataParsed(isSpliced));
+ const [allData] = useState(getDataParsed(false));
+ const [labels, setLabels] = useState([]);
+ const [element, setElement] = useState(chartRef.current);
+
+ const [chartOptions, setChartOptions] = useState(CHART_OPTIONS);
+
+ const [chartType, setChartType] = useState(getTypeFromLocal() || "line");
+
+ function getDataParsed(spliced) {
+ const parsed = [...matrixData].map((m) => ({
+ data: formatTs(m.values),
+ label: formatLabel(m.metric),
+ isVisible: true,
+ id: m.id,
+ }));
+
+ if (spliced) {
+ const splicedData = parsed.splice(0, 20);
+ return splicedData;
+ } else {
+ return parsed;
+ }
+ }
+
+ /**
+ *
+ * Set chart types
+ */
+
+ function plotChartData(data, type, element) {
+ const chartSeries = setChartTypeSeries(type);
+ const { timeformat, min, max } = formatDateRange(data);
+ return $q.plot(
+ element,
+ data,
+ $q.extend(true, {}, chartOptions, {
+ ...chartSeries,
+ xaxis: { timeformat, min, max, },
+ })
+ );
+ }
+
+ function onSetChartType(type) {
+ const element = $q(chartRef.current);
+ const data = isSpliced ? chartData : allData;
+ const newData = getNewData(data, type);
+
+ try {
+ let plot = plotChartData(newData, type, element);
+ const colorLabels = plot.getData();
+ setLabels(colorLabels);
+ $q(chartRef.current).UseTooltip(plot);
+ setChartType(type);
+ setTypeToLocal(type);
+ } catch (e) {
+ console.log(data, e);
+ }
+ }
+
+ function setRanges(event, ranges) {
+ const element = $q(chartRef.current);
+ const data = isSpliced ? chartData : allData;
+ event.preventDefault();
+
+ let newData = [];
+ const lSelected =
+ JSON.parse(localStorage.getItem("labelsSelected")) || [];
+ if (lSelected.length > 0) {
+ const { lines, bars, points } = getSeriesFromChartType(chartType);
+ const ids = lSelected.map((m) => m.id);
+ const dataMapped = data.map((series) => {
+ if (!ids.includes(series.id)) {
+ return {
+ ...series,
+ lines: { ...series.lines, show: false },
+ bars: { ...series.bars, show: false },
+ points: { ...series.points, show: false },
+ isVisible: false,
+ };
+ } else {
+ return {
+ ...series,
+ bars,
+ lines,
+ points,
+ isVisible: true,
+ };
+ }
+ });
+ newData = dataMapped;
+ } else {
+ newData = data;
+ }
+
+ try {
+ let plot = $q.plot(
+ element,
+ newData,
+ $q.extend(true, {}, chartOptions, {
+ xaxis: {
+ min: ranges.xaxis.from - 100000,
+ max: ranges.xaxis.to + 100000,
+ timeformat: formatDateRange(newData).timerange,
+
+ },
+ })
+ );
+ $q(chartRef.current).UseTooltip(plot);
+ setTimeout(() => {
+ const fromTime = ranges.xaxis.from;
+ const toTime = ranges.xaxis.to;
+
+ const fromTs = new Date(
+ moment(parseInt(fromTime)).format(
+ "YYYY-MM-DDTHH:mm:ss.SSSZ"
+ )
+ );
+ const toTs = new Date(
+ moment(parseInt(toTime)).format("YYYY-MM-DDTHH:mm:ss.SSSZ")
+ );
+ const fromLabel = format(fromTs, "yyyy/MM/dd HH:mm:ss");
+ const toLabel = format(toTs, "yyyy/MM/dd HH:mm:ss");
+
+ const timeRangeLabel = `${fromLabel}-${toLabel}`;
+ dispatch(setStopTime(toTs));
+ dispatch(setStartTime(fromTs));
+
+ dispatch(setTimeRangeLabel(timeRangeLabel));
+ dispatch(loadLogs());
+ }, 400);
+ } catch (e) {
+ console.log("error on chart redraw", e);
+ }
+ }
+
+ /**
+ *
+ *Isolate Series clicking label
+ */
+
+ function onLabelClick(e, v) {
+ let newList = [];
+ const lSelected =
+ JSON.parse(localStorage.getItem("labelsSelected")) || [];
+
+ if (lSelected.some(({ id }) => id === v.id)) {
+ const filtered = lSelected.filter((f) => f.id !== v.id);
+ localStorage.setItem("labelsSelected", JSON.stringify(filtered));
+ newList = filtered;
+ } else {
+ newList = lSelected.concat(v);
+ localStorage.setItem("labelsSelected", JSON.stringify(newList));
+ }
+
+ if (newList.length > 0) {
+ const ids = newList.map((m) => m.id);
+ const { lines, bars, points } = getSeriesFromChartType(chartType);
+ let dataSelected = e.map((series) => {
+ if (!ids.includes(series.id)) {
+ return {
+ ...series,
+ lines: { ...series.lines, show: false },
+ bars: { ...series.bars, show: false },
+ points: { ...series.points, show: false },
+ };
+ } else {
+ return {
+ ...series,
+ bars,
+ lines,
+ points,
+ };
+ }
+ });
+ const { timeformat, min, max } = formatDateRange(dataSelected);
+
+ let plot = $q.plot(
+ element,
+ dataSelected,
+
+ $q.extend(true, {}, chartOptions, {
+ series: getSeriesFromChartType(chartType),
+ xaxis: { timeformat, min, max, },
+ })
+ );
+
+ const colorLabels = plot.getData();
+ setLabels(colorLabels);
+ $q(chartRef.current).UseTooltip(plot);
+ } else {
+ const data = isSpliced ? chartData : allData;
+ const { lines, bars, points } = getSeriesFromChartType(chartType);
+ const newData = data.map((series) => {
+ return {
+ ...series,
+ bars,
+ lines,
+ points,
+ isVisible: true,
+ };
+ });
+ const { timeformat, min, max } = formatDateRange(newData);
+
+ let plot = $q.plot(
+ element,
+ newData,
+ $q.extend(true, {}, chartOptions, {
+ series: getSeriesFromChartType(chartType),
+ xaxis: { timeformat, min, max, },
+ })
+ );
+
+ const colorLabels = plot.getData();
+ setLabels(colorLabels);
+ $q(chartRef.current).UseTooltip(plot);
+ }
+ }
+
+ useEffect(() => {
+ setElement(chartRef.current);
+ setLabels(chartData.map(({ label }) => label));
+ $q(chartRef.current).bind("plotselected", setRanges);
+ setChartData(getDataParsed(isSpliced));
+ localStorage.setItem("labelsSelected", JSON.stringify([]));
+ }, []);
+
+ useEffect(() => {
+ setChartOptions(chartOptions);
+ setElement(chartRef.current);
+ drawChartFromData();
+ }, [matrixData, isSpliced]);
+
+ function drawChartFromData() {
+ const data = isSpliced ? chartData : allData;
+ const element = $q(chartRef.current);
+ let newData = getNewData(data);
+ try {
+ const { timeformat, min, max } = formatDateRange(newData);
+ let plot = $q.plot(
+ element,
+ newData,
+ $q.extend(true, {}, chartOptions, {
+ series: getSeriesFromChartType(chartType),
+ xaxis: { timeformat, min, max, },
+ })
+ );
+
+ const colorLabels = plot.getData();
+ setLabels(colorLabels);
+ $q(chartRef.current).UseTooltip(plot);
+ } catch (e) {
+ console.log(e);
+ }
+ }
+
+ const handleNoLimitData = (e) => {
+ setIsSpliced(false);
+ };
+
+ const handleLimitData = (e) => {
+ setIsSpliced(true);
+ };
+
+ return (
+
+ );
+}
diff --git a/src/plugins/queryeditor/index.js b/src/plugins/queryeditor/index.js
index 8e077548..729c88f4 100644
--- a/src/plugins/queryeditor/index.js
+++ b/src/plugins/queryeditor/index.js
@@ -1,163 +1,163 @@
-import styled from "@emotion/styled";
-import { css } from "@emotion/css";
-import React, { useCallback, useState, useMemo, useEffect } from "react";
-
-import { createEditor, Text } from "slate";
-import { Slate, Editable, withReact } from "slate-react";
-import { withHistory } from "slate-history";
-import Prism from "prismjs";
-import "prismjs/components/prism-promql";
-import "prismjs/components/prism-sql";
-import darkTheme from "../../theme/dark";
-const theme = darkTheme;
-const CustomEditor = styled(Editable)`
- flex: 1;
- background: ${theme.inputBg};
- color: ${theme.textColor};
- padding: 4px 8px;
- font-size: 1em;
- font-family: monospace;
- margin: 0px 5px;
- border-radius: 3px;
- line-height: 1.5;
- line-break: anywhere;
-`;
-
-const QueryBar = styled.div`
- display: flex;
- align-items: center;
- flex: 1;
- max-width: 100%;
-`;
-
-function Leaf({ attributes, children, leaf }) {
- return (
-
- {children}
-
- );
-}
-
-export default function QueryEditor({ onQueryChange, value, onKeyDown }) {
- const renderLeaf = useCallback((props) => , []);
-
- const editor = useMemo(() => withHistory(withReact(createEditor())), []);
- // Keep track of state for the value of the editor.
-
- const [language] = useState("sql");
-
- const decorate = useCallback(
- ([node, path]) => {
- const ranges = [];
- if (!Text.isText(node) || node.length < 1) {
- return ranges;
- }
- const tokens = Prism.tokenize(node.text, Prism.languages[language]);
- let start = 0;
- for (const token of tokens) {
- const length = getLength(token);
- const end = start + length;
-
- if (typeof token !== "string") {
- ranges.push({
- [token.type]: true,
- anchor: { path, offset: start },
- focus: { path, offset: end },
- });
- }
- start = end;
- }
- return ranges;
- },
- [language]
- );
-
- function getLength(token) {
- if (typeof token === "string") {
- return token.length;
- } else if (typeof token.content === "string") {
- return token.content.length;
- } else {
- return token.content.reduce((l, t) => l + getLength(t), 0);
- }
- }
-
- const [editorValue, setEditorValue] = useState(value);
-
- useEffect(() => {
- setEditorValue(value);
- }, []);
- useEffect(() => {
- setEditorValue(value);
- editor.children = value;
- }, [value]);
- return (
-
- {/* */}
-
-
-
-
- );
-}
+import styled from "@emotion/styled";
+import { css } from "@emotion/css";
+import React, { useCallback, useState, useMemo, useEffect } from "react";
+
+import { createEditor, Text } from "slate";
+import { Slate, Editable, withReact } from "slate-react";
+import { withHistory } from "slate-history";
+import Prism from "prismjs";
+import "prismjs/components/prism-promql";
+import "prismjs/components/prism-sql";
+import darkTheme from "../../theme/dark";
+const theme = darkTheme;
+const CustomEditor = styled(Editable)`
+ flex: 1;
+ background: ${theme.inputBg};
+ color: ${theme.textColor};
+ padding: 4px 8px;
+ font-size: 1em;
+ font-family: monospace;
+ margin: 0px 5px;
+ border-radius: 3px;
+ line-height: 1.5;
+ line-break: anywhere;
+`;
+
+const QueryBar = styled.div`
+ display: flex;
+ align-items: center;
+ flex: 1;
+ max-width: 100%;
+`;
+
+function Leaf({ attributes, children, leaf }) {
+ return (
+
+ {children}
+
+ );
+}
+
+export default function QueryEditor({ onQueryChange, value, onKeyDown }) {
+ const renderLeaf = useCallback((props) => , []);
+
+ const editor = useMemo(() => withHistory(withReact(createEditor())), []);
+ // Keep track of state for the value of the editor.
+
+ const [language] = useState("sql");
+
+ const decorate = useCallback(
+ ([node, path]) => {
+ const ranges = [];
+ if (!Text.isText(node) || node.length < 1) {
+ return ranges;
+ }
+ const tokens = Prism.tokenize(node.text, Prism.languages[language]);
+ let start = 0;
+ for (const token of tokens) {
+ const length = getLength(token);
+ const end = start + length;
+
+ if (typeof token !== "string") {
+ ranges.push({
+ [token.type]: true,
+ anchor: { path, offset: start },
+ focus: { path, offset: end },
+ });
+ }
+ start = end;
+ }
+ return ranges;
+ },
+ [language]
+ );
+
+ function getLength(token) {
+ if (typeof token === "string") {
+ return token.length;
+ } else if (typeof token.content === "string") {
+ return token.content.length;
+ } else {
+ return token.content.reduce((l, t) => l + getLength(t), 0);
+ }
+ }
+
+ const [editorValue, setEditorValue] = useState(value);
+
+ useEffect(() => {
+ setEditorValue(value);
+ }, []);
+ useEffect(() => {
+ setEditorValue(value);
+ editor.children = value;
+ }, [value]);
+ return (
+
+ {/* */}
+
+
+
+
+ );
+}
diff --git a/src/plugins/queryhistory/styled/index.js b/src/plugins/queryhistory/styled/index.js
index c32db5de..71ba58b6 100644
--- a/src/plugins/queryhistory/styled/index.js
+++ b/src/plugins/queryhistory/styled/index.js
@@ -1,311 +1,311 @@
-import styled from "@emotion/styled";
-import { buttonUnstyledClasses } from "@mui/base/ButtonUnstyled";
-import TabUnstyled, { tabUnstyledClasses } from "@mui/base/TabUnstyled";
-import DisplaySettingsIcon from "@mui/icons-material/DisplaySettings";
-import HistoryIcon from "@mui/icons-material/History";
-import SearchIcon from "@mui/icons-material/Search";
-import TabsListUnstyled from "@mui/base/TabsListUnstyled";
-import TabPanelUnstyled from "@mui/base/TabPanelUnstyled";
-import StarBorderIcon from "@mui/icons-material/StarBorder";
-import LinkIcon from "@mui/icons-material/Link";
-import { createTheme } from "@mui/material";
-import darkTheme from "../../../theme/dark";
-
-const dTheme = darkTheme;
-export const Tab = styled(TabUnstyled)`
- color: ${dTheme.buttonText};
- cursor: pointer;
- font-size: 13px;
- background-color: transparent;
- padding: 6px 10px;
- border: none;
- border-radius: 3px 3px 0px 0px;
- display: flex;
- justify-content: center;
- align-items: center;
- border-bottom: 1px solid transparent;
- transition: 0.2s all;
-
- &:hover {
- background-color: ${dTheme.buttonHover};
- }
-
- &:focus {
- color: #aaa;
- border-radius: 3px 3px 0px 0px;
-
- outline-offset: 2px;
- }
-
- &.${tabUnstyledClasses.selected} {
- border-bottom: 1px solid ${dTheme.primaryDark};
- }
-
- &.${buttonUnstyledClasses.disabled} {
- opacity: 0.5;
- cursor: not-allowed;
- }
- @media screen and (max-width: 360px) {
- span {
- display: none;
- }
- padding: 5px 20px;
- }
-`;
-
-export const TabHistoryIcon = styled(HistoryIcon)`
- height: 16px;
- width: 16px;
- margin-right: 3px;
-`;
-
-export const TabHistoryStarIcon = styled(StarBorderIcon)`
- height: 16px;
- width: 16px;
- margin-right: 3px;
-`;
-export const TabHistorySettingIcon = styled(DisplaySettingsIcon)`
- height: 16px;
- width: 16px;
- margin-right: 3px;
-`;
-
-export const TabHistoryLinkIcon = styled(LinkIcon)`
- height: 16px;
- width: 16px;
- margin-right: 3px;
-`;
-
-export const TabHistorySearchIcon = styled(SearchIcon)`
- height: 21px;
- width: 16px;
- padding: 0px 3px;
- border-radius: 3px 0px 0px 3px;
- background: ${dTheme.inputBg};
-`;
-
-export const TabHeaderContainer = styled.div`
- padding: 0px 15px;
- font-size: 13px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- background: #7b7b7b1f;
- height: 37px;
-`;
-export const TabPanel = styled(TabPanelUnstyled)`
- width: 100%;
-`;
-
-export const TabsList = styled(TabsListUnstyled)`
- min-width: 320px;
- border-bottom: 4px solid ${dTheme.inputBg};
- display: flex;
- align-items: center;
- align-content: space-between;
-`;
-
-export const EmptyHistory = styled.div`
- display: flex;
- align-items: center;
- justify-content: center;
- color: ${dTheme.buttonText};
- font-size: 14px;
- flex: 1;
- padding: 20px;
- height: 50%;
-`;
-
-export const QueryHistoryContainer = styled.div`
- height: 250px;
- overflow-y: auto;
- &.starredCont {
- height: 210px;
- }
- &::-webkit-scrollbar {
- width: 10px;
- background: black;
- }
-
-
-`;
-
-export const HistoryButton = styled.button`
- padding: 3px 6px;
- background: ${dTheme.buttonDefault};
- border-radius: 3px;
- border: none;
- color: ${dTheme.buttonText};
- display: flex;
- align-items: center;
- justify-content: center;
- margin: 0px 6px;
- cursor: pointer;
- min-height: 20px;
-`;
-
-export const SettingItemContainer = styled.div`
- height: 100px;
- width: 240px;
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- padding: 20px;
- background: ${dTheme.viewBg};
- margin: 10px;
- border-radius: 3px;
- & div {
- font-size: 15px;
- color: orange;
- line-height: 1.5;
- }
- & small {
- font-size: 12px;
- color: ${dTheme.buttonText};
- line-height: 1.5;
- margin-bottom:10px;
- }
-`;
-export const SubmitButton = styled(HistoryButton)`
- background: ${dTheme.primaryDark};
- color: ${dTheme.buttonText};
- white-space: nowrap;
- .open-icon {
- display: none;
- }
- .open-text {
- display: flex;
- }
- @media screen and (max-width: 864px) {
- .open-icon {
- display: flex;
- }
- .open-text {
- display: none;
- }
- }
-`;
-
-export const ClearHistoryButton = styled(HistoryButton)`
- font-weight: bold;
- padding: 10px 20px;
- background: ${dTheme.primaryDark};
- margin: 0;
- width: 100%;
- white-space: nowrap;
-`;
-export const StyledCloseButton = styled(HistoryButton)`
- background: none;
- color: ${dTheme.buttonText};
- position: absolute;
- right: 0;
-`;
-
-export const DialogCancelButton = styled(HistoryButton)`
- background: ${dTheme.buttonDefault};
- padding: 8px 16px;
-`;
-export const DialogConfirmButton = styled(HistoryButton)`
- background: ${dTheme.primaryDark};
- padding: 8px 16px;
-`;
-
-export const FilterInput = styled.input`
- color: ${dTheme.buttonText};
- background: ${dTheme.inputBg};
- border: none;
- height: 21px;
- margin: 0px 10px 0px 0px;
- padding: 0px;
- font-size: 13px;
- border-radius: 0px 3px 3px 0px;
- font-family: monospace;
- font-size: 12px;
- &:focus {
- outline: none;
- color: ${dTheme.inputTextFocus};
- }
-`;
-export const RowData = styled.span`
- flex: 1;
- font-family: "monospace";
- font-size: "13px";
- color: ${dTheme.buttonText};
- white-space: nowrap;
- padding: 4px 0px;
- overflow: hidden;
- text-overflow: ellipsis;
-`;
-
-export const LinkParams = styled.div`
- display: flex;
- flex: 1;
- justify-content: space-between;
- .open-button {
- display: none;
- }
- .inline-params {
- align-items: center;
- display: ${(props) => (props.open ? "none" : "grid")};
- flex: 1;
- grid-template-columns: 1fr 0.25fr 0.25fr auto;
- margin-right: 5px;
- }
-
- .open-button {
- display: flex;
- color: ${dTheme.buttonText};
- background: none;
- border: none;
- }
- .block-params {
- display: ${(props) => (props.open ? "flex" : "none")};
- flex-direction: column;
- flex: 1;
- p {
- display: flex;
- align-items: center;
- justify-content: space-between;
- flex: 1;
- border-bottom: 1px solid ${dTheme.buttonDefault};
- margin-bottom: 4px;
- padding-bottom: 2px;
- span {
- margin-left: 3px;
- }
- }
- }
- @media screen and (max-width: 864px) {
- .inline-params {
- display: none;
- }
- }
-`;
-
-export const HistoryRow = styled.div`
- padding: 5px 0px;
- padding-left: 10px;
- background:#7b7b7b1f;
- margin: 5px;
- border-radius: 3px;
- font-size: 13px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- //height: 30px;
-`;
-export const TimeSpan = styled.div`
- @media screen and (max-width: 1370px) {
- display: none;
- }
-`;
-
-export const theme = createTheme({
- palette: {
- mode: "dark",
- primary: {
- main: dTheme.buttonText,
- background: dTheme.buttonHover,
- },
- },
-});
+import styled from "@emotion/styled";
+import { buttonUnstyledClasses } from "@mui/base/ButtonUnstyled";
+import TabUnstyled, { tabUnstyledClasses } from "@mui/base/TabUnstyled";
+import DisplaySettingsIcon from "@mui/icons-material/DisplaySettings";
+import HistoryIcon from "@mui/icons-material/History";
+import SearchIcon from "@mui/icons-material/Search";
+import TabsListUnstyled from "@mui/base/TabsListUnstyled";
+import TabPanelUnstyled from "@mui/base/TabPanelUnstyled";
+import StarBorderIcon from "@mui/icons-material/StarBorder";
+import LinkIcon from "@mui/icons-material/Link";
+import { createTheme } from "@mui/material";
+import darkTheme from "../../../theme/dark";
+
+const dTheme = darkTheme;
+export const Tab = styled(TabUnstyled)`
+ color: ${dTheme.buttonText};
+ cursor: pointer;
+ font-size: 13px;
+ background-color: transparent;
+ padding: 6px 10px;
+ border: none;
+ border-radius: 3px 3px 0px 0px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border-bottom: 1px solid transparent;
+ transition: 0.2s all;
+
+ &:hover {
+ background-color: ${dTheme.buttonHover};
+ }
+
+ &:focus {
+ color: #aaa;
+ border-radius: 3px 3px 0px 0px;
+
+ outline-offset: 2px;
+ }
+
+ &.${tabUnstyledClasses.selected} {
+ border-bottom: 1px solid ${dTheme.primaryDark};
+ }
+
+ &.${buttonUnstyledClasses.disabled} {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
+ @media screen and (max-width: 360px) {
+ span {
+ display: none;
+ }
+ padding: 5px 20px;
+ }
+`;
+
+export const TabHistoryIcon = styled(HistoryIcon)`
+ height: 16px;
+ width: 16px;
+ margin-right: 3px;
+`;
+
+export const TabHistoryStarIcon = styled(StarBorderIcon)`
+ height: 16px;
+ width: 16px;
+ margin-right: 3px;
+`;
+export const TabHistorySettingIcon = styled(DisplaySettingsIcon)`
+ height: 16px;
+ width: 16px;
+ margin-right: 3px;
+`;
+
+export const TabHistoryLinkIcon = styled(LinkIcon)`
+ height: 16px;
+ width: 16px;
+ margin-right: 3px;
+`;
+
+export const TabHistorySearchIcon = styled(SearchIcon)`
+ height: 21px;
+ width: 16px;
+ padding: 0px 3px;
+ border-radius: 3px 0px 0px 3px;
+ background: ${dTheme.inputBg};
+`;
+
+export const TabHeaderContainer = styled.div`
+ padding: 0px 15px;
+ font-size: 13px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ background: #7b7b7b1f;
+ height: 37px;
+`;
+export const TabPanel = styled(TabPanelUnstyled)`
+ width: 100%;
+`;
+
+export const TabsList = styled(TabsListUnstyled)`
+ min-width: 320px;
+ border-bottom: 4px solid ${dTheme.inputBg};
+ display: flex;
+ align-items: center;
+ align-content: space-between;
+`;
+
+export const EmptyHistory = styled.div`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: ${dTheme.buttonText};
+ font-size: 14px;
+ flex: 1;
+ padding: 20px;
+ height: 50%;
+`;
+
+export const QueryHistoryContainer = styled.div`
+ height: 250px;
+ overflow-y: auto;
+ &.starredCont {
+ height: 210px;
+ }
+ &::-webkit-scrollbar {
+ width: 10px;
+ background: black;
+ }
+
+
+`;
+
+export const HistoryButton = styled.button`
+ padding: 3px 6px;
+ background: ${dTheme.buttonDefault};
+ border-radius: 3px;
+ border: none;
+ color: ${dTheme.buttonText};
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin: 0px 6px;
+ cursor: pointer;
+ min-height: 20px;
+`;
+
+export const SettingItemContainer = styled.div`
+ height: 100px;
+ width: 240px;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ padding: 20px;
+ background: ${dTheme.viewBg};
+ margin: 10px;
+ border-radius: 3px;
+ & div {
+ font-size: 15px;
+ color: orange;
+ line-height: 1.5;
+ }
+ & small {
+ font-size: 12px;
+ color: ${dTheme.buttonText};
+ line-height: 1.5;
+ margin-bottom:10px;
+ }
+`;
+export const SubmitButton = styled(HistoryButton)`
+ background: ${dTheme.primaryDark};
+ color: ${dTheme.buttonText};
+ white-space: nowrap;
+ .open-icon {
+ display: none;
+ }
+ .open-text {
+ display: flex;
+ }
+ @media screen and (max-width: 864px) {
+ .open-icon {
+ display: flex;
+ }
+ .open-text {
+ display: none;
+ }
+ }
+`;
+
+export const ClearHistoryButton = styled(HistoryButton)`
+ font-weight: bold;
+ padding: 10px 20px;
+ background: ${dTheme.primaryDark};
+ margin: 0;
+ width: 100%;
+ white-space: nowrap;
+`;
+export const StyledCloseButton = styled(HistoryButton)`
+ background: none;
+ color: ${dTheme.buttonText};
+ position: absolute;
+ right: 0;
+`;
+
+export const DialogCancelButton = styled(HistoryButton)`
+ background: ${dTheme.buttonDefault};
+ padding: 8px 16px;
+`;
+export const DialogConfirmButton = styled(HistoryButton)`
+ background: ${dTheme.primaryDark};
+ padding: 8px 16px;
+`;
+
+export const FilterInput = styled.input`
+ color: ${dTheme.buttonText};
+ background: ${dTheme.inputBg};
+ border: none;
+ height: 21px;
+ margin: 0px 10px 0px 0px;
+ padding: 0px;
+ font-size: 13px;
+ border-radius: 0px 3px 3px 0px;
+ font-family: monospace;
+ font-size: 12px;
+ &:focus {
+ outline: none;
+ color: ${dTheme.inputTextFocus};
+ }
+`;
+export const RowData = styled.span`
+ flex: 1;
+ font-family: monospace;
+ font-size: "13px";
+ color: ${dTheme.buttonText};
+ white-space: nowrap;
+ padding: 4px 0px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+`;
+
+export const LinkParams = styled.div`
+ display: flex;
+ flex: 1;
+ justify-content: space-between;
+ .open-button {
+ display: none;
+ }
+ .inline-params {
+ align-items: center;
+ display: ${(props) => (props.open ? "none" : "grid")};
+ flex: 1;
+ grid-template-columns: 1fr 0.25fr 0.25fr auto;
+ margin-right: 5px;
+ }
+
+ .open-button {
+ display: flex;
+ color: ${dTheme.buttonText};
+ background: none;
+ border: none;
+ }
+ .block-params {
+ display: ${(props) => (props.open ? "flex" : "none")};
+ flex-direction: column;
+ flex: 1;
+ p {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ flex: 1;
+ border-bottom: 1px solid ${dTheme.buttonDefault};
+ margin-bottom: 4px;
+ padding-bottom: 2px;
+ span {
+ margin-left: 3px;
+ }
+ }
+ }
+ @media screen and (max-width: 864px) {
+ .inline-params {
+ display: none;
+ }
+ }
+`;
+
+export const HistoryRow = styled.div`
+ padding: 5px 0px;
+ padding-left: 10px;
+ background:#7b7b7b1f;
+ margin: 5px;
+ border-radius: 3px;
+ font-size: 13px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ //height: 30px;
+`;
+export const TimeSpan = styled.div`
+ @media screen and (max-width: 1370px) {
+ display: none;
+ }
+`;
+
+export const theme = createTheme({
+ palette: {
+ mode: "dark",
+ primary: {
+ main: dTheme.buttonText,
+ background: dTheme.buttonHover,
+ },
+ },
+});
diff --git a/src/plugins/settingsmenu/Menu.js b/src/plugins/settingsmenu/Menu.js
index f1b3d4dc..de317285 100644
--- a/src/plugins/settingsmenu/Menu.js
+++ b/src/plugins/settingsmenu/Menu.js
@@ -1,93 +1,94 @@
-import * as React from "react";
-import Button from "@mui/material/Button";
-import Menu from "@mui/material/Menu";
-import MenuItem from "@mui/material/MenuItem";
-import DisplaySettingsIcon from "@mui/icons-material/DisplaySettings";
-import { useDispatch } from "react-redux";
-
-import CopyButton from "./CopyButton/CopyButton";
-import { styled } from "@mui/material/styles";
-import MenuIcon from "@mui/icons-material/Menu";
-import setSettingsDialogOpen from "../../actions/setSettingsDialogOpen";
-
-const StyledMenu = styled((props) => (
-
-))(({ theme }) => ({
- "& .MuiPaper-root": {
- borderRadius: 6,
- marginTop: theme.spacing(1),
- minWidth: 180,
- color: "#ddd",
- backgroundColor: "#333",
- "& .MuiMenu-list": {
- padding: "4px 0",
- },
- "& .MuiMenuItem-root": {
- "& .MuiSvgIcon-root": {
- fontSize: 18,
- color: theme.palette.text.secondary,
- marginRight: theme.spacing(1.5),
- },
- "&:active": {
- backgroundColor: "#222",
- },
- },
- },
-}));
-
-export default function ClokiMenu() {
- const dispatch = useDispatch();
- const [anchorEl, setAnchorEl] = React.useState(null);
- const open = Boolean(anchorEl);
- const handleClick = (event) => {
- setAnchorEl(event.currentTarget);
- };
- const handleClose = () => {
- setAnchorEl(null);
- };
- const handleSettingsOpen = () => {
- dispatch(setSettingsDialogOpen(true));
-
- handleClose();
- };
- return (
-
-
-
-
- );
-}
+import * as React from "react";
+import Menu from "@mui/material/Menu";
+import MenuItem from "@mui/material/MenuItem";
+import DisplaySettingsIcon from "@mui/icons-material/DisplaySettings";
+import { useDispatch } from "react-redux";
+
+import CopyButton from "./CopyButton/CopyButton";
+import { styled } from "@mui/material/styles";
+import MenuIcon from "@mui/icons-material/Menu";
+import setSettingsDialogOpen from "../../actions/setSettingsDialogOpen";
+import { MenuButton } from "./styled";
+
+const StyledMenu = styled((props) => (
+
+))(({ theme }) => ({
+ "& .MuiPaper-root": {
+ borderRadius: 6,
+ marginTop: theme.spacing(1),
+ minWidth: 180,
+ color: "#ddd",
+ backgroundColor: "#333",
+ "& .MuiMenu-list": {
+ padding: "4px 0",
+ },
+ "& .MuiMenuItem-root": {
+ fontSize:12,
+ "& .MuiSvgIcon-root": {
+ fontSize: 12,
+ color: theme.palette.text.secondary,
+ marginRight: theme.spacing(1.5),
+ },
+ "&:active": {
+ backgroundColor: "#222",
+ },
+ },
+ },
+}));
+
+export default function ClokiMenu() {
+ const dispatch = useDispatch();
+ const [anchorEl, setAnchorEl] = React.useState(null);
+ const open = Boolean(anchorEl);
+ const handleClick = (event) => {
+ setAnchorEl(event.currentTarget);
+ };
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+ const handleSettingsOpen = () => {
+ dispatch(setSettingsDialogOpen(true));
+
+ handleClose();
+ };
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/src/plugins/settingsmenu/styled/index.js b/src/plugins/settingsmenu/styled/index.js
new file mode 100644
index 00000000..3cdf8ae5
--- /dev/null
+++ b/src/plugins/settingsmenu/styled/index.js
@@ -0,0 +1,19 @@
+import styled from "@emotion/styled";
+import darkTheme from "../../../theme/dark";
+const theme = darkTheme;
+
+export const MenuButton = styled.button`
+ border: none;
+ background: ${theme.buttonDefault};
+ color: ${theme.buttonText};
+ padding: 3px 12px;
+ border-radius: 3px;
+ font-size: 12px;
+ cursor: pointer;
+ user-select: none;
+ line-height: 20px;
+ display: flex;
+ align-items: center;
+ margin-left: 10px;
+ height: 26px;
+`;
diff --git a/src/scss/modules/date-range-picker.scss b/src/scss/modules/date-range-picker.scss
index 367014fc..798d1221 100644
--- a/src/scss/modules/date-range-picker.scss
+++ b/src/scss/modules/date-range-picker.scss
@@ -1,27 +1,26 @@
-.date-time-selector {
- svg {
- font-size: 1.15em;
- margin-right: 3px;
- }
- .tooltip {
- background-color: red;
- display: flex;
- align-items: center;
- justify-items: center;
- }
-}
-@media screen and (max-width: 1200px) {
- .date-time-selector {
- font-size: 1em;
- padding: 8px;
- color:#ddd;
- line-height: 1.5;
- margin-right:10px;
- svg {
- margin-right: 0;
- }
- span {
- display: none;
- }
- }
+.date-time-selector {
+ svg {
+ font-size: 1.15em;
+ margin-right: 3px;
+ }
+ .tooltip {
+ background-color: red;
+ display: flex;
+ align-items: center;
+ justify-items: center;
+ }
+}
+@media screen and (max-width: 1200px) {
+ .date-time-selector {
+ font-size: 1em;
+ padding: 8px;
+ color:#ddd;
+ line-height: 1.5;
+ svg {
+ margin-right: 0;
+ }
+ span {
+ display: none;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/scss/modules/log-view.scss b/src/scss/modules/log-view.scss
index 70284e45..3fa5962b 100644
--- a/src/scss/modules/log-view.scss
+++ b/src/scss/modules/log-view.scss
@@ -77,7 +77,7 @@
max-width: 450px;
.value-tags {
font-family: monospace;
- font-size: 0.95em;
+ font-size: 12px;
display: flex;
margin: 2px;
padding: 2px;
diff --git a/src/scss/modules/status-bar.scss b/src/scss/modules/status-bar.scss
index a7e9bd12..fcb76732 100644
--- a/src/scss/modules/status-bar.scss
+++ b/src/scss/modules/status-bar.scss
@@ -1,150 +1,151 @@
-.status-bar {
- display: flex;
- justify-content: space-between;
- padding: 5px 10px;
-}
-.status-options {
- display: flex;
- align-items: center;
-}
-.status-selectors {
- display: flex;
- align-items: center;
- .selector {
- margin-left: 10px;
- .label {
- flex: 1;
- color: #bfbfbf;
- white-space: nowrap;;
- text-transform: uppercase;
- border-radius: 3px;
- }
- }
- & div {
- display: flex;
- align-items: center;
- }
-
- @media screen and (max-width: 565px) {
- display: none;
- }
-}
-.date-selector {
- input {
- color: orange;
- background: #121212;
- border: none;
- margin: 3px;
- padding: 3px 6px;
- font-size: 13px;
- border-radius: 3px;
- &.limit {
- width: 50px;
- }
-
- &.date-time-range {
- width: 120px;
- color: orange;
- background: #121212;
- }
- }
-}
-
-.logo {
- border-radius: 90px;
-}
-
-.api-url-selector {
- margin-left: 20px;
- display: flex;
- align-items: center;
- transition: 0.2s all;
- input {
- color: orange;
- background: #121212;
- border: none;
- margin: 3px;
- padding: 3px 6px;
- font-size: 13px;
- border-radius: 3px;
-
- }
- button {
- display: flex;
- align-items: center;
- height: 20px;
- font-size: 18px;
- border: none;
- margin: 3px;
- padding: 5px 8px;
- border-radius: 3px;
- background: #7b7b7b3b;
- color: #d1d1d1;
- font-size: 0.9em;
- cursor: pointer;
- align-items: center;
- white-space: nowrap;
- text-overflow: ellipsis;
- transition: 0.2s all;
- &:hover {
- background: #9e9e9e3b;
- }
- }
-}
-
-.logo-section {
- display: flex;
- align-items: center;
- flex: 1;
-}
-
-.url-copy {
- display: flex;
- align-items: center;
- height: 20px;
- font-size: 18px;
- border: none;
- margin: 3px;
- padding: 5px 8px;
- border-radius: 3px;
- background: #7b7b7b3b;
- // color: #d1d1d1;
- color: orange;
- font-size: 0.9em;
- cursor: pointer;
- align-items: center;
- white-space: nowrap;
- text-overflow: ellipsis;
- transition: 0.2s all;
- span {
- margin-left: 4px;
- text-transform: uppercase;
- font-size: 0.85em;
- color: #d1d1d1;
- }
- &:hover {
- background: #9e9e9e3b;
- }
- &:disabled {
- color: #7b7b7b;
- cursor: not-allowed;
- }
-}
-@media screen and (max-width: 950px) {
- .url-copy {
- span {
- display: none;
- }
- }
-}
-.copied-warning {
- transition: 0.2s all;
- color: orange;
- font-size: 0.8em;
- text-transform: uppercase;
- margin-right: 10px;
-}
-.submit-checkbox {
- color: red;
- background-color: green;
-}
+.status-bar {
+ display: flex;
+ justify-content: space-between;
+ padding: 0px 7px;
+}
+.status-options {
+ display: flex;
+ align-items: center;
+}
+.status-selectors {
+ display: flex;
+ align-items: center;
+ .selector {
+ margin-left: 10px;
+ .label {
+ flex: 1;
+ color: #bfbfbf;
+ white-space: nowrap;;
+ text-transform: uppercase;
+ border-radius: 3px;
+ font-size: 12px;
+ }
+ }
+ & div {
+ display: flex;
+ align-items: center;
+ }
+
+ @media screen and (max-width: 565px) {
+ display: none;
+ }
+}
+.date-selector {
+ input {
+ color: orange;
+ background: #121212;
+ border: none;
+ margin: 3px;
+ padding: 3px 6px;
+ font-size: 13px;
+ border-radius: 3px;
+ &.limit {
+ width: 50px;
+ }
+
+ &.date-time-range {
+ width: 120px;
+ color: orange;
+ background: #121212;
+ }
+ }
+}
+
+.logo {
+margin-left: 10px;
+}
+
+.api-url-selector {
+ margin-left: 20px;
+ display: flex;
+ align-items: center;
+ transition: 0.2s all;
+ input {
+ color: orange;
+ background: #121212;
+ border: none;
+ margin: 3px;
+ padding: 3px 6px;
+ font-size: 13px;
+ border-radius: 3px;
+
+ }
+ button {
+ display: flex;
+ align-items: center;
+ height: 20px;
+ font-size: 18px;
+ border: none;
+ margin: 3px;
+ padding: 5px 8px;
+ border-radius: 3px;
+ background: #7b7b7b3b;
+ color: #d1d1d1;
+ font-size: 0.9em;
+ cursor: pointer;
+ align-items: center;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ transition: 0.2s all;
+ &:hover {
+ background: #9e9e9e3b;
+ }
+ }
+}
+
+.logo-section {
+ display: flex;
+ align-items: center;
+ flex: 1;
+}
+
+.url-copy {
+ display: flex;
+ align-items: center;
+ height: 20px;
+ font-size: 18px;
+ border: none;
+ margin: 3px;
+ padding: 5px 8px;
+ border-radius: 3px;
+ background: #7b7b7b3b;
+ // color: #d1d1d1;
+ color: orange;
+ font-size: 0.9em;
+ cursor: pointer;
+ align-items: center;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ transition: 0.2s all;
+ span {
+ margin-left: 4px;
+ text-transform: uppercase;
+ font-size: 12px;
+ color: #d1d1d1;
+ }
+ &:hover {
+ background: #9e9e9e3b;
+ }
+ &:disabled {
+ color: #7b7b7b;
+ cursor: not-allowed;
+ }
+}
+@media screen and (max-width: 950px) {
+ .url-copy {
+ span {
+ display: none;
+ }
+ }
+}
+.copied-warning {
+ transition: 0.2s all;
+ color: orange;
+ font-size: 0.8em;
+ text-transform: uppercase;
+ margin-right: 10px;
+}
+.submit-checkbox {
+ color: red;
+ background-color: green;
+}
diff --git a/src/scss/modules/valuesList.scss b/src/scss/modules/valuesList.scss
index 7aa9ab4b..897ef552 100644
--- a/src/scss/modules/valuesList.scss
+++ b/src/scss/modules/valuesList.scss
@@ -1,197 +1,198 @@
-.valuesList {
- transition:.2s all;
- display: flex;
- flex-wrap: wrap;
- flex: 1;
- flex-direction: column;
- font-size: 13px;
-
- background: #262626;
- margin: 5px 0px;
- border-radius: 4px;
- transition: 0.2s all;
- .valuelist-title {
- display: flex;
- flex-direction: column;
- flex: 1;
- justify-content: space-between;
- color: white;
- font-size: 1em;
- flex: 1;
- margin: 10px;
-
- }
- .valuelist-content {
- padding: 5px;
- display: flex;
- color: white;
- font-size: 14px;
- align-items: center;
- flex-wrap: wrap;
- max-height: 500px;
- overflow: auto;
- small {
- margin: 5px;
- padding: 4px 8px;
- border-radius: 3px;
- background: #5454543b;
- line-height: 1.5;
- color: #d1d1d1;
- font-size: 1em;
- cursor: pointer;
- align-items: center;
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
- max-width: 23ch;
- transition: 1s all;
- &:hover {
- background: #ffffff3a;
-
- }
- }
- }
- .valuelist-filter {
- display: flex;
- flex: 1;
- flex-direction: column;
-
-
- .valuelist-filter-title {
- font-size: 0.75em;
- }
- input {
- color: white;
- background: $black-quoise;
- padding: 6px 3px;
- border-radius: 4px;
- flex: 1;
- margin: 0px 3px;
- outline: none;
- border: none;
- }
- }
- &::-webkit-scrollbar {
- width: 10px;
- }
-
- &::-webkit-scrollbar-thumb {
- border-radius: 10px;
- background: $grey-light;
- }
-}
-.values-container {
- max-width: 100%;
- .values-container-column {
- display: flex;
- max-width: 100%;
- .values-column {
- margin: 5px;
- border-radius: 3px;
- background: #323131;
- height: auto;
- min-height: 100px;
- min-width: 175px;
- flex:1;
- .column {
- max-height: 350px;
- &::-webkit-scrollbar {
- width: 10px;
- color: #58585898;
- background: #ffffff1f;
- }
- &::-webkit-scrollbar-thumb {
- border-radius: 10px;
- background: $grey-light;
- }
- }
- .values-column-title {
- background: #403f3f;
- border-left: 1px solid #ffa60056;
- padding: 8px;
- font-size: 1em;
- border-radius: 4px 4px 0px 0px;
- border-bottom: 2px solid #2e2e2e;
- color:white;
- display: flex;
- flex: 1;
- transition: .2s all;
-
- justify-content: space-between;
-
- .close-column {
- align-self: flex-end;
- justify-self: end;
- color:orange;
- cursor:pointer;
-
- padding:2px;
- border-radius: 10px;
- display: flex;
- align-items: center;
- justify-content: center;
- color:#c9c5c5;
-
- font-size: 10px;
- &:hover {
-
- background:$dark-quoise-hover;
-
- color:black;
-
- }
- }
- }
- }
- }
-}
-.legend-container {
- margin:3px;
- padding:3px;
- .legend-title {
- font-size: 13px;
- font-weight: bold;
- }
- .legend-text {
- font-size: 11px;
- font-family: monospace;
- }
-}
-
-.refresh-button {
- display: flex;
- align-items: center;
- margin: 3px;
- padding: 5px 8px;
- border:none;
- height: 22px;
- font-size: 18px;
- border-radius: 3px;
- background: #b1b1b13b;
- color: #d1d1d1;
- font-size: 0.9em;
- cursor: pointer;
- align-items: center;
- white-space: nowrap;
- text-overflow: ellipsis;
- transition: 0.2s all;
- &.haveToRefresh {
- background: $dark-quoise-hover;
- }
- &:hover {
- background: #ffffff3a;
- }
-}
-
-.label-error {
- display:flex;
- align-items: center;
- color:orangered;
- border:1px solid orangered;
- padding:3px 6px;
- border-radius:3px;
- width:250px;
- justify-content: center;
- position:absolute;
- right: 20px;
+.valuesList {
+ transition:.2s all;
+ display: flex;
+ flex-wrap: wrap;
+ flex: 1;
+ flex-direction: column;
+ font-size: 13px;
+
+ background: #262626;
+ margin: 5px 0px;
+ border-radius: 4px;
+ transition: 0.2s all;
+ .valuelist-title {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ justify-content: space-between;
+ color: white;
+ font-size: 1em;
+ flex: 1;
+ margin: 10px;
+
+ }
+ .valuelist-content {
+ padding: 5px;
+ display: flex;
+ color: white;
+ font-size: 14px;
+ align-items: center;
+ flex-wrap: wrap;
+ max-height: 500px;
+ overflow: auto;
+ small {
+ margin: 5px;
+ padding: 4px 8px;
+ border-radius: 3px;
+ background: #5454543b;
+ line-height: 1.5;
+ color: #d1d1d1;
+ font-size: 12px;
+ cursor: pointer;
+ align-items: center;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ max-width: 23ch;
+ transition: 1s all;
+ &:hover {
+ background: #ffffff3a;
+
+ }
+ }
+ }
+ .valuelist-filter {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+
+
+ .valuelist-filter-title {
+ font-size: 0.75em;
+ }
+ input {
+ color: white;
+ background: $black-quoise;
+ padding: 6px 3px;
+ border-radius: 4px;
+ flex: 1;
+ margin: 0px 3px;
+ outline: none;
+ border: none;
+ }
+ }
+ &::-webkit-scrollbar {
+ width: 10px;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ border-radius: 10px;
+ background: $grey-light;
+ }
+}
+.values-container {
+ max-width: 100%;
+ .values-container-column {
+ display: flex;
+ max-width: 100%;
+ .values-column {
+ margin: 5px;
+ border-radius: 3px;
+ background: #323131;
+ height: auto;
+ min-height: 100px;
+ min-width: 175px;
+ flex:1;
+ .column {
+ max-height: 350px;
+ &::-webkit-scrollbar {
+ width: 10px;
+ color: #58585898;
+ background: #ffffff1f;
+ }
+ &::-webkit-scrollbar-thumb {
+ border-radius: 10px;
+ background: $grey-light;
+ }
+ }
+ .values-column-title {
+ background: #403f3f;
+ border-left: 1px solid #ffa60056;
+ padding: 8px;
+ font-size: 1em;
+ border-radius: 4px 4px 0px 0px;
+ border-bottom: 2px solid #2e2e2e;
+ color:white;
+ display: flex;
+ flex: 1;
+ transition: .2s all;
+
+ justify-content: space-between;
+
+ .close-column {
+ align-self: flex-end;
+ justify-self: end;
+ color:orange;
+ cursor:pointer;
+
+ padding:2px;
+ border-radius: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color:#c9c5c5;
+
+ font-size: 10px;
+ &:hover {
+
+ background:$dark-quoise-hover;
+
+ color:black;
+
+ }
+ }
+ }
+ }
+ }
+}
+.legend-container {
+ margin:3px;
+ padding:3px;
+ line-height: 1.5;
+ .legend-title {
+ font-size: 12px;
+ font-weight: bold;
+ }
+ .legend-text {
+ font-size: 12px;
+ font-family: monospace;
+ }
+}
+
+.refresh-button {
+ display: flex;
+ align-items: center;
+ margin: 3px;
+ padding: 5px 8px;
+ border:none;
+ height: 22px;
+ font-size: 18px;
+ border-radius: 3px;
+ background: #b1b1b13b;
+ color: #d1d1d1;
+ font-size: 0.9em;
+ cursor: pointer;
+ align-items: center;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ transition: 0.2s all;
+ &.haveToRefresh {
+ background: $dark-quoise-hover;
+ }
+ &:hover {
+ background: #ffffff3a;
+ }
+}
+
+.label-error {
+ display:flex;
+ align-items: center;
+ color:orangered;
+ border:1px solid orangered;
+ padding:3px 6px;
+ border-radius:3px;
+ width:250px;
+ justify-content: center;
+ position:absolute;
+ right: 20px;
}
\ No newline at end of file
diff --git a/src/store/createInitialState.js b/src/store/createInitialState.js
index 17d6a5bc..ce366e75 100644
--- a/src/store/createInitialState.js
+++ b/src/store/createInitialState.js
@@ -1,68 +1,71 @@
-import * as moment from "moment";
-import { environment } from "../environment/env.dev";
-import stateFromQueryParams from "../helpers/stateFromQueryParams";
-import localService from "../services/localService";
-import localUrl from "../services/localUrl";
-const debugLocal = () => {
- let isDebug = JSON.parse(localStorage.getItem("isDebug"));
- if (!isDebug) {
- localStorage.setItem("isDebug", JSON.stringify({ isActive: false }));
- isDebug = {isActive:false}
- }
-
- return isDebug;
-};
-
-export default function initialState() {
- const urlState = stateFromQueryParams();
- const historyService = localService().historyStore();
- const linkService = localUrl();
- const state = {
- debugMode: debugLocal().isActive|| false,
- labels: [],
- labelValues: [],
- queryHistory: historyService.getAll() || [],
- linksHistory: linkService.getAll() || [],
- timeRange: [],
- query: urlState.query || "",
- logs: [],
- matrixData: [],
- loading: false,
- start:
- urlState.start ||
- new Date(
- moment(Date.now())
- .subtract(5, "minutes")
- .format("YYYY-MM-DDTHH:mm:ss.SSSZ")
- ),
- stop:
- urlState.end ||
- new Date(moment(Date.now()).format("YYYY-MM-DDTHH:mm:ss.SSSZ")),
- from: urlState.from || null,
- to: urlState.to || null,
- label: urlState.label || "Last 5 minutes",
- messages: [],
- limitLoad: false,
- limit: urlState.limit || 100,
- step: urlState.step || 100,
- rangeOpen: false,
- labelsBrowserOpen: true,
- settingsMenuOpen: false,
- timePickerOpen: false,
- settingsDialogOpen: false,
- historyOpen: false,
- apiErrors: "",
- urlQueryParams: urlState || {},
- urlLocation: "",
- apiUrl: urlState.apiUrl || environment.apiUrl || "",
- isSubmit: urlState.isSubmit || false,
- isEmbed: urlState.isEmbed || false,
- chartType: "line",
- notifications: [],
- theme: "darkTheme",
- };
- const debug = state.debugMode;
- if (debug) console.log("🚧 LOGIC/ INITIAL STATE ::: ", state);
-
- return state;
-}
+import * as moment from "moment";
+import { environment } from "../environment/env.dev";
+import stateFromQueryParams from "../helpers/stateFromQueryParams";
+import localService from "../services/localService";
+import localUrl from "../services/localUrl";
+
+const debugLocal = () => {
+ let isDebug = JSON.parse(localStorage.getItem("isDebug"));
+ if (!isDebug) {
+ localStorage.setItem("isDebug", JSON.stringify({ isActive: false }));
+ isDebug = {isActive:false}
+ }
+
+ return isDebug;
+};
+
+export default function initialState() {
+ const urlState = stateFromQueryParams();
+ const historyService = localService().historyStore();
+ const linkService = localUrl();
+
+ const state = {
+ debugMode: debugLocal().isActive|| false,
+ labels: [],
+ labelValues: [],
+ queryHistory: historyService.getAll() || [],
+ linksHistory: linkService.getAll() || [],
+ timeRange: [],
+ query: urlState.query || "",
+ logs: [],
+ matrixData: [],
+ loading: false,
+ start:
+ urlState.start ||
+ new Date(
+ moment(Date.now())
+ .subtract(5, "minutes")
+ .format("YYYY-MM-DDTHH:mm:ss.SSSZ")
+ ),
+ stop:
+ urlState.end ||
+ new Date(moment(Date.now()).format("YYYY-MM-DDTHH:mm:ss.SSSZ")),
+ from: urlState.from || null,
+ to: urlState.to || null,
+ label: urlState.label || "Last 5 minutes",
+ messages: [],
+ limitLoad: false,
+ limit: urlState.limit || 100,
+ step: urlState.step || 100,
+ rangeOpen: false,
+ labelsBrowserOpen: false,
+ settingsMenuOpen: false,
+ timePickerOpen: false,
+ settingsDialogOpen: false,
+ historyOpen: false,
+ apiErrors: "",
+ urlQueryParams: urlState || {},
+ urlLocation: "",
+ apiUrl: urlState.apiUrl || environment.apiUrl || "",
+ apiWarning:{},
+ isSubmit: urlState.isSubmit || false,
+ isEmbed: urlState.isEmbed || false,
+ chartType: "line",
+ notifications: [],
+ theme: "darkTheme",
+ };
+ const debug = state.debugMode;
+ if (debug) console.log("🚧 LOGIC/ INITIAL STATE ::: ", state);
+
+ return state;
+}
diff --git a/src/store/reducer.js b/src/store/reducer.js
index 783cdbd2..81a7b2d3 100644
--- a/src/store/reducer.js
+++ b/src/store/reducer.js
@@ -1,69 +1,71 @@
-const reducer = (state, action) => {
- switch (action.type) {
- case "SET_LABELS":
- return { ...state, labels: action.labels };
- case "SET_LOADING":
- return { ...state, loading: action.loading };
- case "SET_LOGS":
- return { ...state, logs: action.logs };
- case "SET_LABEL_VALUES":
- return { ...state, labelValues: action.labelValues };
- case "SET_START_TIME":
- return { ...state, start: action.start };
- case "SET_STOP_TIME":
- return { ...state, stop: action.stop };
- case "SET_FROM_TIME":
- return { ...state, from: action.from };
- case "SET_TO_TIME":
- return { ...state, to: action.to };
- case "SET_TIME_RANGE_LABEL":
- return { ...state, label: action.label };
- case "SET_QUERY_LIMIT":
- return { ...state, limit: action.limit };
- case "SET_RANGE_OPEN":
- return { ...state, rangeOpen: action.rangeOpen };
- case "SET_BROWSER_OPEN":
- return { ...state, labelsBrowserOpen: action.labelsBrowserOpen };
- case "SET_SETTINGS_MENU_OPEN":
- return { ...state, settingsMenuOpen: action.settingsMenuOpen };
- case "SET_TIME_PICKER_OPEN":
- return { ...state, timePickerOpen: action.timePickerOpen };
- case "SET_SETTINGS_DIALOG_OPEN":
- return { ...state, settingsDialogOpen: action.settingsDialogOpen };
- case "SET_QUERY":
- return { ...state, query: action.query };
- case "SET_QUERY_STEP":
- return { ...state, step: action.step };
- case "SET_API_URL":
- return { ...state, apiUrl: action.apiUrl };
- case "SET_API_ERRORS":
- return { ...state, apiErrors: action.apiErrors };
- case "SET_URL_QUERY_PARAMS":
- return { ...state, urlQueryParams: action.urlQueryParams };
- case "SET_URL_LOCATION":
- return { ...state, urlLocation: action.urlLocation };
- case "SET_IS_SUBMIT":
- return { ...state, isSubmit: action.isSubmit };
- case "SET_IS_EMBED":
- return { ...state, isEmbed: action.isEmbed };
- case "SET_MATRIX_DATA":
- return { ...state, matrixData: action.matrixData };
- case "SET_CHART_TYPE":
- return { ...state, chartType: action.setChartType };
- case "SET_QUERY_HISTORY":
- return { ...state, queryHistory: action.queryHistory };
- case "SET_LINKS_HISTORY":
- return { ...state, linksHistory: action.linksHistory };
- case "SET_HISTORY_OPEN":
- return { ...state, historyOpen: action.historyOpen };
- case "ADD_NOTIFICATION":
- return { ...state, notifications: action.payload };
- case "REMOVE_NOTIFICATION":
- return { ...state, notifications: action.payload };
- case "SET_DEBUG_MODE":
- return { ...state, debugMode: action.debugMode };
- default:
- return { ...state };
- }
-};
-export default reducer;
+const reducer = (state, action) => {
+ switch (action.type) {
+ case "SET_LABELS":
+ return { ...state, labels: action.labels };
+ case "SET_LOADING":
+ return { ...state, loading: action.loading };
+ case "SET_LOGS":
+ return { ...state, logs: action.logs };
+ case "SET_LABEL_VALUES":
+ return { ...state, labelValues: action.labelValues };
+ case "SET_START_TIME":
+ return { ...state, start: action.start };
+ case "SET_STOP_TIME":
+ return { ...state, stop: action.stop };
+ case "SET_FROM_TIME":
+ return { ...state, from: action.from };
+ case "SET_TO_TIME":
+ return { ...state, to: action.to };
+ case "SET_TIME_RANGE_LABEL":
+ return { ...state, label: action.label };
+ case "SET_QUERY_LIMIT":
+ return { ...state, limit: action.limit };
+ case "SET_RANGE_OPEN":
+ return { ...state, rangeOpen: action.rangeOpen };
+ case "SET_BROWSER_OPEN":
+ return { ...state, labelsBrowserOpen: action.labelsBrowserOpen };
+ case "SET_SETTINGS_MENU_OPEN":
+ return { ...state, settingsMenuOpen: action.settingsMenuOpen };
+ case "SET_TIME_PICKER_OPEN":
+ return { ...state, timePickerOpen: action.timePickerOpen };
+ case "SET_SETTINGS_DIALOG_OPEN":
+ return { ...state, settingsDialogOpen: action.settingsDialogOpen };
+ case "SET_QUERY":
+ return { ...state, query: action.query };
+ case "SET_QUERY_STEP":
+ return { ...state, step: action.step };
+ case "SET_API_URL":
+ return { ...state, apiUrl: action.apiUrl };
+ case "SET_API_ERRORS":
+ return { ...state, apiErrors: action.apiErrors };
+ case "SET_URL_QUERY_PARAMS":
+ return { ...state, urlQueryParams: action.urlQueryParams };
+ case "SET_URL_LOCATION":
+ return { ...state, urlLocation: action.urlLocation };
+ case "SET_IS_SUBMIT":
+ return { ...state, isSubmit: action.isSubmit };
+ case "SET_IS_EMBED":
+ return { ...state, isEmbed: action.isEmbed };
+ case "SET_MATRIX_DATA":
+ return { ...state, matrixData: action.matrixData };
+ case "SET_CHART_TYPE":
+ return { ...state, chartType: action.setChartType };
+ case "SET_QUERY_HISTORY":
+ return { ...state, queryHistory: action.queryHistory };
+ case "SET_LINKS_HISTORY":
+ return { ...state, linksHistory: action.linksHistory };
+ case "SET_HISTORY_OPEN":
+ return { ...state, historyOpen: action.historyOpen };
+ case "ADD_NOTIFICATION":
+ return { ...state, notifications: action.payload };
+ case "REMOVE_NOTIFICATION":
+ return { ...state, notifications: action.payload };
+ case "SET_DEBUG_MODE":
+ return { ...state, debugMode: action.debugMode };
+ case "SET_API_WARNING":
+ return { ...state, apiWarning: action.apiWarning};
+ default:
+ return { ...state };
+ }
+};
+export default reducer;
diff --git a/src/theme/styles/Input.js b/src/theme/styles/Input.js
index 8f7b79bc..a8eee843 100644
--- a/src/theme/styles/Input.js
+++ b/src/theme/styles/Input.js
@@ -1,11 +1,11 @@
-import styled from "@emotion/styled"
-
-export const InputSmall = styled.input`
-padding:3px 12px;
-line-height: 20px;
-border: 1px solid;
-outline:none;
-border:none;
-font-size: .9em;
-border-radius:3px;
-`
\ No newline at end of file
+import styled from "@emotion/styled";
+
+export const InputSmall = styled.input`
+ padding: 3px 12px;
+ line-height: 20px;
+ border: 1px solid;
+ outline: none;
+ border: none;
+ font-size: 12px;
+ border-radius: 3px;
+`;