Skip to content

Commit c52bbae

Browse files
committed
multiple tags and request with query
1 parent 98721fa commit c52bbae

File tree

7 files changed

+122
-27
lines changed

7 files changed

+122
-27
lines changed

webapp/javascript/components/TagsBar.jsx

Lines changed: 67 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,76 @@ import { connect } from "react-redux";
33
import "react-dom";
44
import { Menu, SubMenu, MenuItem, MenuButton } from "@szhsin/react-menu";
55

6-
import { fetchTags, fetchTagValues } from "../redux/actions";
6+
import { fetchTags, fetchTagValues, updateTags } from "../redux/actions";
77
import history from "../util/history";
88

9-
function TagsBar({ tags, fetchTags, fetchTagValues, tagValuesLoading }) {
10-
const [tagsValue, setTagsValue] = useState("");
9+
function TagsBar({
10+
tags,
11+
fetchTags,
12+
fetchTagValues,
13+
updateTags,
14+
tagValuesLoading,
15+
labels,
16+
}) {
17+
const [tagsValue, setTagsValue] = useState("{}");
1118

1219
const loadTagValues = (tag) => {
1320
if (tags[tag] && !tags[tag].length && tagValuesLoading !== tag) {
1421
fetchTagValues(tag);
1522
}
1623
};
1724

25+
const onTagsValueChange = (tag, tagValue) => {
26+
if (!tagsValue.includes(tag)) {
27+
setTagsValue(
28+
tagsValue.replace(
29+
"}",
30+
`${tagsValue === "{}" ? "" : ","}${tag}=${tagValue}}`
31+
)
32+
);
33+
} else {
34+
const tagPairs = tagsValue.replace(/[{}]/g, "").split(",");
35+
tagPairs.forEach((pair, i) => {
36+
if (pair.startsWith(tag)) {
37+
tagPairs[i] = `${tag}=${tagValue}`;
38+
}
39+
});
40+
setTagsValue(`{${tagPairs.join(",")}}`);
41+
}
42+
};
43+
1844
useEffect(() => {
1945
fetchTags();
2046
}, []);
2147

2248
useEffect(() => {
2349
const url = new URL(window.location.href);
50+
const tagsParams = [];
2451
Object.keys(tags).forEach((tag) => {
2552
if (url.search.includes(tag)) {
2653
loadTagValues(tag);
27-
setTagsValue(`{${tag}=${url.searchParams.get(tag)}}`);
54+
tagsParams.push(`${tag}=${url.searchParams.get(tag)}`);
2855
}
2956
});
57+
setTagsValue(`{${tagsParams.join(",")}}`);
3058
}, [tags]);
3159

3260
useEffect(() => {
33-
const [name, value] = tagsValue.replace(/[{}]/g, "").split("=");
61+
const tagPairs = tagsValue.replace(/[{}]/g, "").split(",");
3462
const url = new URL(window.location.href);
35-
if (value) {
36-
url.searchParams.set(name, value);
37-
} else {
38-
url.searchParams.delete(name);
39-
}
63+
const tagsUpdater = [];
64+
tagPairs.forEach((pair) => {
65+
const [name, value] = pair.split("=");
66+
if (value) {
67+
url.searchParams.set(name, value);
68+
tagsUpdater.push({ name, value });
69+
} else {
70+
url.searchParams.delete(name);
71+
}
72+
});
4073
history.push(url.search);
74+
updateTags(tagsUpdater);
75+
console.log(tagsUpdater);
4176
}, [tagsValue]);
4277

4378
return (
@@ -56,7 +91,6 @@ function TagsBar({ tags, fetchTags, fetchTagValues, tagValuesLoading }) {
5691
loadTagValues(tag);
5792
return tag;
5893
}}
59-
onChange={(e) => loadTagValues(e.value)}
6094
className="active"
6195
>
6296
{tagValuesLoading === tag ? (
@@ -66,7 +100,7 @@ function TagsBar({ tags, fetchTags, fetchTagValues, tagValuesLoading }) {
66100
<MenuItem
67101
key={tagValue}
68102
value={tagValue}
69-
onClick={(e) => setTagsValue(`{${tag}=${e.value}}`)}
103+
onClick={(e) => onTagsValueChange(tag, e.value)}
70104
className={tagsValue.includes(tagValue) ? "active" : ""}
71105
>
72106
{tagValue}
@@ -76,16 +110,28 @@ function TagsBar({ tags, fetchTags, fetchTagValues, tagValuesLoading }) {
76110
</SubMenu>
77111
))}
78112
</Menu>
79-
<input
80-
className="tags-input"
81-
type="text"
82-
value={tagsValue}
83-
onChange={(e) => setTagsValue(e.target.value)}
84-
/>
113+
<div className="tags-query">
114+
<span className="tags-app-name">
115+
{labels && labels.find((label) => label.name === "__name__").value}
116+
</span>
117+
<pre className="tags-highlighted highlight-promql" aria-hidden="true">
118+
<code className="language-html" id="highlighting-content">
119+
{tagsValue}
120+
</code>
121+
</pre>
122+
<input
123+
className="tags-input"
124+
type="text"
125+
value={tagsValue}
126+
onChange={(e) => setTagsValue(e.target.value)}
127+
/>
128+
</div>
85129
</div>
86130
);
87131
}
88132

89-
export default connect((state) => state, { fetchTags, fetchTagValues })(
90-
TagsBar
91-
);
133+
export default connect((state) => state, {
134+
fetchTags,
135+
fetchTagValues,
136+
updateTags,
137+
})(TagsBar);

webapp/javascript/redux/actionTypes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ export const REQUEST_TAGS = "REQUEST_TAGS";
2020
export const RECEIVE_TAGS = "RECEIVE_TAGS";
2121
export const REQUEST_TAG_VALUES = "REQUEST_TAG_VALUES";
2222
export const RECEIVE_TAG_VALUES = "RECEIVE_TAG_VALUES";
23+
export const UPDATE_TAGS = "UPDATE_TAGS";

webapp/javascript/redux/actions.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
SET_LEFT_UNTIL,
2222
SET_RIGHT_FROM,
2323
SET_RIGHT_UNTIL,
24+
UPDATE_TAGS,
2425
} from "./actionTypes";
2526

2627
export const setDateRange = (from, until) => ({
@@ -108,6 +109,8 @@ export const receiveTagValues = (values, tag) => ({
108109
payload: { values, tag },
109110
});
110111

112+
export const updateTags = (tags) => ({ type: UPDATE_TAGS, payload: { tags } });
113+
111114
export const requestNames = () => ({ type: REQUEST_NAMES, payload: {} });
112115

113116
export const receiveNames = (names) => ({

webapp/javascript/redux/reducers/filters.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
SET_RIGHT_FROM,
2323
SET_LEFT_UNTIL,
2424
SET_RIGHT_UNTIL,
25+
UPDATE_TAGS,
2526
} from "../actionTypes";
2627

2728
const defaultName = window.initialState.appNames.find(
@@ -41,6 +42,7 @@ const initialState = {
4142
isJSONLoading: false,
4243
maxNodes: 1024,
4344
tags: [],
45+
selectedTags: [],
4446
};
4547

4648
window.uniqBy = uniqBy;
@@ -151,7 +153,9 @@ export default function (state = initialState, action) {
151153
...state,
152154
areTagsLoading: false,
153155
tags: action.payload.tags.reduce((acc, tag) => {
154-
acc[tag] = [];
156+
if (tag !== "__name__") {
157+
acc[tag] = [];
158+
}
155159
return acc;
156160
}, {}),
157161
};
@@ -170,6 +174,11 @@ export default function (state = initialState, action) {
170174
[action.payload.tag]: action.payload.values,
171175
},
172176
};
177+
case UPDATE_TAGS:
178+
return {
179+
...state,
180+
selectedTags: action.payload.tags,
181+
};
173182
case REQUEST_NAMES:
174183
return {
175184
...state,

webapp/javascript/util/updateRequests.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,12 @@ export function buildRenderURL(state, fromOverride=null, untilOverride=null, sid
1313
const nameLabel = state.labels.find((x) => x.name == '__name__');
1414

1515
if (nameLabel) {
16-
url += `&name=${nameLabel.value}{`;
16+
url += `&query=${nameLabel.value}{`;
1717
} else {
18-
url += '&name=unknown{';
18+
url += '&query=unknown{';
1919
}
2020

21-
// TODO: replace this so this is a real utility function
22-
url += state.labels.filter((x) => x.name != '__name__').map((x) => `${x.name}=${x.value}`).join(',');
21+
url += state.selectedTags.map((x) => `${x.name}="${x.value}"`).join(',');
2322
url += '}';
2423

2524
if (state.refreshToken) {

webapp/sass/components/labels.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
select {
1515
margin-right: 10px;
16-
max-width: 200px;
16+
width: fit-content;
1717
white-space: nowrap;
1818
overflow: hidden;
1919
text-overflow: ellipsis;

webapp/sass/components/tagsbar.scss

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,45 @@
4848
}
4949
}
5050

51+
.tags-query {
52+
flex-grow: 1;
53+
display: flex;
54+
align-items: center;
55+
}
56+
.tags-app-name {
57+
position: relative;
58+
border-top-left-radius: 4px;
59+
border-bottom-left-radius: 4px;
60+
background-color: #272727;
61+
border: 1px solid #4d4d4d;
62+
height: 100%;
63+
display: flex;
64+
align-items: center;
65+
padding: 0 5px;
66+
border-right: none;
67+
}
5168
.tags-input {
5269
flex-grow: 1;
70+
border-top-left-radius: 0px;
71+
border-bottom-left-radius: 0px;
72+
caret-color: #fff;
73+
color: rgba(0,0,0,0);
74+
letter-spacing: 0;
75+
font-family: arial;
76+
font-size: 16px;
5377
}
5478

79+
.tags-highlighted{
80+
height: 0;
81+
width: 0;
82+
margin-top: -12px;
83+
margin-right: -7px;
84+
z-index: 1;
85+
margin-left: 5px;
86+
pointer-events: none;
87+
code {
88+
font-size: 16px;
89+
font-family: arial;
90+
}
91+
}
5592
}

0 commit comments

Comments
 (0)