From e6945267c1d40782fea3deb8e9eeb5ba6599e9eb Mon Sep 17 00:00:00 2001 From: Joel Guerra Date: Fri, 29 Apr 2022 18:36:43 +0200 Subject: [PATCH 01/11] feature: query type init --- src/components/LabelBrowser/QueryBar.js | 20 ++++- .../LabelBrowser/components/styled/index.js | 3 +- .../QueryTypeBar/components/QueryLabel.js | 10 +++ .../QueryTypeBar/components/QueryLimit.js | 51 +++++++++++ .../components/QueryResolution.js | 59 +++++++++++++ .../components/QueryTypeSwitch.js | 87 +++++++++++++++++++ src/components/QueryTypeBar/index.js | 87 +++++++++++++++++++ src/plugins/queryhistory/index.js | 1 + src/plugins/settingsdialog/SettingsDialog.js | 2 +- src/theme/light.js | 2 +- 10 files changed, 318 insertions(+), 4 deletions(-) create mode 100644 src/components/QueryTypeBar/components/QueryLabel.js create mode 100644 src/components/QueryTypeBar/components/QueryLimit.js create mode 100644 src/components/QueryTypeBar/components/QueryResolution.js create mode 100644 src/components/QueryTypeBar/components/QueryTypeSwitch.js create mode 100644 src/components/QueryTypeBar/index.js diff --git a/src/components/LabelBrowser/QueryBar.js b/src/components/LabelBrowser/QueryBar.js index 55bea3f5..eb6c00fd 100644 --- a/src/components/LabelBrowser/QueryBar.js +++ b/src/components/LabelBrowser/QueryBar.js @@ -25,6 +25,9 @@ import debugLog from "./helpers/debugLog"; import { ThemeProvider } from "@emotion/react"; import { themes } from "../../theme/themes"; import { sendLabels } from "../../hooks/useLabels"; +import CustomizedDividers from "../QueryTypeBar/components/QueryTypeSwitch"; +import QueryTypeSwitch from "../QueryTypeBar/components/QueryTypeSwitch"; +import QueryTypeBar from "../QueryTypeBar"; export const QueryBar = () => { const dispatch = useDispatch(); @@ -85,7 +88,9 @@ export const QueryBar = () => { onSubmit(e); } }; - + const onQueryTypeChange = (e) => { + console.log(e) + } const onSubmit = (e) => { e.preventDefault(); @@ -170,7 +175,20 @@ export const QueryBar = () => { onClick={onSubmit} isMobile={false} /> + + {/* + + + */} + ) diff --git a/src/components/LabelBrowser/components/styled/index.js b/src/components/LabelBrowser/components/styled/index.js index 2436553e..028c5b86 100644 --- a/src/components/LabelBrowser/components/styled/index.js +++ b/src/components/LabelBrowser/components/styled/index.js @@ -42,7 +42,7 @@ export const ShowLabelsBtn = styled(BtnSmall)` export const QueryBarContainer = styled.div` display: flex; padding: 3px 6px; - margin: 5px 0px; + margin-top:5px; margin-left: 0px; background: ${({ theme }) => theme.widgetContainer}; flex-wrap: wrap; @@ -62,6 +62,7 @@ export const ShowLogsBtn = styled(BtnSmall)` background: ${(props) => props.theme.buttonDefault}; border:1px solid ${(props)=>props.theme.buttonBorder}; cursor: not-allowed; + color: ${props => props.theme.textColor}; } @media screen and (max-width: 864px) { display: ${(props) => (props.isMobile ? "flex" : "none")}; diff --git a/src/components/QueryTypeBar/components/QueryLabel.js b/src/components/QueryTypeBar/components/QueryLabel.js new file mode 100644 index 00000000..6bad2298 --- /dev/null +++ b/src/components/QueryTypeBar/components/QueryLabel.js @@ -0,0 +1,10 @@ +import styled from "@emotion/styled"; + +const StyledLabel = styled.div` + +` + +export default function QueryLabel (props) { + const {message, description} = props; + return (<>) +} \ No newline at end of file diff --git a/src/components/QueryTypeBar/components/QueryLimit.js b/src/components/QueryTypeBar/components/QueryLimit.js new file mode 100644 index 00000000..67a10f7c --- /dev/null +++ b/src/components/QueryTypeBar/components/QueryLimit.js @@ -0,0 +1,51 @@ + +import styled from "@emotion/styled"; +import { useEffect, useState } from "react"; +import { useSelector, useDispatch } from "react-redux"; +import { setQueryLimit } from "../../../actions"; + +const InputGroup = styled.div` +display:flex; +margin-right:10px; +`; + +const Label = styled.div` +color:${props => props.theme.textColor}; +background: ${props => props.theme.buttonInactive}; +display:flex; +align-items: center; +justify-content: center; +font-size: 12px; +padding:0px 8px; +`; + +const Input = styled.input` +flex:1; +background : ${props => props.theme.inputBg}; +color: ${props => props.theme.textColor}; +border: 1px solid ${props => props.theme.buttonBorder}; +border-radius: 3px; +max-width: 60px; +padding-left: 8px; +`; + +export default function QueryLimit() { + const dispatch = useDispatch; + const limit = useSelector((store) => store.limit); + const [editedValue, setEditedValue] = useState(limit); + + useEffect(() => { + setEditedValue(limit); + }, [limit, setEditedValue]); + function onLimitChange(e){ + const limit = e.target.value + + dispatch(setQueryLimit(limit)) + } + return ( + + + + + ); +} diff --git a/src/components/QueryTypeBar/components/QueryResolution.js b/src/components/QueryTypeBar/components/QueryResolution.js new file mode 100644 index 00000000..9aa725da --- /dev/null +++ b/src/components/QueryTypeBar/components/QueryResolution.js @@ -0,0 +1,59 @@ +import styled from "@emotion/styled"; +import { useState } from "react"; +const Label = styled.div` + color: ${(props) => props.theme.textColor}; + background: ${(props) => props.theme.buttonInactive}; + + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + padding: 0px 8px; +`; + +const ResSelect = styled.select` + cursor: pointer; + + position: relative; + font-size: 14px; + color: ${(props) => props.theme.textColor}; + background: ${(props) => props.theme.inputBg}; + border: 1px solid ${props => props.theme.buttonBorder}; + border-radius: 3px; + padding: 4px 8px; + line-height: 20px; + flex: 1; + max-width: 60px; + &::-webkit-scrollbar { + width: 5px; + background: ${(props) => props.theme.inputBg}; + } + + &::-webkit-scrollbar-thumb { + border-radius: 10px; + background: ${(props) => props.theme.scrollbarThumb}; + } +`; + +export default function QueryResolution() { + const resolutions = ["1/1", "1/2", "1/3", "1/4", "1/10"]; + + const [resValue, setResValue] = useState(resolutions[0]); + + function handleResChange(e) { + setResValue(e); + } + + return ( + <> + + + {resolutions.map((res, idx) => ( + + ))} + + + ); +} diff --git a/src/components/QueryTypeBar/components/QueryTypeSwitch.js b/src/components/QueryTypeBar/components/QueryTypeSwitch.js new file mode 100644 index 00000000..788f062e --- /dev/null +++ b/src/components/QueryTypeBar/components/QueryTypeSwitch.js @@ -0,0 +1,87 @@ +import styled from "@emotion/styled"; +import { useState } from "react"; +const Label = styled.div` +color:${props => props.theme.textColor}; +background: ${props => props.theme.buttonInactive}; +display:flex; +align-items: center; +justify-content: center; +font-size: 12px; +padding:0px 8px; +`; +const QuerySwitchCont = styled.div` + height:30px; + display: flex; + align-items: center; + font-size: 12px; + background-color: ${(props) => props.theme.buttonInactive}; + + border: 1px solid ${(props) => props.theme.buttonBorder}; + color: ${(props) => props.theme.textColor}; + border-radius: 3px; + margin-right:10px; +`; + +const QuerySwitchBtn = styled.div` + cursor: pointer; + display: flex; + align-items: center; + background: ${(props) => + props.selected ? props.theme.buttonDefault : props.theme.buttonInactive}; + border-left: ${(props) => + props.position === "last" + ? `1px solid ${props.theme.buttonBorder}` + : "none" }; + border-right: ${(props) => + props.position === "first" + ? `1px solid ${props.theme.buttonBorder}` + : "none" }; + border-radius: ${({ position }) => + position === "first" + ? "3px 0px 0px 3px" + : position === "last" + ? "0px 3px 3px 0px" + : "0px"}; + flex: 1; + height: 90%; + + padding: 0px 12px; + font-size: 12px; + line-height: 20px; +`; +const getBtnPos = (key, arr) => { + const arrLen = arr.length; + return key === 0 ? "first" : key === arrLen - 1 ? "last" : "center"; +}; + +export default function QueryTypeSwitch(props) { + const { options, defaultActive, onChange } = props; + + const [activeBtn, setActiveBtn] = useState(defaultActive); + + function setButtonValue(value) { + setActiveBtn(value); + onChange(value) + } + + return (<> + + + + + + {options && + options.map((value, key, arr) => ( + setButtonValue(value.value)} + > + {value.label} + + ))} + + + ); +} diff --git a/src/components/QueryTypeBar/index.js b/src/components/QueryTypeBar/index.js new file mode 100644 index 00000000..fee269bb --- /dev/null +++ b/src/components/QueryTypeBar/index.js @@ -0,0 +1,87 @@ +import { ThemeProvider } from "@emotion/react"; +import styled from "@emotion/styled"; +import { useState, useEffect } from "react"; +import { useSelector, useDispatch } from "react-redux"; +import { themes } from "../../theme/themes"; +import QueryLimit from "./components/QueryLimit"; +import QueryResolution from "./components/QueryResolution"; +import QueryTypeSwitch from "./components/QueryTypeSwitch"; + +/** + * this bar will: + * - select either range or instant as query type + * - limit ( auto 100 ) + * - resolution : 1/1 1/2 1/3 1/4 1/5 1/10 + */ + +const QueryTypeCont = styled.div` + display: flex; + padding:4px; + background: ${(props) => props.theme.widgetContainer}; + color: ${(props) => props.color}; +`; + +export default function QueryTypeBar() { + const dispatch = useDispatch(); + + // values from store + + const theme = useSelector((store) => store.theme); + + const queryType = useSelector((store) => store.queryType); + + const step = useSelector((store) => store.step); + + // local state values + + const [queryTypeSwitch, setQueryTypeSwitch] = useState(queryType); + + const [resolution, setResolution] = useState(step); + + // effects + + useEffect(() => { + setQueryTypeSwitch(queryType); + }, [queryType, setQueryTypeSwitch]); + + useEffect(() => { + setResolution(step); + }, [setResolution, step]); + + const SWITCH_OPTIONS = [ + { value: "range", label: "Range" }, + { value: "instant", label: "Instant" }, + ]; + const STEP_VALUES = [1, 2, 3, 4, 5, 10]; + + function formatResolution(step) { + return `1/${step}`; + } + + function onSwitchChange(e){ + console.log(e) + } + + const stepOptions = () => STEP_VALUES.map((value) => ({ value, label: formatResolution(value) })); + + return ( + + + + + + + + ); + + ///query type + + /// limit + + /// resolution +} diff --git a/src/plugins/queryhistory/index.js b/src/plugins/queryhistory/index.js index 7605b3f2..09161321 100644 --- a/src/plugins/queryhistory/index.js +++ b/src/plugins/queryhistory/index.js @@ -766,6 +766,7 @@ const QueryHistory = (props) => { style={{ maxHeight: "250px" }} open={historyOpen} variant={"persistent"} + theme={themes[theme]} > Embed View diff --git a/src/theme/light.js b/src/theme/light.js index aeb08a9d..a839b939 100644 --- a/src/theme/light.js +++ b/src/theme/light.js @@ -74,7 +74,7 @@ const widgetTitle = lightgrey.lg300; const widgetTitleBorder = lightgrey.lg700; const buttonDefault = white.w100; const buttonHover = white.w700; -const buttonInactive = black.b400; +const buttonInactive = lightgrey.lg10; const buttonBorder = lightgrey.lg100; const buttonText = white.w200; const inputTextFocus = orange.or100; From be31a3e636a451b6097082592297fa04dccee4ae Mon Sep 17 00:00:00 2001 From: Joel Guerra Date: Mon, 2 May 2022 18:35:25 +0200 Subject: [PATCH 02/11] fix add labels after pipe --- src/components/DataView/ValueTags.js | 91 ++++++++++++------- .../LabelBrowser/helpers/querybuilder.js | 41 ++++++++- 2 files changed, 96 insertions(+), 36 deletions(-) diff --git a/src/components/DataView/ValueTags.js b/src/components/DataView/ValueTags.js index 3eb244e1..da5d2708 100644 --- a/src/components/DataView/ValueTags.js +++ b/src/components/DataView/ValueTags.js @@ -3,28 +3,39 @@ import { queryBuilderWithLabels } from "../LabelBrowser/helpers/querybuilder"; import store from "../../store/store"; import loadLabelValues from "../../actions/loadLabelValues"; import loadLogs from "../../actions/loadLogs"; -import { ZoomIn, ZoomOut } from "@mui/icons-material/"; +import { ZoomIn, ZoomOut } from "@mui/icons-material/"; import { useSelector } from "react-redux"; import { themes } from "../../theme/themes"; import { ThemeProvider } from "@emotion/react"; -import styled from '@emotion/styled' +import styled from "@emotion/styled"; const ValueTagsStyled = styled.div` - color: ${props => props.theme.textPrimary}; - flex:1; + color: ${(props) => props.theme.textPrimary}; + flex: 1; &:hover { - background: ${props => props.theme.widgetContainer}; + background: ${(props) => props.theme.widgetContainer}; } -` +`; + export default function ValueTags({ tags }) { const theme = useSelector((store) => store.theme); const isEmbed = useSelector((store) => store.isEmbed); + const query = useSelector((store) => store.query); async function addLabel(e, key, value, isInverted = false) { e.preventDefault(); e.stopPropagation(); const { labels, apiUrl } = store.getState(); const label = labels.find((label) => label.name === key); + const symb = isInverted ? '!=' : '=' + const isAlreadySelected = query.includes(`${key}="${value}"`) + const isAlreadyInverted = query.includes(`${key}!="${value}"`) + + if((isAlreadyInverted && isInverted)|| (isAlreadySelected && !isInverted) ) { + return; + } + if (label) { + const labelValue = label.values.find((tag) => tag.name === value); if (labelValue?.selected && labelValue.inverted === isInverted) { return; @@ -40,7 +51,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 ); @@ -54,40 +65,56 @@ export default function ValueTags({ tags }) { } queryBuilderWithLabels(); + store.dispatch(loadLogs()); + } else { + queryBuilderWithLabels(true,[`${key}${symb}"${value}"`]) store.dispatch(loadLogs()); } } return ( - {Object.entries(tags).map(([key, value], k) => ( -
- {!isEmbed && ( - <> - addLabel(e, key, value)} - className={"icon"} - > - - - addLabel(e, key, value, true)} - className={"icon"} - > - - - - )} +
+ {!isEmbed && ( + <> + addLabel(e, key, value)} + className={"icon"} + > + + + + addLabel(e, key, value, true) + } + className={"icon"} + > + + + + )} - {key} - {value} -
+ {key} + {value} +
))}
diff --git a/src/components/LabelBrowser/helpers/querybuilder.js b/src/components/LabelBrowser/helpers/querybuilder.js index 7de52e05..219e7e1f 100644 --- a/src/components/LabelBrowser/helpers/querybuilder.js +++ b/src/components/LabelBrowser/helpers/querybuilder.js @@ -1,11 +1,42 @@ import { setQuery } from "../../../actions"; import store from "../../../store/store"; -export function queryBuilder(labels) { +export const PIPE_PARSE = [ + { + label: "json", + }, + { + label: "regexp", + text: 'regexp ""', + }, + { + label: "logfmt", + }, + { + label: "pattern", + }, +]; + +const pipeParseOpts = ["json", "regexp", "logfmt", "pattern", "~", "="]; + +export function queryBuilder(labels, hasPipe = false, pipeLabels = []) { const actualQuery = store.getState().query; const preTags = actualQuery.split("{")[0]; - const postTags = actualQuery.split("}")[1]; + let postTags = ""; + + if (hasPipe) { + postTags = actualQuery.split("}")[1]; + const expParse = actualQuery.split(/[|]/); + if (pipeParseOpts.some((s) => expParse[1].includes(s))) { + const pipeTags = ` | ${pipeLabels}`; + postTags = postTags.toString().concat(pipeTags.toString()); + } + } else { + postTags = actualQuery.split("}")[1]; + } + const selectedLabels = []; + for (const label of labels) { if (label.selected && label.values && label.values.length > 0) { const selectedValues = label.values @@ -27,12 +58,14 @@ export function queryBuilder(labels) { }); } } + return [preTags, "{", selectedLabels.join(","), "}", postTags].join(""); } -export function queryBuilderWithLabels() { +export function queryBuilderWithLabels(hasPipe = false, pipeLabels = []) { const labels = store.getState().labels; - const query = queryBuilder(labels); + const query = queryBuilder(labels, hasPipe, pipeLabels); + store.dispatch(setQuery(query)); } From 7a4557b25e30541e909561842d08ea1dc9f5ca37 Mon Sep 17 00:00:00 2001 From: Joel Guerra Date: Tue, 3 May 2022 17:36:05 +0200 Subject: [PATCH 03/11] add query type functionality --- src/actions/index.js | 2 + src/actions/loadLogs.js | 52 ++++++----- src/actions/setQueryTime.js | 6 ++ src/actions/setQueryType.js | 6 ++ src/components/DataView/ValueTags.js | 20 +++-- src/components/LabelBrowser/QueryBar.js | 11 --- .../ShowLabelsButton/ShowLabelsButton.js | 4 +- .../LabelBrowser/components/styled/index.js | 1 + .../QueryTypeBar/components/QueryLimit.js | 46 +++++----- .../components/QueryTypeSwitch.js | 2 +- src/components/QueryTypeBar/index.js | 14 +-- src/components/Switch/Switch.js | 87 +++++++++++++++++++ src/helpers/UpdateStateFromQueryParams.js | 53 ++++++----- src/store/createInitialState.js | 2 + src/store/reducer.js | 8 +- 15 files changed, 219 insertions(+), 95 deletions(-) create mode 100644 src/actions/setQueryTime.js create mode 100644 src/actions/setQueryType.js create mode 100644 src/components/Switch/Switch.js diff --git a/src/actions/index.js b/src/actions/index.js index bf067bae..4cdd7f56 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -6,6 +6,8 @@ export * from "./setRangeOpen"; export * from "./setTimeRangeLabel"; export * from "./setApiUrl"; export * from "./setQuery"; +export * from "./setQueryTime"; +export * from "./setQueryType"; export * from "./setIsSubmit"; export * from "./setMatrixData"; export * from "./setQueryHistory"; diff --git a/src/actions/loadLogs.js b/src/actions/loadLogs.js index 58051e05..5442afd8 100644 --- a/src/actions/loadLogs.js +++ b/src/actions/loadLogs.js @@ -6,7 +6,7 @@ import setMatrixData from "./setMatrixData"; import { nanoid } from "nanoid"; import { setStartTime, setStopTime } from "./"; import { findRangeByLabel } from "../components/StatusBar/components/daterangepicker/utils"; - +import { setQueryTime } from "./setQueryTime"; export default function loadLogs() { const localStore = store.getState(); @@ -21,34 +21,46 @@ export default function loadLogs() { } = localStore; let { start: startTs, stop: stopTs } = localStore; - function adjustForTimezone(date){ - + function adjustForTimezone(date) { var timeOffsetInMS = date.getTimezoneOffset() * 60000; date.setTime(date.getTime() + timeOffsetInMS); - return date + return date; } function getTimeParsed(time) { return time.getTime() + "000000"; } + const time = localStore.time || new Date().getTime() + "000000"; + + - const timeZone = new Date().getTimezoneOffset() + + const timeZone = new Date().getTimezoneOffset(); const parsedStart = getTimeParsed(startTs); const parsedStop = getTimeParsed(stopTs); - const parsedTime = "&start=" + (from || parsedStart) + "&end=" + (to || parsedStop); + const parsedTime = + "&start=" + (from || parsedStart) + "&end=" + (to || parsedStop); if (findRangeByLabel(rangeLabel)) { - ({ dateStart: startTs, dateEnd: stopTs } = - findRangeByLabel(rangeLabel)); + ({ dateStart: startTs, dateEnd: stopTs } = findRangeByLabel( + rangeLabel + )); } store.dispatch(setStartTime(startTs)); store.dispatch(setStopTime(stopTs)); - + const queryType = store.getState().queryType; 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 queryUrl = `${url}/loki/api/v1`; + + const rangeEP = `${queryUrl}/query_range?query=${encodedQuery}&limit=${limit}${parsedTime}${queryStep}`; + const instantEP = `${queryUrl}/query?query=${encodedQuery}&limit=${limit}&time=${time}`; + + const endpoint = { instant: instantEP, range: rangeEP }; + + // const getUrl = `${url}/loki/api/v1/query_range?query=${encodedQuery}&limit=${limit}${parsedTime}${queryStep}`; const options = { method: "GET", @@ -64,8 +76,8 @@ export default function loadLogs() { type === "streams" ? fromNanoSec(ts) : type === "matrix" - ? toMiliseC(ts) - : ts; + ? toMiliseC(ts) + : ts; const mapStreams = (streams, messages, type) => { streams.forEach((stream) => { stream.values.forEach((log, i) => { @@ -78,8 +90,8 @@ export default function loadLogs() { type === "streams" ? stream.stream : type === "matrix" - ? stream.metric - : {}, + ? stream.metric + : {}, showTs: true, showLabels: false, id: nanoid(), @@ -95,7 +107,7 @@ export default function loadLogs() { dispatch(setMatrixData([])); await axios - .get(getUrl, options) + .get(endpoint[queryType], options) ?.then((response) => { if (response?.data?.data) { let messages = []; @@ -111,6 +123,9 @@ export default function loadLogs() { dispatch(setLogs(messSorted || [])); dispatch(setLoading(false)); + if(queryType === 'instant') { + store.dispatch(setQueryTime(time)) + } } } @@ -120,22 +135,19 @@ export default function loadLogs() { dispatch(setMatrixData(idResult || [])); dispatch(setLoading(false)); } - // dispatch(setLoading(false)); + // dispatch(setLoading(false)); } else { dispatch(setLogs([])); dispatch(setMatrixData([])); dispatch(setLoading(false)); } - // dispatch(setLoading(false)); + // dispatch(setLoading(false)); }) .catch((error) => { - dispatch(setLogs([])); dispatch(setMatrixData([])); dispatch(setLoading(false)); - - }); }; } diff --git a/src/actions/setQueryTime.js b/src/actions/setQueryTime.js new file mode 100644 index 00000000..7f77f45a --- /dev/null +++ b/src/actions/setQueryTime.js @@ -0,0 +1,6 @@ +export const setQueryTime = (time) => (dispatch)=>{ + dispatch({ + type: 'SET_QUERY_TIME', + time + }) +} diff --git a/src/actions/setQueryType.js b/src/actions/setQueryType.js new file mode 100644 index 00000000..22b71896 --- /dev/null +++ b/src/actions/setQueryType.js @@ -0,0 +1,6 @@ +export const setQueryType = (queryType) => (dispatch) => { + dispatch({ + type: "SET_QUERY_TYPE", + queryType, + }); +}; diff --git a/src/components/DataView/ValueTags.js b/src/components/DataView/ValueTags.js index da5d2708..cd00c52e 100644 --- a/src/components/DataView/ValueTags.js +++ b/src/components/DataView/ValueTags.js @@ -3,7 +3,7 @@ import { queryBuilderWithLabels } from "../LabelBrowser/helpers/querybuilder"; import store from "../../store/store"; import loadLabelValues from "../../actions/loadLabelValues"; import loadLogs from "../../actions/loadLogs"; -import { ZoomIn, ZoomOut } from "@mui/icons-material/"; +import { ZoomIn, ZoomOut } from "@mui/icons-material/"; import { useSelector } from "react-redux"; import { themes } from "../../theme/themes"; import { ThemeProvider } from "@emotion/react"; @@ -26,16 +26,18 @@ export default function ValueTags({ tags }) { e.stopPropagation(); const { labels, apiUrl } = store.getState(); const label = labels.find((label) => label.name === key); - const symb = isInverted ? '!=' : '=' - const isAlreadySelected = query.includes(`${key}="${value}"`) - const isAlreadyInverted = query.includes(`${key}!="${value}"`) + const symb = isInverted ? "!=" : "="; + const isAlreadySelected = query.includes(`${key}="${value}"`); + const isAlreadyInverted = query.includes(`${key}!="${value}"`); - if((isAlreadyInverted && isInverted)|| (isAlreadySelected && !isInverted) ) { - return; - } + if ( + (isAlreadyInverted && isInverted) || + (isAlreadySelected && !isInverted) + ) { + return; + } if (label) { - const labelValue = label.values.find((tag) => tag.name === value); if (labelValue?.selected && labelValue.inverted === isInverted) { return; @@ -67,7 +69,7 @@ export default function ValueTags({ tags }) { store.dispatch(loadLogs()); } else { - queryBuilderWithLabels(true,[`${key}${symb}"${value}"`]) + queryBuilderWithLabels(true, [`${key}${symb}"${value}"`]); store.dispatch(loadLogs()); } } diff --git a/src/components/LabelBrowser/QueryBar.js b/src/components/LabelBrowser/QueryBar.js index eb6c00fd..8f19b713 100644 --- a/src/components/LabelBrowser/QueryBar.js +++ b/src/components/LabelBrowser/QueryBar.js @@ -176,17 +176,6 @@ export const QueryBar = () => { isMobile={false} /> - {/* - - - */} diff --git a/src/components/LabelBrowser/components/ShowLabelsButton/ShowLabelsButton.js b/src/components/LabelBrowser/components/ShowLabelsButton/ShowLabelsButton.js index fb47c0fe..18d775dc 100644 --- a/src/components/LabelBrowser/components/ShowLabelsButton/ShowLabelsButton.js +++ b/src/components/LabelBrowser/components/ShowLabelsButton/ShowLabelsButton.js @@ -26,9 +26,9 @@ export default function ShowLabelsButton({ isMobile={isMobile} > {labelsBrowserOpen ? ( - + ) : ( - + )}{" "} {LOG_BROWSER} diff --git a/src/components/LabelBrowser/components/styled/index.js b/src/components/LabelBrowser/components/styled/index.js index 028c5b86..31255b81 100644 --- a/src/components/LabelBrowser/components/styled/index.js +++ b/src/components/LabelBrowser/components/styled/index.js @@ -29,6 +29,7 @@ export const ShowLabelsBtn = styled(BtnSmall)` transition: 0.25s all; justify-content: flex-start; color: ${({ theme }) => theme.textColor}; + height: 28px; &:hover { background: ${({ theme }) => theme.buttonHover}; } diff --git a/src/components/QueryTypeBar/components/QueryLimit.js b/src/components/QueryTypeBar/components/QueryLimit.js index 67a10f7c..14d1aad7 100644 --- a/src/components/QueryTypeBar/components/QueryLimit.js +++ b/src/components/QueryTypeBar/components/QueryLimit.js @@ -1,51 +1,53 @@ - import styled from "@emotion/styled"; import { useEffect, useState } from "react"; import { useSelector, useDispatch } from "react-redux"; import { setQueryLimit } from "../../../actions"; const InputGroup = styled.div` -display:flex; -margin-right:10px; + display: flex; + margin-right: 10px; `; const Label = styled.div` -color:${props => props.theme.textColor}; -background: ${props => props.theme.buttonInactive}; -display:flex; -align-items: center; -justify-content: center; -font-size: 12px; -padding:0px 8px; + color: ${(props) => props.theme.textColor}; + background: ${(props) => props.theme.buttonInactive}; + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + padding: 0px 8px; `; const Input = styled.input` -flex:1; -background : ${props => props.theme.inputBg}; -color: ${props => props.theme.textColor}; -border: 1px solid ${props => props.theme.buttonBorder}; -border-radius: 3px; -max-width: 60px; -padding-left: 8px; + flex: 1; + background: ${(props) => props.theme.inputBg}; + color: ${(props) => props.theme.textColor}; + border: 1px solid ${(props) => props.theme.buttonBorder}; + border-radius: 3px; + max-width: 60px; + padding-left: 8px; `; export default function QueryLimit() { - const dispatch = useDispatch; + const dispatch = useDispatch(); const limit = useSelector((store) => store.limit); const [editedValue, setEditedValue] = useState(limit); useEffect(() => { setEditedValue(limit); }, [limit, setEditedValue]); - function onLimitChange(e){ - const limit = e.target.value - dispatch(setQueryLimit(limit)) + function onLimitChange(e) { + dispatch(setQueryLimit(e.target.value)); } return ( - + ); } diff --git a/src/components/QueryTypeBar/components/QueryTypeSwitch.js b/src/components/QueryTypeBar/components/QueryTypeSwitch.js index 788f062e..1abf5249 100644 --- a/src/components/QueryTypeBar/components/QueryTypeSwitch.js +++ b/src/components/QueryTypeBar/components/QueryTypeSwitch.js @@ -10,7 +10,7 @@ font-size: 12px; padding:0px 8px; `; const QuerySwitchCont = styled.div` - height:30px; + display: flex; align-items: center; font-size: 12px; diff --git a/src/components/QueryTypeBar/index.js b/src/components/QueryTypeBar/index.js index fee269bb..be780945 100644 --- a/src/components/QueryTypeBar/index.js +++ b/src/components/QueryTypeBar/index.js @@ -2,6 +2,7 @@ import { ThemeProvider } from "@emotion/react"; import styled from "@emotion/styled"; import { useState, useEffect } from "react"; import { useSelector, useDispatch } from "react-redux"; +import { setQueryType } from "../../actions"; import { themes } from "../../theme/themes"; import QueryLimit from "./components/QueryLimit"; import QueryResolution from "./components/QueryResolution"; @@ -16,9 +17,10 @@ import QueryTypeSwitch from "./components/QueryTypeSwitch"; const QueryTypeCont = styled.div` display: flex; - padding:4px; + padding: 4px; background: ${(props) => props.theme.widgetContainer}; color: ${(props) => props.color}; + height:26px; `; export default function QueryTypeBar() { @@ -58,20 +60,20 @@ export default function QueryTypeBar() { return `1/${step}`; } - function onSwitchChange(e){ - console.log(e) + function onSwitchChange(e) { + dispatch(setQueryType(e)); } - const stepOptions = () => STEP_VALUES.map((value) => ({ value, label: formatResolution(value) })); + const stepOptions = () => + STEP_VALUES.map((value) => ({ value, label: formatResolution(value) })); return ( diff --git a/src/components/Switch/Switch.js b/src/components/Switch/Switch.js new file mode 100644 index 00000000..6901c9b6 --- /dev/null +++ b/src/components/Switch/Switch.js @@ -0,0 +1,87 @@ +import styled from "@emotion/styled"; +import { useState } from "react"; +const Label = styled.div` + color: ${(props) => props.theme.textColor}; + background: ${(props) => props.theme.buttonInactive}; + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + padding: 0px 8px; +`; +const SwitchCont = styled.div` + + display: flex; + align-items: center; + font-size: 12px; + background-color: ${(props) => props.theme.buttonInactive}; + + border: 1px solid ${(props) => props.theme.buttonBorder}; + color: ${(props) => props.theme.textColor}; + border-radius: 3px; + margin-right: 10px; +`; + +const SwitchBtn = styled.div` + cursor: pointer; + display: flex; + align-items: center; + background: ${(props) => + props.selected + ? props.theme.buttonDefault + : props.theme.buttonInactive}; + border-left: ${(props) => + props.position === "last" + ? `1px solid ${props.theme.buttonBorder}` + : "none"}; + border-right: ${(props) => + props.position === "first" + ? `1px solid ${props.theme.buttonBorder}` + : "none"}; + border-radius: ${({ position }) => + position === "first" + ? "3px 0px 0px 3px" + : position === "last" + ? "0px 3px 3px 0px" + : "0px"}; + flex: 1; + height: 90%; + + padding: 0px 12px; + font-size: 12px; + line-height: 20px; +`; +const getBtnPos = (key, arr) => { + const arrLen = arr.length; + return key === 0 ? "first" : key === arrLen - 1 ? "last" : "center"; +}; + +export default function QueryTypeSwitch(props) { + const { options, defaultActive, onChange, label } = props; + + const [activeBtn, setActiveBtn] = useState(defaultActive); + + function setButtonValue(value) { + setActiveBtn(value); + onChange(value); + } + + return ( + <> + + + {options && + options.map((value, key, arr) => ( + setButtonValue(value.value)} + > + {value.label} + + ))} + + + ); +} diff --git a/src/helpers/UpdateStateFromQueryParams.js b/src/helpers/UpdateStateFromQueryParams.js index d4e7a731..fe2de29b 100644 --- a/src/helpers/UpdateStateFromQueryParams.js +++ b/src/helpers/UpdateStateFromQueryParams.js @@ -2,20 +2,22 @@ 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, + setQueryTime, setQueryStep, + setQueryType, setStartTime, setStopTime, setTheme, - } from "../actions"; -import loadLabels from "../actions/loadLabels" +import loadLabels from "../actions/loadLabels"; import loadLabelValues from "../actions/loadLabelValues"; import setFromTime from "../actions/setFromTime"; import setIsEmbed from "../actions/setIsEmbed"; @@ -26,8 +28,8 @@ import { setUrlQueryParams } from "../actions/setUrlQueryParams"; import { environment } from "../environment/env.dev"; import store from "../store/store"; export function UpdateStateFromQueryParams() { - - const isLightTheme = window.matchMedia('(prefers-color-scheme: light)').matches; + const isLightTheme = window.matchMedia("(prefers-color-scheme: light)") + .matches; const { hash } = useLocation(); const dispatch = useDispatch(); @@ -36,48 +38,56 @@ export function UpdateStateFromQueryParams() { 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 to = useSelector((store) => store.to); const step = useSelector((store) => store.step); - const labels = useSelector((store) => store.labels) + 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 theme = useSelector((store) => isLightTheme ? 'light' : store.theme) + const queryType = useSelector((store) => store.queryType); + const time = useSelector((store) => store.time); + const theme = useSelector((store) => + isLightTheme ? "light" : store.theme + ); const STORE_KEYS = { apiUrl, query, + queryType, start, limit, step, end: stop, from, to, + time, isSubmit, isEmbed, - theme + theme, }; const STORE_ACTIONS = { apiUrl: setApiUrl, query: setQuery, + queryType: setQueryType, start: setStartTime, limit: setQueryLimit, step: setQueryStep, end: setStopTime, from: setFromTime, to: setToTime, + time: setQueryTime, isSubmit: setIsSubmit, isEmbed: setIsEmbed, - theme: setTheme + theme: setTheme, }; - const STRING_VALUES = ["limit", "step", "apiUrl", "theme"]; + const STRING_VALUES = ["limit", "step", "apiUrl", "theme", "queryType","time"]; const QUERY_VALUE = "query"; - const TIME_VALUES = ["start", "end",]; + const TIME_VALUES = ["start", "end"]; const BOOLEAN_VALUES = ["isSubmit", "isEmbed"]; @@ -106,9 +116,9 @@ export function UpdateStateFromQueryParams() { startParams[param] !== "" ) { dispatch(STORE_ACTIONS[param](startParams[param])); - - if(param === 'apiUrl') { - dispatch(loadLabels(startParams[param])) + + if (param === "apiUrl") { + dispatch(loadLabels(startParams[param])); } } else if ( QUERY_VALUE === param && @@ -139,12 +149,14 @@ export function UpdateStateFromQueryParams() { } }); - decodeQuery(decodeURIComponent(startParams.query),apiUrl,labels); + 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); @@ -174,7 +186,6 @@ export function UpdateStateFromQueryParams() { window.location.hash = urlFromHash; } - }, []); useEffect(() => { @@ -219,8 +230,7 @@ export function UpdateStateFromQueryParams() { }, [STORE_KEYS]); } -export function decodeQuery(query, apiUrl, labels=[]) { - +export function decodeQuery(query, apiUrl, labels = []) { const queryArr = query ?.match(/[^{\}]+(?=})/g, "$1") ?.map((m) => m.split(",")) @@ -270,11 +280,10 @@ export function decodeQuery(query, apiUrl, labels=[]) { }; labelObj.values.push(valueObj); labelsFromQuery.push(labelObj); - } }); - const newLabels = labels + const newLabels = labels; newLabels?.forEach((label) => { if (label.selected && label.values > 0) { diff --git a/src/store/createInitialState.js b/src/store/createInitialState.js index 46f5c51f..bbf0705a 100644 --- a/src/store/createInitialState.js +++ b/src/store/createInitialState.js @@ -25,6 +25,7 @@ export default function initialState() { linksHistory: linkService.getAll() || [], timeRange: [], query: urlState.query || "", + queryType: urlState.queryType || 'range', logs: [], matrixData: [], loading: false, @@ -35,6 +36,7 @@ export default function initialState() { .subtract(5, "minutes") .format("YYYY-MM-DDTHH:mm:ss.SSSZ") ), + time: urlState.time || '', stop: urlState.end || new Date(moment(Date.now()).format("YYYY-MM-DDTHH:mm:ss.SSSZ")), diff --git a/src/store/reducer.js b/src/store/reducer.js index eba0a35c..9d351013 100644 --- a/src/store/reducer.js +++ b/src/store/reducer.js @@ -40,6 +40,8 @@ const reducer = (state, action) => { return { ...state, apiErrors: action.apiErrors }; case "SET_URL_QUERY_PARAMS": return { ...state, urlQueryParams: action.urlQueryParams }; + case "SET_QUERY_TYPE": + return { ...state, queryType: action.queryType }; case "SET_URL_LOCATION": return { ...state, urlLocation: action.urlLocation }; case "SET_IS_SUBMIT": @@ -62,8 +64,10 @@ const reducer = (state, action) => { return { ...state, notifications: action.payload }; case "SET_DEBUG_MODE": return { ...state, debugMode: action.debugMode }; - case "SET_THEME": - return {...state, theme: action.theme}; + case "SET_THEME": + return { ...state, theme: action.theme }; + case "SET_QUERY_TIME": + return { ...state, time: action.time }; default: return { ...state }; } From 696bc139f159d122ca6b9b414a47398f7ba7d25b Mon Sep 17 00:00:00 2001 From: Joel Guerra Date: Fri, 6 May 2022 17:55:40 +0200 Subject: [PATCH 04/11] resolution calv init --- src/actions/loadLogs.js | 25 ++-- .../actions/setQueryResolution.js | 6 + .../components/QueryResolution.js | 26 ++-- src/components/QueryTypeBar/helpers/index.js | 120 ++++++++++++++++++ src/components/QueryTypeBar/index.js | 4 +- src/store/createInitialState.js | 1 + src/store/reducer.js | 2 + 7 files changed, 163 insertions(+), 21 deletions(-) create mode 100644 src/components/QueryTypeBar/actions/setQueryResolution.js create mode 100644 src/components/QueryTypeBar/helpers/index.js diff --git a/src/actions/loadLogs.js b/src/actions/loadLogs.js index 5442afd8..4e95966d 100644 --- a/src/actions/loadLogs.js +++ b/src/actions/loadLogs.js @@ -7,6 +7,7 @@ import { nanoid } from "nanoid"; import { setStartTime, setStopTime } from "./"; import { findRangeByLabel } from "../components/StatusBar/components/daterangepicker/utils"; import { setQueryTime } from "./setQueryTime"; +// import adjustedStep from "../components/QueryTypeBar/helpers"; export default function loadLogs() { const localStore = store.getState(); @@ -14,6 +15,7 @@ export default function loadLogs() { query, limit, step, + // queryResolution, apiUrl, label: rangeLabel, from, @@ -21,21 +23,23 @@ export default function loadLogs() { } = localStore; let { start: startTs, stop: stopTs } = localStore; - function adjustForTimezone(date) { - var timeOffsetInMS = date.getTimezoneOffset() * 60000; - date.setTime(date.getTime() + timeOffsetInMS); - return date; - } + // @TODO : add target for multiple queries + + // function adjustForTimezone(date) { + // var timeOffsetInMS = date.getTimezoneOffset() * 60000; + // date.setTime(date.getTime() + timeOffsetInMS); + // return date; + // } function getTimeParsed(time) { return time.getTime() + "000000"; } const time = localStore.time || new Date().getTime() + "000000"; - - + - const timeZone = new Date().getTimezoneOffset(); + + // const timeZone = new Date().getTimezoneOffset(); const parsedStart = getTimeParsed(startTs); const parsedStop = getTimeParsed(stopTs); const parsedTime = @@ -51,6 +55,11 @@ export default function loadLogs() { const queryType = store.getState().queryType; const origin = window.location.origin; const url = apiUrl; + + // const range = { to : (to || parsedStop), from: (from || parsedStart) } + // console.log(range) + // const step = adjustedStep({resolution:queryResolution},{range} ) + const queryStep = `&step=${step || 120}`; const encodedQuery = `${encodeURIComponent(query)}`; const queryUrl = `${url}/loki/api/v1`; diff --git a/src/components/QueryTypeBar/actions/setQueryResolution.js b/src/components/QueryTypeBar/actions/setQueryResolution.js new file mode 100644 index 00000000..e317f589 --- /dev/null +++ b/src/components/QueryTypeBar/actions/setQueryResolution.js @@ -0,0 +1,6 @@ +export const setQueryResolution = ( queryResolution ) => (dispatch) => { + dispatch({ + type: 'SET_QUERY_RESOLUTION', + queryResolution + }) +} \ No newline at end of file diff --git a/src/components/QueryTypeBar/components/QueryResolution.js b/src/components/QueryTypeBar/components/QueryResolution.js index 9aa725da..cd55d805 100644 --- a/src/components/QueryTypeBar/components/QueryResolution.js +++ b/src/components/QueryTypeBar/components/QueryResolution.js @@ -1,9 +1,13 @@ import styled from "@emotion/styled"; import { useState } from "react"; +import { useDispatch } from "react-redux"; +import { setQueryResolution } from "../actions/setQueryResolution"; +import { DEFAULT_RESOLUTION, RESOLUTION_OPTIONS } from "../helpers"; + const Label = styled.div` color: ${(props) => props.theme.textColor}; background: ${(props) => props.theme.buttonInactive}; - + display: flex; align-items: center; justify-content: center; @@ -18,12 +22,12 @@ const ResSelect = styled.select` font-size: 14px; color: ${(props) => props.theme.textColor}; background: ${(props) => props.theme.inputBg}; - border: 1px solid ${props => props.theme.buttonBorder}; + border: 1px solid ${(props) => props.theme.buttonBorder}; border-radius: 3px; padding: 4px 8px; line-height: 20px; flex: 1; - max-width: 60px; + max-width: 70px; &::-webkit-scrollbar { width: 5px; background: ${(props) => props.theme.inputBg}; @@ -36,21 +40,21 @@ const ResSelect = styled.select` `; export default function QueryResolution() { - const resolutions = ["1/1", "1/2", "1/3", "1/4", "1/10"]; - - const [resValue, setResValue] = useState(resolutions[0]); + const dispatch = useDispatch(); + const [resValue, setResValue] = useState(DEFAULT_RESOLUTION.value); function handleResChange(e) { - setResValue(e); + setResValue(parseInt(e.target.value)); + dispatch(setQueryResolution(parseInt(e.target.value))); } return ( <> - - {resolutions.map((res, idx) => ( - ); diff --git a/src/store/createInitialState.js b/src/store/createInitialState.js index bbf0705a..7acf5c54 100644 --- a/src/store/createInitialState.js +++ b/src/store/createInitialState.js @@ -29,6 +29,7 @@ export default function initialState() { logs: [], matrixData: [], loading: false, + queryResolution: 1, start: urlState.start || new Date( diff --git a/src/store/reducer.js b/src/store/reducer.js index 9d351013..74a78c76 100644 --- a/src/store/reducer.js +++ b/src/store/reducer.js @@ -68,6 +68,8 @@ const reducer = (state, action) => { return { ...state, theme: action.theme }; case "SET_QUERY_TIME": return { ...state, time: action.time }; + case "SET_QUERY_RESOLUTION": + return {...state, queryResolution: action.queryResolution}; default: return { ...state }; } From 56944b715ce4364590e75bfe321de271f334d400 Mon Sep 17 00:00:00 2001 From: Joel Guerra Date: Mon, 9 May 2022 09:43:41 +0200 Subject: [PATCH 05/11] fix: cleanup --- src/actions/loadLogs.js | 27 +---------- src/components/LabelBrowser/QueryBar.js | 2 - .../actions/setQueryResolution.js | 10 ++-- .../QueryTypeBar/components/QueryLabel.js | 10 ---- src/components/QueryTypeBar/helpers/index.js | 48 ------------------- src/components/QueryTypeBar/index.js | 42 +--------------- 6 files changed, 8 insertions(+), 131 deletions(-) delete mode 100644 src/components/QueryTypeBar/components/QueryLabel.js diff --git a/src/actions/loadLogs.js b/src/actions/loadLogs.js index 4e95966d..49d3c1de 100644 --- a/src/actions/loadLogs.js +++ b/src/actions/loadLogs.js @@ -15,7 +15,6 @@ export default function loadLogs() { query, limit, step, - // queryResolution, apiUrl, label: rangeLabel, from, @@ -23,23 +22,10 @@ export default function loadLogs() { } = localStore; let { start: startTs, stop: stopTs } = localStore; - // @TODO : add target for multiple queries - - // function adjustForTimezone(date) { - // var timeOffsetInMS = date.getTimezoneOffset() * 60000; - // date.setTime(date.getTime() + timeOffsetInMS); - // return date; - // } - function getTimeParsed(time) { return time.getTime() + "000000"; } const time = localStore.time || new Date().getTime() + "000000"; - - - - - // const timeZone = new Date().getTimezoneOffset(); const parsedStart = getTimeParsed(startTs); const parsedStop = getTimeParsed(stopTs); const parsedTime = @@ -56,10 +42,6 @@ export default function loadLogs() { const origin = window.location.origin; const url = apiUrl; - // const range = { to : (to || parsedStop), from: (from || parsedStart) } - // console.log(range) - // const step = adjustedStep({resolution:queryResolution},{range} ) - const queryStep = `&step=${step || 120}`; const encodedQuery = `${encodeURIComponent(query)}`; const queryUrl = `${url}/loki/api/v1`; @@ -69,8 +51,6 @@ export default function loadLogs() { const endpoint = { instant: instantEP, range: rangeEP }; - // const getUrl = `${url}/loki/api/v1/query_range?query=${encodedQuery}&limit=${limit}${parsedTime}${queryStep}`; - const options = { method: "GET", headers: { @@ -109,7 +89,6 @@ export default function loadLogs() { }); }; - //const mapMatrix return async function (dispatch) { dispatch(setLoading(true)); dispatch(setLogs([])); @@ -132,8 +111,8 @@ export default function loadLogs() { dispatch(setLogs(messSorted || [])); dispatch(setLoading(false)); - if(queryType === 'instant') { - store.dispatch(setQueryTime(time)) + if (queryType === "instant") { + store.dispatch(setQueryTime(time)); } } } @@ -144,13 +123,11 @@ export default function loadLogs() { dispatch(setMatrixData(idResult || [])); dispatch(setLoading(false)); } - // dispatch(setLoading(false)); } else { dispatch(setLogs([])); dispatch(setMatrixData([])); dispatch(setLoading(false)); } - // dispatch(setLoading(false)); }) .catch((error) => { dispatch(setLogs([])); diff --git a/src/components/LabelBrowser/QueryBar.js b/src/components/LabelBrowser/QueryBar.js index 8f19b713..ff1fe5cd 100644 --- a/src/components/LabelBrowser/QueryBar.js +++ b/src/components/LabelBrowser/QueryBar.js @@ -25,8 +25,6 @@ import debugLog from "./helpers/debugLog"; import { ThemeProvider } from "@emotion/react"; import { themes } from "../../theme/themes"; import { sendLabels } from "../../hooks/useLabels"; -import CustomizedDividers from "../QueryTypeBar/components/QueryTypeSwitch"; -import QueryTypeSwitch from "../QueryTypeBar/components/QueryTypeSwitch"; import QueryTypeBar from "../QueryTypeBar"; export const QueryBar = () => { diff --git a/src/components/QueryTypeBar/actions/setQueryResolution.js b/src/components/QueryTypeBar/actions/setQueryResolution.js index e317f589..8eea64f5 100644 --- a/src/components/QueryTypeBar/actions/setQueryResolution.js +++ b/src/components/QueryTypeBar/actions/setQueryResolution.js @@ -1,6 +1,6 @@ -export const setQueryResolution = ( queryResolution ) => (dispatch) => { +export const setQueryResolution = (queryResolution) => (dispatch) => { dispatch({ - type: 'SET_QUERY_RESOLUTION', - queryResolution - }) -} \ No newline at end of file + type: "SET_QUERY_RESOLUTION", + queryResolution, + }); +}; diff --git a/src/components/QueryTypeBar/components/QueryLabel.js b/src/components/QueryTypeBar/components/QueryLabel.js deleted file mode 100644 index 6bad2298..00000000 --- a/src/components/QueryTypeBar/components/QueryLabel.js +++ /dev/null @@ -1,10 +0,0 @@ -import styled from "@emotion/styled"; - -const StyledLabel = styled.div` - -` - -export default function QueryLabel (props) { - const {message, description} = props; - return (<>) -} \ No newline at end of file diff --git a/src/components/QueryTypeBar/helpers/index.js b/src/components/QueryTypeBar/helpers/index.js index 93a12bfe..f96808c9 100644 --- a/src/components/QueryTypeBar/helpers/index.js +++ b/src/components/QueryTypeBar/helpers/index.js @@ -13,7 +13,6 @@ function adjustInterval( if (safeInterval > 1) { safeInterval = Math.ceil(safeInterval); } - console.log(safeInterval) return Math.max(resolution * dynamicInterval, safeInterval); } @@ -27,7 +26,6 @@ function getIntervalInfo(timespanMs) { let intervalMs = timespanMs; let interval = ""; - // below 5 seconds we force the resolution to be per 1ms as interval in scopedVars is not less than 10ms if (timespanMs < SECOND * 5) { intervalMs = MILLISECOND; interval = "1ms"; @@ -60,61 +58,15 @@ export const RESOLUTION_OPTIONS = [DEFAULT_RESOLUTION].concat( })) ); -/** - * options: { range : { from, to }} - * target: { resolution } - */ - -/** - * - * @param {*} target - * @param {*} options - * @returns - */ export default function adjustedStep(target, options) { - console.log(target,options) - // resolution = resolution denominator const resolution = target.resolution || DEFAULT_RESOLUTION.value; const startNs = getTime(options.range.from, false); const endNs = getTime(options.range.to, true); const rangeMs = Math.ceil((endNs - startNs) / 1e6); - - console.log(rangeMs) - console.log(resolution) const { intervalMs } = getIntervalInfo(rangeMs); - console.log(intervalMs) - const intl = adjustInterval(intervalMs || 1000, resolution, rangeMs); console.log(intl) return Math.ceil(intl) / 1000; } - - -// @TODO histogram request - -// function getLogsVolumeDataProvider(request) { -// const isLogsVolumeAvailable = request.targets.some((target) => target.expr && !isMetricsQuery(target.expr)); -// if (!isLogsVolumeAvailable) { -// return undefined; -// } -// // the targets are the containers -// const logsVolumeRequest = JSON.parse(JSON.stringify(request)); -// logsVolumeRequest.targets = logsVolumeRequest.targets -// .filter((target) => target.expr && !isMetricsQuery(target.expr)) -// .map((target) => { -// return { -// ...target, -// instant: false, -// volumeQuery: true, -// expr: `sum by (level) (count_over_time(${target.expr}[$__interval]))`, -// }; -// }); - -// return queryLogsVolume(this, logsVolumeRequest, { -// extractLevel, -// range: request.range, -// targets: request.targets, -// }); -// } diff --git a/src/components/QueryTypeBar/index.js b/src/components/QueryTypeBar/index.js index 0136e363..f283d7bd 100644 --- a/src/components/QueryTypeBar/index.js +++ b/src/components/QueryTypeBar/index.js @@ -5,68 +5,35 @@ import { useSelector, useDispatch } from "react-redux"; import { setQueryType } from "../../actions"; import { themes } from "../../theme/themes"; import QueryLimit from "./components/QueryLimit"; -// import QueryResolution from "./components/QueryResolution"; import QueryTypeSwitch from "./components/QueryTypeSwitch"; -/** - * this bar will: - * - select either range or instant as query type - * - limit ( auto 100 ) - * - resolution : 1/1 1/2 1/3 1/4 1/5 1/10 - */ - const QueryTypeCont = styled.div` display: flex; padding: 4px; background: ${(props) => props.theme.widgetContainer}; color: ${(props) => props.color}; - height:26px; + height: 26px; `; export default function QueryTypeBar() { const dispatch = useDispatch(); - - // values from store - const theme = useSelector((store) => store.theme); - const queryType = useSelector((store) => store.queryType); - - const step = useSelector((store) => store.step); - - // local state values - const [queryTypeSwitch, setQueryTypeSwitch] = useState(queryType); - const [resolution, setResolution] = useState(step); - - // effects - useEffect(() => { setQueryTypeSwitch(queryType); }, [queryType, setQueryTypeSwitch]); - useEffect(() => { - setResolution(step); - }, [setResolution, step]); - const SWITCH_OPTIONS = [ { value: "range", label: "Range" }, { value: "instant", label: "Instant" }, ]; - const STEP_VALUES = [1, 2, 3, 4, 5, 10]; - - function formatResolution(step) { - return `1/${step}`; - } function onSwitchChange(e) { dispatch(setQueryType(e)); } - const stepOptions = () => - STEP_VALUES.map((value) => ({ value, label: formatResolution(value) })); - return ( @@ -76,14 +43,7 @@ export default function QueryTypeBar() { defaultActive={queryTypeSwitch} /> - {/* */} ); - - ///query type - - /// limit - - /// resolution } From e442cbdd926d9fe7404a2e8644003768e6571958 Mon Sep 17 00:00:00 2001 From: Joel Guerra Date: Tue, 10 May 2022 09:56:38 +0200 Subject: [PATCH 06/11] fix empty view, optimization improve --- src/actions/index.js | 1 + src/actions/loadLabelValues.js | 1 + src/actions/loadLabels.js | 3 + src/actions/loadLogs.js | 156 ++++++++++++------ src/actions/setFromTime.js | 13 +- src/actions/setIsEmptyView.js | 8 + src/actions/setLabelValues.js | 15 +- src/actions/setLabels.js | 13 +- src/actions/setQueryLimit.js | 13 +- src/components/DataView/DataView.js | 14 +- src/components/DataView/EmptyView.js | 25 ++- src/components/DataView/LogsRow.js | 1 + src/components/DataView/ValueTags.js | 2 + src/components/DataView/helpers/index.js | 1 + src/components/LabelBrowser/QueryBar.js | 6 +- src/components/LabelBrowser/ValuesList.js | 11 +- .../components/apiselector/ApiSelector.js | 4 +- src/helpers/UpdateStateFromQueryParams.js | 8 +- src/plugins/charts/index.js | 2 + src/store/createInitialState.js | 1 + src/store/reducer.js | 2 + 21 files changed, 201 insertions(+), 99 deletions(-) create mode 100644 src/actions/setIsEmptyView.js diff --git a/src/actions/index.js b/src/actions/index.js index 4cdd7f56..2380f243 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -20,3 +20,4 @@ export * from "./removeAlert"; export * from "./setFromTime"; export * from "./setToTime"; export * from "./setTheme"; +export * from "./setIsEmptyView"; \ No newline at end of file diff --git a/src/actions/loadLabelValues.js b/src/actions/loadLabelValues.js index 00e8ec25..285905ec 100644 --- a/src/actions/loadLabelValues.js +++ b/src/actions/loadLabelValues.js @@ -46,6 +46,7 @@ export default function loadLabelValues(label, labelList, apiUrl) { l.values = [...values]; } }); + console.log("labels changed from here") dispatch(setLabels(lsList)) } else if(!response) { dispatch(setApiError('URL NOT FOUND')) diff --git a/src/actions/loadLabels.js b/src/actions/loadLabels.js index 8649f907..72ef9049 100644 --- a/src/actions/loadLabels.js +++ b/src/actions/loadLabels.js @@ -4,6 +4,7 @@ import setLoading from "./setLoading"; import { setApiError } from "./setApiError"; import { createAlert } from "./createAlert"; + export default function loadLabels(apiUrl) { const origin = window.location.origin; const url = apiUrl; @@ -36,6 +37,7 @@ export default function loadLabels(apiUrl) { values: [], })); if (labels) { + console.log("loding labels from loadLabels") dispatch(setLabels(labels || [])); dispatch(setApiError("")); dispatch(setLoading(false)); @@ -48,6 +50,7 @@ export default function loadLabels(apiUrl) { dispatch(setApiError("")); dispatch(setLabels([])); + } }) .catch((error) => { diff --git a/src/actions/loadLogs.js b/src/actions/loadLogs.js index 49d3c1de..234cb372 100644 --- a/src/actions/loadLogs.js +++ b/src/actions/loadLogs.js @@ -7,7 +7,53 @@ import { nanoid } from "nanoid"; import { setStartTime, setStopTime } from "./"; import { findRangeByLabel } from "../components/StatusBar/components/daterangepicker/utils"; import { setQueryTime } from "./setQueryTime"; +import setIsEmptyView from "./setIsEmptyView"; + // import adjustedStep from "../components/QueryTypeBar/helpers"; +export async function getAsyncResponse( + cb //: callback dispatch function +) { + return await cb; +} + +export function sortMessagesByTimestamp( + messages //:array sort by timestamp +) { + const startTime = performance.now() + const mess = messages?.sort((a, b) => (a.timestamp < b.timestamp ? 1 : -1)); + const duration = performance.now() - startTime; + console.log("sorting logs took: ",duration," ms") + return mess + +} + +export function fromNanoSec( + ts // :timestamp +) { + return parseInt(ts / 1000000); +} + +export function mapStreams (streams) { + const startTime = performance.now() + let messages = [] + + streams.forEach((stream) => { + stream.values.forEach(([ts,text], i) => { + messages.push({ + type:'stream', + timestamp:fromNanoSec(ts), + text, + tags: stream.stream || {}, + showTs: true, + showLabels: false, + id: nanoid(), + }); + }); + }); + const duration = performance.now() - startTime; + console.log("mapping logs took: ",duration," ms") + return messages +}; export default function loadLogs() { const localStore = store.getState(); @@ -19,21 +65,25 @@ export default function loadLogs() { label: rangeLabel, from, to, + debugMode, } = localStore; let { start: startTs, stop: stopTs } = localStore; function getTimeParsed(time) { return time.getTime() + "000000"; } + const time = localStore.time || new Date().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)); @@ -59,81 +109,95 @@ export default function loadLogs() { }, }; - 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(), - }); - }); - }); - }; - return async function (dispatch) { dispatch(setLoading(true)); + dispatch(setIsEmptyView(false)); dispatch(setLogs([])); dispatch(setMatrixData([])); await axios .get(endpoint[queryType], options) ?.then((response) => { + if (response?.data?.streams?.length === 0) { + if (debugMode) + console.log( + "🚧 loadLogs / getting no data from streams" + ); + dispatch(setIsEmptyView(true)); + } if (response?.data?.data) { let messages = []; - const result = response?.data?.data?.result; // array + const result = response?.data?.data?.result; const type = response?.data?.data?.resultType; if (type === "streams") { - mapStreams(result, messages, type); + messages = mapStreams(result); dispatch(setMatrixData([])); - const messSorted = messages?.sort((a, b) => - a.timestamp < b.timestamp ? 1 : -1 - ); + const messSorted = sortMessagesByTimestamp(messages) if (messSorted) { - dispatch(setLogs(messSorted || [])); - - dispatch(setLoading(false)); - if (queryType === "instant") { - store.dispatch(setQueryTime(time)); + try { + getAsyncResponse( + dispatch(setLogs(messSorted || [])) + ).then(() => { + if (messSorted.length === 0) { + if (debugMode) + console.log( + "🚧 loadLogs / getting no messages sorted" + ); + dispatch(setIsEmptyView(true)); + } + dispatch(setIsEmptyView(false)); + dispatch(setLoading(false)); + }); + if (queryType === "instant") { + store.dispatch(setQueryTime(time)); + } + } catch (e) { + console.log(e); } } } if (type === "matrix") { - const idResult = - result?.map((m) => ({ ...m, id: nanoid() })) || []; - dispatch(setMatrixData(idResult || [])); - dispatch(setLoading(false)); + try { + const idResult = + result?.map((m) => ({ ...m, id: nanoid() })) || + []; + + getAsyncResponse( + dispatch(setMatrixData(idResult || [])) + ).then(() => { + dispatch(setLoading(false)); + if (idResult.length === 0) { + if (debugMode) + console.log( + "getting no data from matrix" + ); + dispatch(setIsEmptyView(true)); + } + dispatch(setIsEmptyView(false)); + }); + } catch (e) { + if (debugMode) + console.log( + "🚧 loadLogs / getting an error from rendering matrix type streams" + ); + console.log(e); + } } } else { dispatch(setLogs([])); dispatch(setMatrixData([])); - dispatch(setLoading(false)); + + // } }) .catch((error) => { dispatch(setLogs([])); dispatch(setMatrixData([])); - dispatch(setLoading(false)); + if (debugMode) + console.log("getting an error from response: ", error); + dispatch(setIsEmptyView(true)); }); }; } diff --git a/src/actions/setFromTime.js b/src/actions/setFromTime.js index adfec8dc..1ecccc78 100644 --- a/src/actions/setFromTime.js +++ b/src/actions/setFromTime.js @@ -1,7 +1,8 @@ -export default function setFromTime(toTime){ - return function (dispatch){ - dispatch({ - type:"SET_FROM_TIME" - }) - } +export default function setFromTime(toTime){ + return function (dispatch){ + dispatch({ + type:"SET_FROM_TIME", + toTime + }) + } } \ No newline at end of file diff --git a/src/actions/setIsEmptyView.js b/src/actions/setIsEmptyView.js new file mode 100644 index 00000000..0b2c461e --- /dev/null +++ b/src/actions/setIsEmptyView.js @@ -0,0 +1,8 @@ +const setIsEmptyView = (isEmptyView) => (dispatch) => { + dispatch({ + type: 'SET_IS_EMPTY_VIEW', + isEmptyView, + }) +} + +export default setIsEmptyView; \ No newline at end of file diff --git a/src/actions/setLabelValues.js b/src/actions/setLabelValues.js index 4e82dd8d..77bdc1e0 100644 --- a/src/actions/setLabelValues.js +++ b/src/actions/setLabelValues.js @@ -1,7 +1,8 @@ -const setLabelValues = (labelValues) => (dispatch) => { - dispatch({ - type: 'SET_LABEL_VALUES', - labelValues - }); -} -export default setLabelValues; +const setLabelValues = (labelValues) => (dispatch) => { + console.log('labelValues set to', labelValues) + dispatch({ + type: 'SET_LABEL_VALUES', + labelValues + }); +} +export default setLabelValues; diff --git a/src/actions/setLabels.js b/src/actions/setLabels.js index 0c8a8437..02a04935 100644 --- a/src/actions/setLabels.js +++ b/src/actions/setLabels.js @@ -1,6 +1,7 @@ -export const setLabels = (labels) => (dispatch) => { - dispatch({ - type: 'SET_LABELS', - labels: labels - }); -}; +export const setLabels = (labels) => (dispatch) => { + console.log('labels set to',labels) + dispatch({ + type: 'SET_LABELS', + labels: labels + }); +}; diff --git a/src/actions/setQueryLimit.js b/src/actions/setQueryLimit.js index e8af27d4..4d4819b9 100644 --- a/src/actions/setQueryLimit.js +++ b/src/actions/setQueryLimit.js @@ -1,6 +1,7 @@ -export const setQueryLimit = (limit) => (dispatch) => { - dispatch({ - type: 'SET_QUERY_LIMIT', - limit - }); -} +export const setQueryLimit = (limit) => (dispatch) => { + console.log("limit set to",limit) + dispatch({ + type: 'SET_QUERY_LIMIT', + limit + }); +} diff --git a/src/components/DataView/DataView.js b/src/components/DataView/DataView.js index 85ef1e44..4209fd94 100644 --- a/src/components/DataView/DataView.js +++ b/src/components/DataView/DataView.js @@ -18,16 +18,20 @@ class DataView extends Component { matrixData: props.matrixData || [], loading: false, theme: props.theme, + isEmptyView: props.isEmptyView || false }; } + getMatrixForChart = () => { return this.props.matrixData; }; + getLimit = () => { return this.props.limit; }; render() { + return ( @@ -49,11 +53,12 @@ class DataView extends Component { matrixData={this.getMatrixForChart()} /> ) : null} - {this.props.messages.length < 1 && - this.getMatrixForChart().length < 1 && - !this.props.loading && } - + {this.props.loading && } + + {this.props.isEmptyView && } + + @@ -70,6 +75,7 @@ const mapStateToProps = (state) => { loading: state.loading, matrixData: state.matrixData, theme: state.theme, + isEmptyView: state.isEmptyView, }; }; diff --git a/src/components/DataView/EmptyView.js b/src/components/DataView/EmptyView.js index 0d91c751..45d79f93 100644 --- a/src/components/DataView/EmptyView.js +++ b/src/components/DataView/EmptyView.js @@ -1,17 +1,24 @@ import { ThemeProvider } from "@emotion/react"; + import { useSelector } from "react-redux"; import { themes } from "../../theme/themes"; import { EmptyViewContainer } from "./styled"; export default function EmptyView() { - const theme = useSelector( store => store.theme) + const theme = useSelector((store) => store.theme); + const loading = useSelector((store) => store.loading); + + return ( - - - { - "Please adjust search parameters and click on ‘Show Logs’ button" - } - - - ); + !loading && ( + + + { + "Please adjust search parameters and click on ‘Show Logs’ button" + } + + + ) + ) + } diff --git a/src/components/DataView/LogsRow.js b/src/components/DataView/LogsRow.js index 2db79750..56cfd1b2 100644 --- a/src/components/DataView/LogsRow.js +++ b/src/components/DataView/LogsRow.js @@ -11,6 +11,7 @@ export default function LogsRow({ message }) { const messages = useSelector((store) => store.logs); const theme = useStore().getState().theme; + function toggleTagsActive(idx) { let arrCopy = [...messages]; arrCopy.forEach((entry) => { diff --git a/src/components/DataView/ValueTags.js b/src/components/DataView/ValueTags.js index cd00c52e..48e6c78e 100644 --- a/src/components/DataView/ValueTags.js +++ b/src/components/DataView/ValueTags.js @@ -47,6 +47,7 @@ export default function ValueTags({ tags }) { true || labelValue.inverted !== isInverted; labelValue.inverted = !labelValue.inverted && isInverted; label.selected = label.values.some((value) => value.selected); + console.log("labels set at value tags if labelvalue") store.dispatch(setLabels(labels)); } else { await store.dispatch(loadLabelValues(label, labels, apiUrl)); @@ -63,6 +64,7 @@ export default function ValueTags({ tags }) { updatedLabel.selected = updatedLabel.values.some( (value) => value.selected ); + console.log('labels set if no labelvalue') store.dispatch(setLabels(updatedLabels)); } queryBuilderWithLabels(); diff --git a/src/components/DataView/helpers/index.js b/src/components/DataView/helpers/index.js index d70e87f4..a67f2107 100644 --- a/src/components/DataView/helpers/index.js +++ b/src/components/DataView/helpers/index.js @@ -15,6 +15,7 @@ export function getRowColor(tags) { } export function toggleActiveStyles(idx) { + console.log(idx, 'toggled') return idx.showLabels ? "value-tags-container labelsActive" : "value-tags-container labelsInactive"; diff --git a/src/components/LabelBrowser/QueryBar.js b/src/components/LabelBrowser/QueryBar.js index ff1fe5cd..2c821c15 100644 --- a/src/components/LabelBrowser/QueryBar.js +++ b/src/components/LabelBrowser/QueryBar.js @@ -86,9 +86,6 @@ export const QueryBar = () => { onSubmit(e); } }; - const onQueryTypeChange = (e) => { - console.log(e) - } const onSubmit = (e) => { e.preventDefault(); @@ -173,9 +170,8 @@ export const QueryBar = () => { onClick={onSubmit} isMobile={false} /> - - + ) diff --git a/src/components/LabelBrowser/ValuesList.js b/src/components/LabelBrowser/ValuesList.js index cd5ac796..956a4eb4 100644 --- a/src/components/LabelBrowser/ValuesList.js +++ b/src/components/LabelBrowser/ValuesList.js @@ -104,20 +104,23 @@ export const ValuesList = (props) => { 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(() => { + // dispatch(loadLabels(apiUrl)); + // if (debug) console.log("🚧 LOGIC/LabelBrowser/ValuesList", apiUrl); + // }, [apiUrl]); useEffect(() => { setLabelList(labels); // LABELS + console.log('labels changed') }, [labels]); const handleRefresh = (e) => { e.preventDefault(); + console.log("event handled") dispatch(loadLabels(apiUrl)); }; diff --git a/src/components/StatusBar/components/apiselector/ApiSelector.js b/src/components/StatusBar/components/apiselector/ApiSelector.js index 0215a753..4e1322d9 100644 --- a/src/components/StatusBar/components/apiselector/ApiSelector.js +++ b/src/components/StatusBar/components/apiselector/ApiSelector.js @@ -28,7 +28,7 @@ export function ApiSelector() { useEffect(() => { setEditedUrl(apiUrl); - + console.log("labels loaded from apiURL") dispatch(loadLabels(apiUrl)); }, [apiUrl]); @@ -57,7 +57,7 @@ export function ApiSelector() { dispatch(setApiUrl(editedUrl)); setEditedUrl(editedUrl); - + console.log("set from onurlsubmit") dispatch(loadLabels(editedUrl)); dispatch(setLabelsBrowserOpen(false)); diff --git a/src/helpers/UpdateStateFromQueryParams.js b/src/helpers/UpdateStateFromQueryParams.js index fe2de29b..60bb3c0a 100644 --- a/src/helpers/UpdateStateFromQueryParams.js +++ b/src/helpers/UpdateStateFromQueryParams.js @@ -116,10 +116,6 @@ export function UpdateStateFromQueryParams() { startParams[param] !== "" ) { dispatch(STORE_ACTIONS[param](startParams[param])); - - if (param === "apiUrl") { - dispatch(loadLabels(startParams[param])); - } } else if ( QUERY_VALUE === param && startParams[param] !== "" @@ -307,10 +303,12 @@ export function decodeQuery(query, apiUrl, labels = []) { 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 @@ -321,6 +319,8 @@ export function decodeQuery(query, apiUrl, labels = []) { .filter((value) => !!value); labelWithValues.values = values; labelWithValues.selected = true; + console.log('labels changed from labels from query') + console.log('here the labels get their values') store.dispatch(setLabels(labelsWithValues)); }); } diff --git a/src/plugins/charts/index.js b/src/plugins/charts/index.js index 44bcf4bb..00809556 100644 --- a/src/plugins/charts/index.js +++ b/src/plugins/charts/index.js @@ -160,10 +160,12 @@ export default function ClokiChart({ matrixData }) { 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) { diff --git a/src/store/createInitialState.js b/src/store/createInitialState.js index 7acf5c54..50783d80 100644 --- a/src/store/createInitialState.js +++ b/src/store/createInitialState.js @@ -63,6 +63,7 @@ export default function initialState() { chartType: "line", notifications: [], theme: urlState.theme || "dark", + isEmptyView: false, }; const debug = state.debugMode; if (debug) console.log("🚧 LOGIC/ INITIAL STATE ::: ", state); diff --git a/src/store/reducer.js b/src/store/reducer.js index 74a78c76..50c922cc 100644 --- a/src/store/reducer.js +++ b/src/store/reducer.js @@ -70,6 +70,8 @@ const reducer = (state, action) => { return { ...state, time: action.time }; case "SET_QUERY_RESOLUTION": return {...state, queryResolution: action.queryResolution}; + case "SET_IS_EMPTY_VIEW": + return {...state, isEmptyView: action.isEmptyView}; default: return { ...state }; } From eb407c1608c534edf7c7ec7dac4bff2add8d24cb Mon Sep 17 00:00:00 2001 From: Joel Guerra Date: Tue, 10 May 2022 13:41:48 +0200 Subject: [PATCH 07/11] add virtual scroll --- package-lock.json | 49 +++++++++++++ package.json | 2 + src/components/DataView/DataView.js | 12 ++-- src/components/DataView/LogsView.js | 105 ++++++++++++++++++++++++++++ 4 files changed, 164 insertions(+), 4 deletions(-) create mode 100644 src/components/DataView/LogsView.js diff --git a/package-lock.json b/package-lock.json index 67374e96..6c9cadb3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "env-cmd": "^10.1.0", "jquery": "^3.6.0", "lodash": "^4.17.21", + "memoize-one": "^6.0.0", "moment": "^2.29.2", "nanoid": "^3.3.1", "prismjs": "^1.27.0", @@ -33,6 +34,7 @@ "react-redux": "^7.2.6", "react-responsive": "^9.0.0-beta.6", "react-router-dom": "^6.2.1", + "react-window": "^1.8.7", "redux-thunk": "^2.4.1", "slate": "^0.73.1", "slate-history": "^0.66.0", @@ -13790,6 +13792,11 @@ "node": ">= 4.0.0" } }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -16644,6 +16651,27 @@ "react-dom": ">=16.6.0" } }, + "node_modules/react-window": { + "version": "1.8.7", + "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.7.tgz", + "integrity": "sha512-JHEZbPXBpKMmoNO1bNhoXOOLg/ujhL/BU4IqVU9r8eQPcy5KQnGHIHDRkJ0ns9IM5+Aq5LNwt3j8t3tIrePQzA==", + "dependencies": { + "@babel/runtime": "^7.0.0", + "memoize-one": ">=3.1.1 <6" + }, + "engines": { + "node": ">8.0.0" + }, + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-window/node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, "node_modules/readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -30295,6 +30323,11 @@ "fs-monkey": "1.0.3" } }, + "memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -32278,6 +32311,22 @@ "prop-types": "^15.6.2" } }, + "react-window": { + "version": "1.8.7", + "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.7.tgz", + "integrity": "sha512-JHEZbPXBpKMmoNO1bNhoXOOLg/ujhL/BU4IqVU9r8eQPcy5KQnGHIHDRkJ0ns9IM5+Aq5LNwt3j8t3tIrePQzA==", + "requires": { + "@babel/runtime": "^7.0.0", + "memoize-one": ">=3.1.1 <6" + }, + "dependencies": { + "memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + } + } + }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", diff --git a/package.json b/package.json index baf037fd..0564ada0 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "env-cmd": "^10.1.0", "jquery": "^3.6.0", "lodash": "^4.17.21", + "memoize-one": "^6.0.0", "moment": "^2.29.2", "nanoid": "^3.3.1", "prismjs": "^1.27.0", @@ -34,6 +35,7 @@ "react-redux": "^7.2.6", "react-responsive": "^9.0.0-beta.6", "react-router-dom": "^6.2.1", + "react-window": "^1.8.7", "redux-thunk": "^2.4.1", "slate": "^0.73.1", "slate-history": "^0.66.0", diff --git a/src/components/DataView/DataView.js b/src/components/DataView/DataView.js index 4209fd94..1e1f2944 100644 --- a/src/components/DataView/DataView.js +++ b/src/components/DataView/DataView.js @@ -9,6 +9,7 @@ import LogsRow from "./LogsRow"; import EmptyView from "./EmptyView"; import { ThemeProvider } from "@emotion/react"; import { themes } from "../../theme/themes"; +import { ExampleWrapper } from "./LogsView"; class DataView extends Component { constructor(props) { super(props); @@ -18,7 +19,7 @@ class DataView extends Component { matrixData: props.matrixData || [], loading: false, theme: props.theme, - isEmptyView: props.isEmptyView || false + isEmptyView: props.isEmptyView || false, }; } @@ -31,12 +32,11 @@ class DataView extends Component { }; render() { - return ( - {this.props.messages.length > 0 && + {/* {this.props.messages.length > 0 && this.getMatrixForChart().length < 1 ? this.props.messages.map((message, key) => ( )) - : null} + : null} */} {this.getMatrixForChart().length > 0 ? ( ) : null} + {this.props.messages.length > 0 && ( + + )} + {this.props.loading && } {this.props.isEmptyView && } diff --git a/src/components/DataView/LogsView.js b/src/components/DataView/LogsView.js new file mode 100644 index 00000000..a2a2fb2c --- /dev/null +++ b/src/components/DataView/LogsView.js @@ -0,0 +1,105 @@ +import React, { PureComponent, memo, useEffect } from 'react'; +import memoize from 'memoize-one'; +import { FixedSizeList as List, areEqual } from 'react-window'; +import ValueTags from './ValueTags'; +import { ThemeProvider } from '@emotion/react'; +import { themes } from '../../theme/themes'; +import { LogRow, RowLogContent, RowTimestamp } from './styled'; +import { useSelector } from 'react-redux'; +import { getRowColor } from './helpers'; + + +// If list items are expensive to render, +// Consider using PureComponent to avoid unnecessary re-renders. +// https://reactjs.org/docs/react-api.html#reactpurecomponent + +const Row = memo(({ data, index, style }) => { + // Data passed to List as "itemData" is available as props.data + const { items, toggleItemActive } = data; + const item = items[index]; + + return ( + + toggleItemActive(index)} style={style}> + {item.showLabels ? 'active' : 'inactive'} + {item.timestamp} + {item.text} + {item.showLabels} + {item.showLabels && ()} + + + + ); +}, areEqual); + +// This helper function memoizes incoming props, +// To avoid causing unnecessary re-renders pure Row components. +// This is only needed since we are passing multiple props with a wrapper object. +// If we were only passing a single, stable value (e.g. items), +// We could just pass the value directly. +const createItemData = memoize((items, toggleItemActive) => ({ + items, + toggleItemActive, +})); + +// In this example, "items" is an Array of objects to render, +// and "toggleItemActive" is a function that updates an item's state. +function Example({ height, items, toggleItemActive, width }) { + // Bundle additional data to list items using the "itemData" prop. + // It will be accessible to item renderers as props.data. + // Memoize this data to avoid bypassing shouldComponentUpdate(). + const itemData = createItemData(items, toggleItemActive); +const theme = useSelector( store => store.theme) + return ( + + + + + {Row} + + + + + ); +} + +export class ExampleWrapper extends PureComponent { + constructor(props){ + super(props) + const {messages} = props || [] + this.state = { + messages + }; + } + + + toggleItemActive = index => + this.setState(prevState => { + const message = prevState.messages[index]; + const messages = prevState.messages.concat(); + messages[index] = { + ...message, + showLabels: !message.showLabels, + }; + return { messages }; + }); +// items == messages + render() { + return ( + + ); + } +} \ No newline at end of file From 728acb14df9873f87b28c553d5884ac784a171af Mon Sep 17 00:00:00 2001 From: jacovinus Date: Tue, 10 May 2022 18:16:39 +0200 Subject: [PATCH 08/11] adjust logs structure --- src/components/DataView/DataView.js | 10 +- src/components/DataView/LogsRow.js | 1 + src/components/DataView/LogsView.js | 177 +++++++++++++++------------- 3 files changed, 102 insertions(+), 86 deletions(-) diff --git a/src/components/DataView/DataView.js b/src/components/DataView/DataView.js index 1e1f2944..c96a4f2b 100644 --- a/src/components/DataView/DataView.js +++ b/src/components/DataView/DataView.js @@ -1,7 +1,7 @@ import React, { Component } from "react"; import { connect } from "react-redux"; -import { DataViewCont, DataViewStyled, Loader } from "./styled"; +import { DataViewCont, DataViewStyled, Loader, RowLogContent, RowTimestamp } from "./styled"; import ClokiChart from "../../plugins/charts"; import QueryHistory from "../../plugins/queryhistory"; @@ -46,7 +46,9 @@ class DataView extends Component { /> )) : null} */} - + {this.props.messages.length > 0 && ( + + )} {this.getMatrixForChart().length > 0 ? ( ) : null} - {this.props.messages.length > 0 && ( - - )} - {this.props.loading && } {this.props.isEmptyView && } diff --git a/src/components/DataView/LogsRow.js b/src/components/DataView/LogsRow.js index 56cfd1b2..5e1e1a8d 100644 --- a/src/components/DataView/LogsRow.js +++ b/src/components/DataView/LogsRow.js @@ -43,3 +43,4 @@ export default function LogsRow({ message }) { ); } + diff --git a/src/components/DataView/LogsView.js b/src/components/DataView/LogsView.js index a2a2fb2c..107dcdc7 100644 --- a/src/components/DataView/LogsView.js +++ b/src/components/DataView/LogsView.js @@ -1,38 +1,45 @@ -import React, { PureComponent, memo, useEffect } from 'react'; -import memoize from 'memoize-one'; -import { FixedSizeList as List, areEqual } from 'react-window'; -import ValueTags from './ValueTags'; -import { ThemeProvider } from '@emotion/react'; -import { themes } from '../../theme/themes'; -import { LogRow, RowLogContent, RowTimestamp } from './styled'; -import { useSelector } from 'react-redux'; -import { getRowColor } from './helpers'; - +import React, { PureComponent, memo, createRef } from "react"; +import memoize from "memoize-one"; +import { VariableSizeList as List, areEqual } from "react-window"; +import ValueTags from "./ValueTags"; +import { ThemeProvider } from "@emotion/react"; +import { themes } from "../../theme/themes"; +import { LogRow, RowLogContent, RowTimestamp } from "./styled"; +import { useSelector } from "react-redux"; +import { formatDate, getRowColor } from "./helpers"; // If list items are expensive to render, // Consider using PureComponent to avoid unnecessary re-renders. // https://reactjs.org/docs/react-api.html#reactpurecomponent - -const Row = memo(({ data, index, style }) => { - // Data passed to List as "itemData" is available as props.data - const { items, toggleItemActive } = data; - const item = items[index]; - return ( +const Row = ({ data, index, style, onUpdate }) => { + // Data passed to List as "itemData" is available as props.data + const { items, toggleItemActive } = data; + const item = items[index]; + console.log(style); - toggleItemActive(index)} style={style}> - {item.showLabels ? 'active' : 'inactive'} - {item.timestamp} - {item.text} - {item.showLabels} - {item.showLabels && ()} - - + return ( + { + toggleItemActive(index) + onUpdate(index) + } } + style={{ + ...style,...{ display: "flex", + height: (item.showLabels ? "100px" : "35px") + " !important"} + + }} + > +
+ {formatDate(item.timestamp)} + {item.text} +
- ); -}, areEqual); + {item.showLabels && } +
+ ); +}; // This helper function memoizes incoming props, // To avoid causing unnecessary re-renders pure Row components. @@ -40,66 +47,76 @@ const Row = memo(({ data, index, style }) => { // If we were only passing a single, stable value (e.g. items), // We could just pass the value directly. const createItemData = memoize((items, toggleItemActive) => ({ - items, - toggleItemActive, + items, + toggleItemActive, })); // In this example, "items" is an Array of objects to render, // and "toggleItemActive" is a function that updates an item's state. function Example({ height, items, toggleItemActive, width }) { - // Bundle additional data to list items using the "itemData" prop. - // It will be accessible to item renderers as props.data. - // Memoize this data to avoid bypassing shouldComponentUpdate(). - const itemData = createItemData(items, toggleItemActive); -const theme = useSelector( store => store.theme) - return ( - - - - - {Row} - - - - - ); + // Bundle additional data to list items using the "itemData" prop. + // It will be accessible to item renderers as props.data. + // Memoize this data to avoid bypassing shouldComponentUpdate(). + + // calculate item size after tags ammount + const listRef = createRef(null) + console.log(items) + const itemData = createItemData(items, toggleItemActive); + const theme = useSelector((store) => store.theme); + const limit = useSelector((store)=> store.limit) + function calculateItemSize(idx) { + return items[idx].showLabels ? Object.keys(items[idx].tags).length * 25 + 40 : 35 + + } + function updateIndex(idx){ + listRef.current.resetAfterIndex(idx, true) + } + + return ( + + + {Row} + + + ); } export class ExampleWrapper extends PureComponent { - constructor(props){ - super(props) - const {messages} = props || [] + constructor(props) { + super(props); + const { messages } = props || []; this.state = { - messages - }; + messages, + }; } - - toggleItemActive = index => - this.setState(prevState => { - const message = prevState.messages[index]; - const messages = prevState.messages.concat(); - messages[index] = { - ...message, - showLabels: !message.showLabels, - }; - return { messages }; - }); -// items == messages - render() { - return ( - - ); - } -} \ No newline at end of file + toggleItemActive = (index) => + this.setState((prevState) => { + const message = prevState.messages[index]; + const messages = prevState.messages.concat(); + messages[index] = { + ...message, + showLabels: !message.showLabels, + }; + return { messages }; + }); + // items == messages + render() { + return ( + + ); + } +} From 02d8599ee9cff1d7038723d82f86219b78161566 Mon Sep 17 00:00:00 2001 From: Joel Guerra Date: Thu, 12 May 2022 12:40:48 +0200 Subject: [PATCH 09/11] fix labels loading time --- package-lock.json | 38 ------- package.json | 1 - src/components/DataView/DataView.js | 24 +---- src/components/DataView/LogRows/index.js | 80 +++++++++++++++ src/components/DataView/LogsRow.js | 46 --------- src/components/DataView/LogsView.js | 122 ----------------------- src/components/DataView/ValueTags.js | 2 + 7 files changed, 87 insertions(+), 226 deletions(-) create mode 100644 src/components/DataView/LogRows/index.js delete mode 100644 src/components/DataView/LogsRow.js delete mode 100644 src/components/DataView/LogsView.js diff --git a/package-lock.json b/package-lock.json index 6c9cadb3..c24d5b02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,7 +34,6 @@ "react-redux": "^7.2.6", "react-responsive": "^9.0.0-beta.6", "react-router-dom": "^6.2.1", - "react-window": "^1.8.7", "redux-thunk": "^2.4.1", "slate": "^0.73.1", "slate-history": "^0.66.0", @@ -16651,27 +16650,6 @@ "react-dom": ">=16.6.0" } }, - "node_modules/react-window": { - "version": "1.8.7", - "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.7.tgz", - "integrity": "sha512-JHEZbPXBpKMmoNO1bNhoXOOLg/ujhL/BU4IqVU9r8eQPcy5KQnGHIHDRkJ0ns9IM5+Aq5LNwt3j8t3tIrePQzA==", - "dependencies": { - "@babel/runtime": "^7.0.0", - "memoize-one": ">=3.1.1 <6" - }, - "engines": { - "node": ">8.0.0" - }, - "peerDependencies": { - "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-window/node_modules/memoize-one": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", - "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" - }, "node_modules/readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -32311,22 +32289,6 @@ "prop-types": "^15.6.2" } }, - "react-window": { - "version": "1.8.7", - "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.7.tgz", - "integrity": "sha512-JHEZbPXBpKMmoNO1bNhoXOOLg/ujhL/BU4IqVU9r8eQPcy5KQnGHIHDRkJ0ns9IM5+Aq5LNwt3j8t3tIrePQzA==", - "requires": { - "@babel/runtime": "^7.0.0", - "memoize-one": ">=3.1.1 <6" - }, - "dependencies": { - "memoize-one": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", - "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" - } - } - }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", diff --git a/package.json b/package.json index 0564ada0..6290d7b0 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,6 @@ "react-redux": "^7.2.6", "react-responsive": "^9.0.0-beta.6", "react-router-dom": "^6.2.1", - "react-window": "^1.8.7", "redux-thunk": "^2.4.1", "slate": "^0.73.1", "slate-history": "^0.66.0", diff --git a/src/components/DataView/DataView.js b/src/components/DataView/DataView.js index c96a4f2b..12e05cb0 100644 --- a/src/components/DataView/DataView.js +++ b/src/components/DataView/DataView.js @@ -1,21 +1,19 @@ import React, { Component } from "react"; import { connect } from "react-redux"; - -import { DataViewCont, DataViewStyled, Loader, RowLogContent, RowTimestamp } from "./styled"; - +import { DataViewCont, DataViewStyled, Loader } from "./styled"; import ClokiChart from "../../plugins/charts"; import QueryHistory from "../../plugins/queryhistory"; -import LogsRow from "./LogsRow"; import EmptyView from "./EmptyView"; import { ThemeProvider } from "@emotion/react"; import { themes } from "../../theme/themes"; -import { ExampleWrapper } from "./LogsView"; +import { LogRows } from "./LogRows"; class DataView extends Component { constructor(props) { super(props); + const { messages } = props || []; this.state = { limit: props.limit || 100, - messages: props.messages || [], + messages, matrixData: props.matrixData || [], loading: false, theme: props.theme, @@ -36,18 +34,8 @@ class DataView extends Component { - {/* {this.props.messages.length > 0 && - this.getMatrixForChart().length < 1 - ? this.props.messages.map((message, key) => ( - - )) - : null} */} {this.props.messages.length > 0 && ( - + )} {this.getMatrixForChart().length > 0 ? ( { return { messages: state.logs, - start: state.start, - stop: state.stop, limit: state.limit, loading: state.loading, matrixData: state.matrixData, diff --git a/src/components/DataView/LogRows/index.js b/src/components/DataView/LogRows/index.js new file mode 100644 index 00000000..05e8e586 --- /dev/null +++ b/src/components/DataView/LogRows/index.js @@ -0,0 +1,80 @@ +import memoize from "memoize-one"; +import { PureComponent } from "react"; +import { formatDate, getRowColor } from "../helpers"; +import { LogRow, RowLogContent, RowTimestamp } from "../styled"; +import ValueTags from "../ValueTags"; + +function Row({ toggleItemActive, index, log }) { + + return ( + { + toggleItemActive(index); + }} + > +
+ {formatDate(log.timestamp)} + {log.text} +
+ + {log.showLabels && ( +
+ +
+ )} +
+ ) + +} + +const createItemData = memoize((items, toggleItemActive) => ({ + items, + toggleItemActive, +})); + +function Logs({ items, toggleItemActive }) { + const itemData = createItemData(items, toggleItemActive); + return ( + itemData && + itemData.items.map((log, key) => ( + + )) + ); +} + +export class LogRows extends PureComponent { + constructor(props) { + super(props); + const { messages } = props || []; + + this.state = { + messages, + }; + } + + toggleItemActive = (index) => + this.setState((prevState) => { + const message = prevState.messages[index]; + const messages = prevState.messages.concat(); + messages[index] = { + ...message, + showLabels: !message.showLabels, + }; + return { messages }; + }); + + render() { + return ( + + ); + } +} diff --git a/src/components/DataView/LogsRow.js b/src/components/DataView/LogsRow.js deleted file mode 100644 index 5e1e1a8d..00000000 --- a/src/components/DataView/LogsRow.js +++ /dev/null @@ -1,46 +0,0 @@ -import { formatDate, getRowColor, toggleActiveStyles } from "./helpers"; -import { LogRow, RowLogContent, RowTimestamp } from "./styled"; -import ValueTags from "./ValueTags"; -import { useSelector, useDispatch, useStore } from "react-redux"; -import setLogs from "../../actions/setLogs"; -import { ThemeProvider } from "@emotion/react"; -import { themes } from "../../theme/themes"; - -export default function LogsRow({ message }) { - const dispatch = useDispatch(); - const messages = useSelector((store) => store.logs); - - const theme = useStore().getState().theme; - - function toggleTagsActive(idx) { - let arrCopy = [...messages]; - arrCopy.forEach((entry) => { - if (entry.id === idx) { - entry.showLabels = entry.showLabels ? false : true; - } - }); - dispatch(setLogs(arrCopy)); - } - - return ( - - { - toggleTagsActive(message.id); - }} - > -
- {formatDate(message.timestamp)} - {message.text} -
- {message.tags && ( -
- -
- )} -
-
- ); -} - diff --git a/src/components/DataView/LogsView.js b/src/components/DataView/LogsView.js deleted file mode 100644 index 107dcdc7..00000000 --- a/src/components/DataView/LogsView.js +++ /dev/null @@ -1,122 +0,0 @@ -import React, { PureComponent, memo, createRef } from "react"; -import memoize from "memoize-one"; -import { VariableSizeList as List, areEqual } from "react-window"; -import ValueTags from "./ValueTags"; -import { ThemeProvider } from "@emotion/react"; -import { themes } from "../../theme/themes"; -import { LogRow, RowLogContent, RowTimestamp } from "./styled"; -import { useSelector } from "react-redux"; -import { formatDate, getRowColor } from "./helpers"; - -// If list items are expensive to render, -// Consider using PureComponent to avoid unnecessary re-renders. -// https://reactjs.org/docs/react-api.html#reactpurecomponent - -const Row = ({ data, index, style, onUpdate }) => { - // Data passed to List as "itemData" is available as props.data - const { items, toggleItemActive } = data; - const item = items[index]; - console.log(style); - - return ( - { - toggleItemActive(index) - onUpdate(index) - } } - style={{ - ...style,...{ display: "flex", - height: (item.showLabels ? "100px" : "35px") + " !important"} - - }} - > -
- {formatDate(item.timestamp)} - {item.text} -
- - {item.showLabels && } -
- ); -}; - -// This helper function memoizes incoming props, -// To avoid causing unnecessary re-renders pure Row components. -// This is only needed since we are passing multiple props with a wrapper object. -// If we were only passing a single, stable value (e.g. items), -// We could just pass the value directly. -const createItemData = memoize((items, toggleItemActive) => ({ - items, - toggleItemActive, -})); - -// In this example, "items" is an Array of objects to render, -// and "toggleItemActive" is a function that updates an item's state. -function Example({ height, items, toggleItemActive, width }) { - // Bundle additional data to list items using the "itemData" prop. - // It will be accessible to item renderers as props.data. - // Memoize this data to avoid bypassing shouldComponentUpdate(). - - // calculate item size after tags ammount - const listRef = createRef(null) - console.log(items) - const itemData = createItemData(items, toggleItemActive); - const theme = useSelector((store) => store.theme); - const limit = useSelector((store)=> store.limit) - function calculateItemSize(idx) { - return items[idx].showLabels ? Object.keys(items[idx].tags).length * 25 + 40 : 35 - - } - function updateIndex(idx){ - listRef.current.resetAfterIndex(idx, true) - } - - return ( - - - {Row} - - - ); -} - -export class ExampleWrapper extends PureComponent { - constructor(props) { - super(props); - const { messages } = props || []; - this.state = { - messages, - }; - } - - toggleItemActive = (index) => - this.setState((prevState) => { - const message = prevState.messages[index]; - const messages = prevState.messages.concat(); - messages[index] = { - ...message, - showLabels: !message.showLabels, - }; - return { messages }; - }); - // items == messages - render() { - return ( - - ); - } -} diff --git a/src/components/DataView/ValueTags.js b/src/components/DataView/ValueTags.js index 48e6c78e..1f3f8517 100644 --- a/src/components/DataView/ValueTags.js +++ b/src/components/DataView/ValueTags.js @@ -12,6 +12,8 @@ import styled from "@emotion/styled"; const ValueTagsStyled = styled.div` color: ${(props) => props.theme.textPrimary}; flex: 1; + z-index: 10000; + display: flex; &:hover { background: ${(props) => props.theme.widgetContainer}; } From 6d1d813e37005d89c328196d4cd24185c330b42e Mon Sep 17 00:00:00 2001 From: Joel Guerra Date: Thu, 12 May 2022 17:31:04 +0200 Subject: [PATCH 10/11] fix label selection highlight at label selector --- src/actions/loadLogs.js | 3 +-- src/components/DataView/ValueTags.js | 2 +- src/components/LabelBrowser/QueryBar.js | 3 --- src/components/LabelBrowser/ValuesList.js | 9 ++----- src/helpers/UpdateStateFromQueryParams.js | 12 ++++++--- src/plugins/charts/index.js | 33 +++++++---------------- 6 files changed, 23 insertions(+), 39 deletions(-) diff --git a/src/actions/loadLogs.js b/src/actions/loadLogs.js index 234cb372..92cb63b8 100644 --- a/src/actions/loadLogs.js +++ b/src/actions/loadLogs.js @@ -76,8 +76,7 @@ export default function loadLogs() { const time = localStore.time || new Date().getTime() + "000000"; const parsedStart = getTimeParsed(startTs); const parsedStop = getTimeParsed(stopTs); - const parsedTime = - "&start=" + (from || parsedStart) + "&end=" + (to || parsedStop); + const parsedTime = "&start=" + (from || parsedStart) + "&end=" + (to || parsedStop); if (findRangeByLabel(rangeLabel)) { ({ dateStart: startTs, dateEnd: stopTs } = findRangeByLabel( diff --git a/src/components/DataView/ValueTags.js b/src/components/DataView/ValueTags.js index 1f3f8517..5bbe0ef2 100644 --- a/src/components/DataView/ValueTags.js +++ b/src/components/DataView/ValueTags.js @@ -49,8 +49,8 @@ export default function ValueTags({ tags }) { true || labelValue.inverted !== isInverted; labelValue.inverted = !labelValue.inverted && isInverted; label.selected = label.values.some((value) => value.selected); - console.log("labels set at value tags if labelvalue") store.dispatch(setLabels(labels)); + } else { await store.dispatch(loadLabelValues(label, labels, apiUrl)); const updatedLabels = store.getState().labels; diff --git a/src/components/LabelBrowser/QueryBar.js b/src/components/LabelBrowser/QueryBar.js index 2c821c15..a9090697 100644 --- a/src/components/LabelBrowser/QueryBar.js +++ b/src/components/LabelBrowser/QueryBar.js @@ -67,9 +67,6 @@ export const QueryBar = () => { const onValueDisplay = (e) => { e.preventDefault(); const isOpen = labelsBrowserOpen ? false : true; - if (isOpen) { - dispatch(loadLabels(apiUrl)); - } dispatch(setLabelsBrowserOpen(isOpen)); }; diff --git a/src/components/LabelBrowser/ValuesList.js b/src/components/LabelBrowser/ValuesList.js index 956a4eb4..68e74247 100644 --- a/src/components/LabelBrowser/ValuesList.js +++ b/src/components/LabelBrowser/ValuesList.js @@ -30,9 +30,9 @@ const ValuesListStyled = styled.div` background: ${(props) => props.theme.widgetContainer}; .valuelist-content { small { - color: ${(props) => props.theme.textColor} !important; + color: ${(props) => props.theme.textColor}; background: ${(props) => props.theme.buttonDefault} !important; - border: 1px solid ${(props) => props.theme.buttonBorder} !important; + border: 1px solid ${(props) => props.theme.buttonBorder}; margin: 5px; padding: 4px 8px; border-radius: 3px; @@ -108,11 +108,6 @@ export const ValuesList = (props) => { const labelsBrowserOpen = useSelector((store) => store.labelsBrowserOpen); const CLEAR = "clear"; - // useEffect(() => { - // dispatch(loadLabels(apiUrl)); - // if (debug) console.log("🚧 LOGIC/LabelBrowser/ValuesList", apiUrl); - // }, [apiUrl]); - useEffect(() => { setLabelList(labels); // LABELS console.log('labels changed') diff --git a/src/helpers/UpdateStateFromQueryParams.js b/src/helpers/UpdateStateFromQueryParams.js index 60bb3c0a..7e7ce589 100644 --- a/src/helpers/UpdateStateFromQueryParams.js +++ b/src/helpers/UpdateStateFromQueryParams.js @@ -83,7 +83,14 @@ export function UpdateStateFromQueryParams() { theme: setTheme, }; - const STRING_VALUES = ["limit", "step", "apiUrl", "theme", "queryType","time"]; + const STRING_VALUES = [ + "limit", + "step", + "apiUrl", + "theme", + "queryType", + "time", + ]; const QUERY_VALUE = "query"; @@ -123,6 +130,7 @@ export function UpdateStateFromQueryParams() { const parsedQuery = decodeURIComponent( startParams[param] ); + dispatch(STORE_ACTIONS[param](parsedQuery)); } else if ( TIME_VALUES.includes(param) && @@ -319,8 +327,6 @@ export function decodeQuery(query, apiUrl, labels = []) { .filter((value) => !!value); labelWithValues.values = values; labelWithValues.selected = true; - console.log('labels changed from labels from query') - console.log('here the labels get their values') store.dispatch(setLabels(labelsWithValues)); }); } diff --git a/src/plugins/charts/index.js b/src/plugins/charts/index.js index 00809556..789aafda 100644 --- a/src/plugins/charts/index.js +++ b/src/plugins/charts/index.js @@ -1,11 +1,8 @@ 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"; @@ -60,11 +57,6 @@ export default function ClokiChart({ matrixData }) { } } - /** - * - * Set chart types - */ - function plotChartData(data, type, element) { const chartSeries = setChartTypeSeries(type); const { timeformat, min, max } = formatDateRange(data); @@ -73,7 +65,7 @@ export default function ClokiChart({ matrixData }) { data, $q.extend(true, {}, chartOptions, { ...chartSeries, - xaxis: { timeformat, min, max, }, + xaxis: { timeformat, min, max }, }) ); } @@ -139,10 +131,10 @@ export default function ClokiChart({ matrixData }) { 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; @@ -160,7 +152,7 @@ export default function ClokiChart({ matrixData }) { const toLabel = format(toTs, "yyyy/MM/dd HH:mm:ss"); const timeRangeLabel = `${fromLabel}-${toLabel}`; - + dispatch(setStopTime(toTs)); dispatch(setStartTime(fromTs)); @@ -173,11 +165,6 @@ export default function ClokiChart({ matrixData }) { } } - /** - * - *Isolate Series clicking label - */ - function onLabelClick(e, v) { let newList = []; const lSelected = @@ -220,7 +207,7 @@ export default function ClokiChart({ matrixData }) { $q.extend(true, {}, chartOptions, { series: getSeriesFromChartType(chartType), - xaxis: { timeformat, min, max, }, + xaxis: { timeformat, min, max }, }) ); @@ -246,7 +233,7 @@ export default function ClokiChart({ matrixData }) { newData, $q.extend(true, {}, chartOptions, { series: getSeriesFromChartType(chartType), - xaxis: { timeformat, min, max, }, + xaxis: { timeformat, min, max }, }) ); @@ -281,7 +268,7 @@ export default function ClokiChart({ matrixData }) { newData, $q.extend(true, {}, chartOptions, { series: getSeriesFromChartType(chartType), - xaxis: { timeformat, min, max, }, + xaxis: { timeformat, min, max }, }) ); @@ -302,7 +289,7 @@ export default function ClokiChart({ matrixData }) { }; return ( -
+
From 8239242fbcdc2372b7c3c6525713d940e90a5d9f Mon Sep 17 00:00:00 2001 From: Joel Guerra Date: Thu, 12 May 2022 17:55:47 +0200 Subject: [PATCH 11/11] add logs to debug --- src/actions/loadLabelValues.js | 1 - src/actions/loadLogs.js | 7 ++++--- src/actions/setLabelValues.js | 1 - src/actions/setLabels.js | 1 - src/actions/setQueryLimit.js | 1 - src/components/LabelBrowser/ValuesList.js | 1 - 6 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/actions/loadLabelValues.js b/src/actions/loadLabelValues.js index 285905ec..00e8ec25 100644 --- a/src/actions/loadLabelValues.js +++ b/src/actions/loadLabelValues.js @@ -46,7 +46,6 @@ export default function loadLabelValues(label, labelList, apiUrl) { l.values = [...values]; } }); - console.log("labels changed from here") dispatch(setLabels(lsList)) } else if(!response) { dispatch(setApiError('URL NOT FOUND')) diff --git a/src/actions/loadLogs.js b/src/actions/loadLogs.js index 92cb63b8..c706df31 100644 --- a/src/actions/loadLogs.js +++ b/src/actions/loadLogs.js @@ -10,6 +10,7 @@ import { setQueryTime } from "./setQueryTime"; import setIsEmptyView from "./setIsEmptyView"; // import adjustedStep from "../components/QueryTypeBar/helpers"; +const debugMode = store.getState().debugMode export async function getAsyncResponse( cb //: callback dispatch function ) { @@ -22,7 +23,7 @@ export function sortMessagesByTimestamp( const startTime = performance.now() const mess = messages?.sort((a, b) => (a.timestamp < b.timestamp ? 1 : -1)); const duration = performance.now() - startTime; - console.log("sorting logs took: ",duration," ms") + if(debugMode) console.log( "🚧 loadLogs / sorting logs took: ",duration," ms") return mess } @@ -51,7 +52,7 @@ export function mapStreams (streams) { }); }); const duration = performance.now() - startTime; - console.log("mapping logs took: ",duration," ms") + if(debugMode) console.log( "🚧 loadLogs / mapping logs took: ",duration," ms") return messages }; @@ -169,7 +170,7 @@ export default function loadLogs() { if (idResult.length === 0) { if (debugMode) console.log( - "getting no data from matrix" + "🚧 loadLogs / getting no data from matrix" ); dispatch(setIsEmptyView(true)); } diff --git a/src/actions/setLabelValues.js b/src/actions/setLabelValues.js index 77bdc1e0..98ab8da2 100644 --- a/src/actions/setLabelValues.js +++ b/src/actions/setLabelValues.js @@ -1,5 +1,4 @@ const setLabelValues = (labelValues) => (dispatch) => { - console.log('labelValues set to', labelValues) dispatch({ type: 'SET_LABEL_VALUES', labelValues diff --git a/src/actions/setLabels.js b/src/actions/setLabels.js index 02a04935..c97659f3 100644 --- a/src/actions/setLabels.js +++ b/src/actions/setLabels.js @@ -1,5 +1,4 @@ export const setLabels = (labels) => (dispatch) => { - console.log('labels set to',labels) dispatch({ type: 'SET_LABELS', labels: labels diff --git a/src/actions/setQueryLimit.js b/src/actions/setQueryLimit.js index 4d4819b9..b05e042e 100644 --- a/src/actions/setQueryLimit.js +++ b/src/actions/setQueryLimit.js @@ -1,5 +1,4 @@ export const setQueryLimit = (limit) => (dispatch) => { - console.log("limit set to",limit) dispatch({ type: 'SET_QUERY_LIMIT', limit diff --git a/src/components/LabelBrowser/ValuesList.js b/src/components/LabelBrowser/ValuesList.js index 68e74247..ee0aacbd 100644 --- a/src/components/LabelBrowser/ValuesList.js +++ b/src/components/LabelBrowser/ValuesList.js @@ -110,7 +110,6 @@ export const ValuesList = (props) => { useEffect(() => { setLabelList(labels); // LABELS - console.log('labels changed') }, [labels]); const handleRefresh = (e) => {