From b13d297452b2a03bff17b7b513d77b1637cf5657 Mon Sep 17 00:00:00 2001 From: jacovinus Date: Sat, 5 Mar 2022 19:24:48 +0100 Subject: [PATCH 1/4] add local services --- src/services/consts.js | 16 ++++++++ src/services/index.js | 4 ++ src/services/localHistory.js | 79 ++++++++++++++++++++++++++++++++++++ src/services/localLabels.js | 62 ++++++++++++++++++++++++++++ src/services/localQuery.js | 8 ++++ src/services/localService.js | 33 ++++++++++++++- src/services/localUrl.js | 64 +++++++++++++++++++++++++++++ 7 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 src/services/consts.js create mode 100644 src/services/index.js create mode 100644 src/services/localHistory.js create mode 100644 src/services/localLabels.js create mode 100644 src/services/localQuery.js create mode 100644 src/services/localUrl.js diff --git a/src/services/consts.js b/src/services/consts.js new file mode 100644 index 00000000..c192e43d --- /dev/null +++ b/src/services/consts.js @@ -0,0 +1,16 @@ +const _APP = "cloki-query"; +const _HISTORY_ITEM = _APP + "-history-item"; +const _TIMERANGE_ITEM = _APP + "-time-range-item"; +const _CHART_ITEM = _APP + "-chart-item"; +const _LABELS_ITEM = _APP + '-labels-item'; +const _URL_ITEM = _APP + "-url-item"; +const _QUERY_ITEM = _APP + "-url-item"; + +module.exports = { + _HISTORY_ITEM, + _CHART_ITEM, + _LABELS_ITEM, + _TIMERANGE_ITEM, + _URL_ITEM, + _QUERY_ITEM +} diff --git a/src/services/index.js b/src/services/index.js new file mode 100644 index 00000000..95c5b696 --- /dev/null +++ b/src/services/index.js @@ -0,0 +1,4 @@ +export * from './localHistory' +export * from './localLabels' +export * from './localQuery' +export * from './localUrl' diff --git a/src/services/localHistory.js b/src/services/localHistory.js new file mode 100644 index 00000000..d3865184 --- /dev/null +++ b/src/services/localHistory.js @@ -0,0 +1,79 @@ +import { nanoid } from "nanoid"; +import { _HISTORY_ITEM } from "./consts"; +import { l_set, l_get, j_parse, j_string, cleanup } from "./localService"; + +const localHistory = () => { + const get = () => { + return j_parse(l_get(_HISTORY_ITEM)); + }; + + const set = (data) => { + l_set(_HISTORY_ITEM, j_string(data)); + }; + + const clean = () => { + l_set(_HISTORY_ITEM, j_string(cleanup)); + return getAll() || []; + }; + + const historyStorage = get(); + + const findById = (item) => + historyStorage.find(({ id }) => item.id === id) || {}; + + const add = (item) => { + let previousData = get() || []; + try { + const newItem = { + id: item.id || nanoid(), + timestamp: item.timestamp || Date.now(), + starred: item.starred || false, + data: encodeURI(item.data) || "", + }; + let newStorage = [newItem].concat(previousData); + + set(newStorage); + return getAll(); + } catch (e) { + console.log("error on add", e); + } + }; + + const update = (item) => { + const { id } = item; + + let newStorage = []; + + try { + newStorage = historyStorage.map((m) => + m.id === id ? { ...m, ...item } : m + ); + set(newStorage); + return getAll(); + } catch (e) { + console.log(e); + } + }; + + function getAll() { + const actualStorage = j_parse(l_get(_HISTORY_ITEM)) || []; + + return ( + actualStorage?.map((m) => ({ + ...m, + data: decodeURI(m.data), + })) || [] + ); + } + + const remove = (item) => { + const filtered = historyStorage.filter(({ id }) => id !== item.id); + + set(filtered); + return getAll(); + }; + + return { clean, get, set, update, add, remove, getAll, findById }; +}; + +export default localHistory; diff --git a/src/services/localLabels.js b/src/services/localLabels.js new file mode 100644 index 00000000..77d7eab0 --- /dev/null +++ b/src/services/localLabels.js @@ -0,0 +1,62 @@ +import { nanoid } from "nanoid"; +import { _LABELS_ITEM } from "./consts"; +import { l_get, l_set, j_string, j_parse, cleanup } from "./localService"; + +const localLabels = () => { + const get = () => { + return l_get(_LABELS_ITEM); + }; + const set = (item) => { + l_set(_LABELS_ITEM, item); + }; + + const clean = () => { + l_set(_LABELS_ITEM, j_string(cleanup)); + return getAll() || []; + }; + + const labelsStorage = get(); + + const findById = (item) => + labelsStorage.find(({ id }) => item.id === id) || {}; + // add + const add = (item) => { + let previousData = get() || []; + try { + const newItem = { + id: item.id || nanoid(), + timestamp: item.timestamp || Date.now(), + data: item.data || {}, + }; + let newStorage = [newItem].concat(previousData); + set(newStorage); + return getAll(); + } catch (e) { + console.log(e); + } + }; + // update + const update = (item) => { + const { id } = item; + + let newStorage = []; + + try { + newStorage = labelsStorage.map((m) => + m.id === id ? { ...m, ...item } : m + ); + set(newStorage); + return getAll(); + } catch (e) { + console.log(e); + } + }; + // remove + function getAll() { + const actualStorage = j_parse(l_get(_LABELS_ITEM)) || []; + return actualStorage; + } + return { get, set, clean, add, update, findById, getAll }; +}; + +export default localLabels; diff --git a/src/services/localQuery.js b/src/services/localQuery.js new file mode 100644 index 00000000..b67c368b --- /dev/null +++ b/src/services/localQuery.js @@ -0,0 +1,8 @@ +import { nanoid } from "nanoid"; +import { _QUERY_ITEM } from "./consts"; + +import { getStorageItem, setStorageItem, cleanup } from "./localService"; + +const localQuery = () => {}; + +export default localQuery; diff --git a/src/services/localService.js b/src/services/localService.js index 72f1ce51..1825ea8d 100644 --- a/src/services/localService.js +++ b/src/services/localService.js @@ -5,6 +5,7 @@ function localService(item = null) { const _HISTORY_ITEM = _APP + "-history-item"; const _TIMERANGE_ITEM = _APP + "-time-range-item"; const _CHART_ITEM = _APP + "-chart-item"; + const _LABELS_ITEM = _APP + '-labels-item'; const cleanup = []; @@ -15,7 +16,10 @@ function localService(item = null) { const setStorageItem = (name, data) => { localStorage.setItem(name, data); }; - + const j_parse = (item) => JSON.parse(item) + const j_string = (item) => JSON.stringify(item) + const l_set = (item,value) => { localStorage.set(item,value) } + const l_get = (item) => localStorage.get(item) const historyStore = () => { const get = () => { return JSON.parse(getStorageItem(_HISTORY_ITEM)); @@ -94,8 +98,35 @@ function localService(item = null) { return { clean, get, set, getById, update, add, remove, getAll }; }; + const labelsStore = () => { + const get = () => { + return localStorage.getItem(_LABELS_ITEM); + } + const set = (item) => { + localStorage.setItem(_LABELS_ITEM,item) + } + + const clean = () => { + setStorageItem(_LABELS_ITEM, JSON.stringify(cleanup)); + return getAll()||[] + }; + + function getAll(){ + const actualStorage = JSON.parse(localStorage.getItem(_LABELS_ITEM))||[] + return actualStorage; + } + + } return { historyStore, + labelsStore, + setStorageItem, + getStorageItem, + cleanup, + j_parse, + j_string, + l_set, + l_get }; } diff --git a/src/services/localUrl.js b/src/services/localUrl.js new file mode 100644 index 00000000..66337015 --- /dev/null +++ b/src/services/localUrl.js @@ -0,0 +1,64 @@ +import { nanoid } from "nanoid"; +import { _HISTORY_ITEM, _URL_ITEM } from "./consts"; +import { l_set, l_get, cleanup, j_parse, j_string } from "./localService"; + +const localUrl = () => { + const get = () => { + return j_parse(l_get(_URL_ITEM)); + }; + const set = (item) => { + return l_set(_URL_ITEM, j_string(item)); + }; + const clean = () => { + l_set(_URL_ITEM, j_string(cleanup)); + }; + const urlStorage = get(); + + const findById = (item) => + urlStorage.find(({ id }) => item.id === id) || {}; + + const update = (item) => { + const { id } = item; + let newStorage = []; + try { + newStorage = urlStorage.map((m) => + m.id === id ? { ...m, ...item } : m + ); + set(newStorage); + return getAll(); + } catch (e) { + console.log(e); + } + }; + const add = (item) => { + let previousData = get() || []; + try { + const newItem = { + id: item.id || nanoid(), + timestamp: item.timestamp || Date.now(), + description: item.description || "", + data: item.data || "", + }; + let newStorage = [newItem].concat(previousData); + set(newStorage); + return getAll(); + } catch (e) { + console.log(e); + } + }; + + const remove = (item) => { + const filtered = urlStorage.filter(({ id }) => id !== item.id); + set(filtered); + return getAll(); + }; + + function getAll() { + const actualStorage = j_parse(l_get(_HISTORY_ITEM)) || []; + return actualStorage; + } + + return { clean, get, set, update, add, remove, getAll, findById }; +}; + +export default localUrl; From 764372a61a72c1ebb13802fa7ea6497f85bfa1a6 Mon Sep 17 00:00:00 2001 From: jacovinus Date: Mon, 7 Mar 2022 13:03:55 +0100 Subject: [PATCH 2/4] fix: #56 removing labels does not update state --- src/actions/LoadLabels.js | 3 - src/actions/loadLabelValues.js | 4 - src/actions/loadLogs.js | 6 +- src/components/LabelBrowser/QueryBar.js | 10 +- src/components/LabelBrowser/ValuesList.js | 1 - .../LabelBrowser/helpers/querybuilder.js | 7 +- src/components/LogView.js | 286 ++++++++++-------- src/components/UpdateStateFromQueryParams.js | 66 ++-- 8 files changed, 209 insertions(+), 174 deletions(-) diff --git a/src/actions/LoadLabels.js b/src/actions/LoadLabels.js index 5d1b4f5f..639124cc 100644 --- a/src/actions/LoadLabels.js +++ b/src/actions/LoadLabels.js @@ -32,10 +32,7 @@ export default function loadLabels(apiUrl) { const labels = response?.data?.data.sort().map((label) => ({ name: label, selected: false, - loading: false, values: [], - hidden: false, - facets: 0, })); dispatch(setLabels(labels || [])); } diff --git a/src/actions/loadLabelValues.js b/src/actions/loadLabelValues.js index ecab3020..baf189ca 100644 --- a/src/actions/loadLabelValues.js +++ b/src/actions/loadLabelValues.js @@ -37,8 +37,6 @@ export default function loadLabelValues(label, labelList, apiUrl) { const values = response?.data?.data?.map?.((value) => ({ name: value, selected: false, - loading: false, - hidden: false, inverted: false })); @@ -55,8 +53,6 @@ export default function loadLabelValues(label, labelList, apiUrl) { dispatch(setApiError('')) dispatch(setLabelValues(response?.data?.data)); - - }).catch(error => { dispatch(setLoading(false)) const { message } = errorHandler(url, error) diff --git a/src/actions/loadLogs.js b/src/actions/loadLogs.js index c12ea9f8..acf9efe2 100644 --- a/src/actions/loadLogs.js +++ b/src/actions/loadLogs.js @@ -17,7 +17,7 @@ export default function loadLogs() { // const step = 120 // const direction = 'backward' const localStore = store.getState(); - const { query: label, limit, step, apiUrl, label: rangeLabel } = localStore; + const { query, limit, step, apiUrl, label: rangeLabel } = localStore; let { start: startTs, stop: stopTs } = localStore; if (findRangeByLabel(rangeLabel)) { @@ -39,9 +39,9 @@ export default function loadLogs() { const queryStep = `&step=${step || 120}`; - const query = `${encodeURIComponent(label)}`; + const encodedQuery = `${encodeURIComponent(query)}`; - const getUrl = `${url}/loki/api/v1/query_range?query=${query}&limit=${limit}${parsedTime}${queryStep}`; + const getUrl = `${url}/loki/api/v1/query_range?query=${encodedQuery}&limit=${limit}${parsedTime}${queryStep}`; const options = { method: "GET", diff --git a/src/components/LabelBrowser/QueryBar.js b/src/components/LabelBrowser/QueryBar.js index 10f447f6..f3fae2df 100644 --- a/src/components/LabelBrowser/QueryBar.js +++ b/src/components/LabelBrowser/QueryBar.js @@ -10,7 +10,8 @@ import HistoryIcon from "@mui/icons-material/History"; import styled from "@emotion/styled"; import setHistoryOpen from "../../actions/setHistoryOpen"; import { Tooltip } from "@mui/material"; -import Badge from '@mui/material/Badge'; +import { decodeQuery } from "../UpdateStateFromQueryParams"; + const HistoryButton = styled.button` background: none; @@ -27,6 +28,7 @@ export const QueryBar = () => { const labelsBrowserOpen = useSelector((store) => store.labelsBrowserOpen); const debug = useSelector((store) => store.debug); const query = useSelector((store) => store.query); + const apiUrl = useSelector((store) => store.apiUrl) const isSubmit = useSelector((store) => store.isSubmit); const historyOpen = useSelector((store) => store.historyOpen) const [queryInput, setQueryInput] = useState(query); @@ -60,7 +62,6 @@ export const QueryBar = () => { ); // here dispatch(setLoading(true)); - dispatch(loadLogs()); setTimeout(() => { @@ -107,14 +108,15 @@ export const QueryBar = () => { dispatch(setQuery(queryInput)); - if (onQueryValid(query)) { + if (onQueryValid(queryInput)) { try { const historyUpdated = historyService.add({ - data: query, + data: queryInput, url: window.location.hash, }); dispatch(setQueryHistory(historyUpdated)); dispatch(setLabelsBrowserOpen(false)); + decodeQuery(query,apiUrl) dispatch(loadLogs()); } catch (e) { console.log(e); diff --git a/src/components/LabelBrowser/ValuesList.js b/src/components/LabelBrowser/ValuesList.js index afd1a8d4..e6f25e0b 100644 --- a/src/components/LabelBrowser/ValuesList.js +++ b/src/components/LabelBrowser/ValuesList.js @@ -32,7 +32,6 @@ export const ValuesList = (props) => { const [labelsSelected, setLabelsSelected] = useState([]); const labels = useSelector(state => { const selected = state.labels.filter((f) => f.selected); - console.log(JSON.stringify(selected) !== JSON.stringify(labelsSelected)) if (JSON.stringify(selected) !== JSON.stringify(labelsSelected)) { setLabelsSelected(selected); } diff --git a/src/components/LabelBrowser/helpers/querybuilder.js b/src/components/LabelBrowser/helpers/querybuilder.js index 81cf2d77..c34e4624 100644 --- a/src/components/LabelBrowser/helpers/querybuilder.js +++ b/src/components/LabelBrowser/helpers/querybuilder.js @@ -2,6 +2,7 @@ import { setQuery } from "../../../actions"; import store from "../../../store/store"; export function queryBuilder(labels) { + console.log(labels) const selectedLabels = []; for (const label of labels) { if (label.selected && label.values && label.values.length > 0) { @@ -30,6 +31,6 @@ export function queryBuilder(labels) { export function queryBuilderWithLabels() { const labels = store.getState().labels; console.log(labels) - const query = queryBuilder(labels) - store.dispatch(setQuery(query)); -} \ No newline at end of file + const query = queryBuilder(labels) + store.dispatch(setQuery(query)); +} diff --git a/src/components/LogView.js b/src/components/LogView.js index 6578d0d6..63a428bf 100644 --- a/src/components/LogView.js +++ b/src/components/LogView.js @@ -1,185 +1,210 @@ import { ZoomIn, ZoomOut } from "@mui/icons-material/"; -import { CircularProgress, } from "@mui/material"; +import { CircularProgress } from "@mui/material"; import * as moment from "moment"; import React, { Component } from "react"; import { connect } from "react-redux"; import { setLabels } from "../actions"; -import loadLabelValues from '../actions/loadLabelValues'; +import loadLabelValues from "../actions/loadLabelValues"; import ClokiChart from "../plugins/charts"; import QueryHistory from "../plugins/queryhistory"; import store from "../store/store"; import { queryBuilderWithLabels } from "./LabelBrowser/helpers/querybuilder"; -import loadLogs from "../actions/loadLogs" +import loadLogs from "../actions/loadLogs"; +import styled from "@emotion/styled"; + +const EmptyViewContainer = styled.div` + color: white; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 175px; + font-size: 1em; + color: #aaa; + font-weight: lighter; + letter-spacing: 1px; +`; const TAGS_LEVEL = { - critical: ['emerg', 'fatal', 'alert', 'crit', 'critical'], - error: ['err', 'eror', 'error', 'warning'], - warning: ['warn', 'warning'], - info: ['info', 'information', 'notice'], - debug: ['dbug', 'debug'], - trace: ['trace'] -} + critical: ["emerg", "fatal", "alert", "crit", "critical"], + error: ["err", "eror", "error", "warning"], + warning: ["warn", "warning"], + info: ["info", "information", "notice"], + debug: ["dbug", "debug"], + trace: ["trace"], +}; export const ValueTags = (props) => { const addLabel = async (e, key, value, isInverted = false) => { e.preventDefault(); e.stopPropagation(); - const {labels, apiUrl} = store.getState(); - const label = labels.find(label => label.name === key); + const { labels, apiUrl } = store.getState(); + console.log(e,key, value, isInverted) + const label = labels.find((label) => label.name === key); if (label) { - const labelValue = label.values.find(tag => tag.name === value); + const labelValue = label.values.find((tag) => tag.name === value); if (labelValue?.selected && labelValue.inverted === isInverted) { - console.log(labelValue) + console.log(labelValue); return; } if (labelValue) { - labelValue.selected = true || (labelValue.inverted !== isInverted); + labelValue.selected = + true || labelValue.inverted !== isInverted; labelValue.inverted = !labelValue.inverted && isInverted; - label.selected = label.values.some(value => value.selected); + label.selected = label.values.some((value) => value.selected); store.dispatch(setLabels(labels)); } else { - await store.dispatch(loadLabelValues(label,labels,apiUrl)); + await store.dispatch(loadLabelValues(label, labels, apiUrl)); const updatedLabels = store.getState().labels; - const updatedLabel = updatedLabels.find(label => label.name === key); - const labelValue = updatedLabel.values.find(tag => tag.name === value); - labelValue.selected = true || (labelValue.inverted !== isInverted); + const updatedLabel = updatedLabels.find( + (label) => label.name === key + ); + const labelValue = updatedLabel.values.find( + (tag) => tag.name === value + ); + labelValue.selected = + true || labelValue.inverted !== isInverted; labelValue.inverted = !labelValue.inverted && isInverted; - updatedLabel.selected = updatedLabel.values.some(value => value.selected); + updatedLabel.selected = updatedLabel.values.some( + (value) => value.selected + ); store.dispatch(setLabels(updatedLabels)); } - queryBuilderWithLabels() - store.dispatch(loadLogs()) + queryBuilderWithLabels(); + + store.dispatch(loadLogs()); } - } + }; const getTags = (tags) => { - return Object.entries(tags).map( - ([key, value], k) => ( -
- addLabel(e, key, value)} className={'icon'}> - - - addLabel(e, key, value, true)} className={'icon'}> - - - - {key} - {value} -
- ) - ) - } - - return getTags(props.tags) + return Object.entries(tags).map(([key, value], k) => ( +
+ addLabel(e, key, value)} + className={"icon"} + > + + + addLabel(e, key, value, true)} + className={"icon"} + > + + + + {key} + {value} +
+ )); + }; -} + return getTags(props.tags); +}; class LogView extends Component { - constructor(props) { - super(props) + super(props); this.state = { limitLoad: this.props.limitLoad || false, limit: props.limit || 100, messages: props.messages || [], matrixData: props.matrixData || [], - loading: false - } + loading: false, + }; } - - toggleTagsActive(idx) { - let arrCopy = [...this.props.messages] - arrCopy.forEach( entry => { - if(entry.id === idx) { - entry.showLabels = entry.showLabels ? false : true + toggleTagsActive(idx) { + let arrCopy = [...this.props.messages]; + arrCopy.forEach((entry) => { + if (entry.id === idx) { + entry.showLabels = entry.showLabels ? false : true; } - }) - this.setState({...this.state,logs : arrCopy}) + }); + this.setState({ ...this.state, logs: arrCopy }); } - toggleActiveStyles(idx){ - return idx.showLabels ? "value-tags-container labelsActive" : "value-tags-container labelsInactive" - - } - getMatrixForChart = () => { - return this.props.matrixData + toggleActiveStyles(idx) { + return idx.showLabels + ? "value-tags-container labelsActive" + : "value-tags-container labelsInactive"; } + getMatrixForChart = () => { + return this.props.matrixData; + }; getLimit = () => { - return this.props.limit - } + return this.props.limit; + }; onShowTags = (e, value) => { - e.preventDefault() + e.preventDefault(); value.showLabels = !value.showLabels; - const logs = value - this.setState({ ...this.state, messages: logs }) - } + const logs = value; + this.setState({ ...this.state, messages: logs }); + }; getLogColor = (tags) => { - if (tags?.['level']) { - return Object.keys(TAGS_LEVEL).find(level => TAGS_LEVEL[level].includes((tags.level).toLowerCase())) - - } else { return 'unknown' } - - } + if (tags?.["level"]) { + return Object.keys(TAGS_LEVEL).find((level) => + TAGS_LEVEL[level].includes(tags.level.toLowerCase()) + ); + } else { + return "unknown"; + } + }; render() { - return (
- {this.props.messages.length > 0 && this.getMatrixForChart().length < 1 ? ( - this.props.messages.map((value, key) => ( -
this.toggleTagsActive(value.id)} - > - - {this.formatDate(value.timestamp)} - - {value.text} - - {value.tags && ( -
- -
- )} -
- ) - - ) ): (null)} - + {this.props.messages.length > 0 && + this.getMatrixForChart().length < 1 + ? this.props.messages.map((value, key) => ( +
+ this.toggleTagsActive(value.id) + } + > + + {this.formatDate(value.timestamp)} + + + {value.text} + + + {value.tags && ( +
+ +
+ )} +
+ )) + : null} {this.getMatrixForChart().length > 0 ? ( - ) : (null)} - {this.props.messages.length < 1 && this.getMatrixForChart().length < 1 && !this.props.loading &&( -
- - {"Please adjust search parameters and click on ‘Show Logs’ button"} - - -
- )} - + ) : null} + {this.props.messages.length < 1 && + this.getMatrixForChart().length < 1 && + !this.props.loading && ( + + { + "Please adjust search parameters and click on ‘Show Logs’ button" + } + + )} + {this.props.loading && ( { - return moment(parseInt(timestamp)).format("YYYY-MM-DD HH:mm:ss.SSS UTC"); + return moment(parseInt(timestamp)).format( + "YYYY-MM-DD HH:mm:ss.SSS UTC" + ); }; } @@ -204,7 +230,7 @@ const mapStateToProps = (state) => { stop: state.stop, limit: state.limit, loading: state.loading, - matrixData: state.matrixData + matrixData: state.matrixData, }; }; diff --git a/src/components/UpdateStateFromQueryParams.js b/src/components/UpdateStateFromQueryParams.js index 8ad705b9..03bf1ad0 100644 --- a/src/components/UpdateStateFromQueryParams.js +++ b/src/components/UpdateStateFromQueryParams.js @@ -82,7 +82,6 @@ export function UpdateStateFromQueryParams() { dispatch(STORE_ACTIONS[param](startParams[param])) } else if (QUERY_VALUE === param && startParams[param] !== '') { const parsedQuery = decodeURIComponent(startParams[param]) - decodeQuery(parsedQuery, apiUrl) dispatch(STORE_ACTIONS[param](parsedQuery)) } else if (TIME_VALUES.includes(param) && startParams[param] !== '') { const croppedTime = ((startParams[param])) / 1000000 @@ -95,6 +94,8 @@ export function UpdateStateFromQueryParams() { } }) + decodeQuery(decodeURIComponent(startParams.query),apiUrl) + } } @@ -116,12 +117,14 @@ export function UpdateStateFromQueryParams() { urlFromHash.set(param, time_value.toString()) } else if (QUERY_VALUE === param) { const parsed = encodeURIComponent(STORE_KEYS[param]).toString(); - decodeQuery(parsed, apiUrl) urlFromHash.set(param, parsed.toString()) } else if(BOOLEAN_VALUES === param && typeof param === 'boolean') { urlFromHash.set(param,param.toString()) } }) + const newQuery = STORE_KEYS[query] + decodeQuery(newQuery,apiUrl) + window.location.hash = urlFromHash } @@ -175,8 +178,9 @@ export function UpdateStateFromQueryParams() { }, [STORE_KEYS]) } -async function decodeQuery(query, apiUrl) { - await store.dispatch(loadLabels(apiUrl)) + + export async function decodeQuery(query, apiUrl) { + await store.dispatch(loadLabels(apiUrl)) const queryArr = query.replaceAll(/[{}]/g,'').split(','); const labelsFromQuery = []; queryArr.forEach(label => { @@ -198,7 +202,6 @@ async function decodeQuery(query, apiUrl) { labelsFromQuery.push(labelObj); } else if(label.includes("=~")) { const values = regexQuery[1].split('|') - console.log(values) const labelObj = { name: regexQuery[0], values: [] @@ -228,27 +231,38 @@ async function decodeQuery(query, apiUrl) { } }); const newLabels = store.getState().labels; - labelsFromQuery.forEach(async (label) => { - - const cleanLabel = newLabels?.find(item => item?.name === label?.name); - if (!cleanLabel) { - return + newLabels.forEach(label=> { + if(label.selected && label.values > 0){ + label.selected = false + label.values.forEach(value=> { + if(value.selected) { + value.selected = false; + } + }) } - - await store.dispatch(loadLabelValues(cleanLabel,newLabels,apiUrl)); - const labelsWithValues = store.getState().labels; - const labelWithValues = labelsWithValues.find(item => item?.name === label?.name); - let values = labelWithValues.values; - values = label.values.concat(values); - values = values - .sort((a, b) => a.name.localeCompare(b.name)) - .filter((i, k, a) => { - console.log(a[k-1]) - return i.name !== a[k - 1]?.name}) - .filter((i) => !!i); - labelWithValues.values = values; - labelWithValues.selected = true; - store.dispatch(setLabels(labelsWithValues)) }) -} \ No newline at end of file + if(labelsFromQuery.length > 0) { + labelsFromQuery.forEach( async(label) => { + + const cleanLabel = newLabels?.find(item => item?.name === label?.name); + if (!cleanLabel) { + return + } + await store.dispatch(loadLabelValues(cleanLabel,newLabels,apiUrl)); + const labelsWithValues = store.getState().labels; + const labelWithValues = labelsWithValues.find(item => item?.name === label?.name); + let values = labelWithValues.values; + values = label.values.concat(values); + values = values + .sort((a, b) => a.name.localeCompare(b.name)) + .filter((value, index, arr) => { + return value.name !== arr[index - 1]?.name}) + .filter((value) => !!value); + labelWithValues.values = values; + labelWithValues.selected = true; + store.dispatch(setLabels(labelsWithValues)) + }) + } + +} From 662d47841b9892380e915efce45744cda58900e9 Mon Sep 17 00:00:00 2001 From: jacovinus Date: Mon, 7 Mar 2022 16:19:39 +0100 Subject: [PATCH 3/4] fix labels with matrix --- src/components/UpdateStateFromQueryParams.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/UpdateStateFromQueryParams.js b/src/components/UpdateStateFromQueryParams.js index 03bf1ad0..ad98393b 100644 --- a/src/components/UpdateStateFromQueryParams.js +++ b/src/components/UpdateStateFromQueryParams.js @@ -181,7 +181,7 @@ export function UpdateStateFromQueryParams() { export async function decodeQuery(query, apiUrl) { await store.dispatch(loadLabels(apiUrl)) - const queryArr = query.replaceAll(/[{}]/g,'').split(','); + const queryArr = query.match(/[^{\}]+(?=})/g, "$1").map(m => m.split(",")).flat() const labelsFromQuery = []; queryArr.forEach(label => { const regexQuery = label.match(/([^{}=,~!]+)/gm); From 36b4f993647e72f004343b8f2434f473fbd5edc8 Mon Sep 17 00:00:00 2001 From: jacovinus Date: Mon, 7 Mar 2022 18:58:56 +0100 Subject: [PATCH 4/4] change close to clear labels --- src/components/LabelBrowser/QueryBar.js | 4 +++- src/components/LabelBrowser/ValuesList.js | 4 ++-- src/components/StatusBar/StatusBar.js | 6 +++--- src/components/UpdateStateFromQueryParams.js | 7 +++---- src/services/localService.js | 7 +++++-- src/services/localUrl.js | 6 +++++- 6 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/components/LabelBrowser/QueryBar.js b/src/components/LabelBrowser/QueryBar.js index f3fae2df..50b81c87 100644 --- a/src/components/LabelBrowser/QueryBar.js +++ b/src/components/LabelBrowser/QueryBar.js @@ -11,6 +11,7 @@ import styled from "@emotion/styled"; import setHistoryOpen from "../../actions/setHistoryOpen"; import { Tooltip } from "@mui/material"; import { decodeQuery } from "../UpdateStateFromQueryParams"; +import localUrl from "../../services/localUrl"; const HistoryButton = styled.button` @@ -38,7 +39,7 @@ export const QueryBar = () => { const LOG_BROWSER = "Log Browser"; const queryHistory = useSelector((store) => store.queryHistory) const [historyItems, setHistoryItems] = useState(queryHistory.length>0) - + const saveUrl = localUrl() useEffect(()=>{ setHistoryItems(queryHistory.length>0) },[queryHistory]) @@ -118,6 +119,7 @@ export const QueryBar = () => { dispatch(setLabelsBrowserOpen(false)); decodeQuery(query,apiUrl) dispatch(loadLogs()); + saveUrl.add({data: window.location.href, description:'From Query Submit'}) } catch (e) { console.log(e); } diff --git a/src/components/LabelBrowser/ValuesList.js b/src/components/LabelBrowser/ValuesList.js index e6f25e0b..efeb26ba 100644 --- a/src/components/LabelBrowser/ValuesList.js +++ b/src/components/LabelBrowser/ValuesList.js @@ -46,7 +46,7 @@ export const ValuesList = (props) => { if(debug) console.log('🚧 LOGIC/LabelBrowser/ValuesList', apiUrl) const labelsBrowserOpen = useSelector((store) => store.labelsBrowserOpen) - const CLOSE = "close" + const CLEAR = "clear" /** * TODO: FILTER VALUES INSIDE LABELS */ @@ -190,7 +190,7 @@ export const ValuesList = (props) => { onClick={(e) => onLabelOpen(e, labelSelected) } - >{CLOSE} + >{CLEAR}
{labelSelected?.values?.map( diff --git a/src/components/StatusBar/StatusBar.js b/src/components/StatusBar/StatusBar.js index a8b1b822..89168a18 100644 --- a/src/components/StatusBar/StatusBar.js +++ b/src/components/StatusBar/StatusBar.js @@ -11,9 +11,9 @@ import { DateRangePicker } from "../../plugins/daterangepicker"; import { DATE_TIME_RANGE } from '../../plugins/daterangepicker/consts'; import { findRangeByLabel } from "../../plugins/daterangepicker/utils"; import { UpdateStateFromQueryParams } from "../UpdateStateFromQueryParams"; - import store from '../../store/store' import loadLabels from "../../actions/LoadLabels"; +import localUrl from "../../services/localUrl"; export default function StatusBar() { @@ -150,6 +150,7 @@ export function StatusBarSelectors() { const dispatch = useDispatch(); const [open, setOpen] = useState() const LINK_COPIED = "Link Copied To Clipboard" + const saveUrl = localUrl() const initialDateRange = () => { try { const ls = JSON.parse(localStorage.getItem(DATE_TIME_RANGE)); @@ -179,6 +180,7 @@ export function StatusBarSelectors() { const setSubmit = dispatch(setIsSubmit(true)) setTimeout(()=>{ navigator.clipboard.writeText(window.location.href).then(function () { + saveUrl.add({data:window.location.href,description:'From Shared URL'}) setCopied(true) setTimeout(() => { setCopied(false) @@ -189,8 +191,6 @@ export function StatusBarSelectors() { }) },200) - - } return ( diff --git a/src/components/UpdateStateFromQueryParams.js b/src/components/UpdateStateFromQueryParams.js index ad98393b..9e041f0e 100644 --- a/src/components/UpdateStateFromQueryParams.js +++ b/src/components/UpdateStateFromQueryParams.js @@ -173,7 +173,6 @@ export function UpdateStateFromQueryParams() { } }) window.location.hash = paramsFromHash - } }, [STORE_KEYS]) @@ -181,9 +180,9 @@ export function UpdateStateFromQueryParams() { export async function decodeQuery(query, apiUrl) { await store.dispatch(loadLabels(apiUrl)) - const queryArr = query.match(/[^{\}]+(?=})/g, "$1").map(m => m.split(",")).flat() + const queryArr = query?.match(/[^{\}]+(?=})/g, "$1")?.map(m => m.split(","))?.flat() const labelsFromQuery = []; - queryArr.forEach(label => { + queryArr?.forEach(label => { const regexQuery = label.match(/([^{}=,~!]+)/gm); if (!regexQuery) { return; @@ -231,7 +230,7 @@ export function UpdateStateFromQueryParams() { } }); const newLabels = store.getState().labels; - newLabels.forEach(label=> { + newLabels?.forEach(label=> { if(label.selected && label.values > 0){ label.selected = false label.values.forEach(value=> { diff --git a/src/services/localService.js b/src/services/localService.js index 1825ea8d..5a947554 100644 --- a/src/services/localService.js +++ b/src/services/localService.js @@ -1,4 +1,5 @@ import { nanoid } from "nanoid"; + function localService(item = null) { const _APP = "cloki-query"; @@ -18,8 +19,8 @@ function localService(item = null) { }; const j_parse = (item) => JSON.parse(item) const j_string = (item) => JSON.stringify(item) - const l_set = (item,value) => { localStorage.set(item,value) } - const l_get = (item) => localStorage.get(item) + const l_set = (item,value) => { localStorage.setItem(item,value) } + const l_get = (item) => localStorage.getItem(item) const historyStore = () => { const get = () => { return JSON.parse(getStorageItem(_HISTORY_ITEM)); @@ -117,6 +118,8 @@ function localService(item = null) { } } + + return { historyStore, labelsStore, diff --git a/src/services/localUrl.js b/src/services/localUrl.js index 66337015..5cf76db6 100644 --- a/src/services/localUrl.js +++ b/src/services/localUrl.js @@ -1,8 +1,12 @@ import { nanoid } from "nanoid"; import { _HISTORY_ITEM, _URL_ITEM } from "./consts"; -import { l_set, l_get, cleanup, j_parse, j_string } from "./localService"; +import localService from "./localService"; + const localUrl = () => { + + const {l_set, l_get, cleanup, j_parse, j_string} = localService() + const get = () => { return j_parse(l_get(_URL_ITEM)); };