andoncloud-prometheus-widget 1.3.17 → 1.3.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -3
- package/dist/assets/thumbnail.svg +42 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.js +278 -101
- package/dist/index.js.map +1 -1
- package/dist/thumbnail-B_DBfYD0.js +6 -0
- package/dist/thumbnail-B_DBfYD0.js.map +1 -0
- package/package.json +33 -31
- package/dist/index.cjs +0 -628
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -42
package/dist/index.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
+
import { t as thumbnail_default } from "./thumbnail-B_DBfYD0.js";
|
|
1
2
|
import { registerTranslations } from "andoncloud-sdk";
|
|
2
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
4
|
import { generateTimeRange, getCurrentShift, getRecentShift, normalizeShifts, useGqlClients } from "andoncloud-dashboard-toolkit";
|
|
4
5
|
import { BaseWidget } from "andoncloud-widget-base";
|
|
5
6
|
import { useTranslation } from "react-i18next";
|
|
6
7
|
import { Clear } from "@mui/icons-material";
|
|
7
8
|
import { TabContext, TabList, TabPanel } from "@mui/lab";
|
|
8
|
-
import { Box, Button, FormControl, FormHelperText, IconButton, InputLabel, MenuItem, Select, Stack, Tab, TextField } from "@mui/material";
|
|
9
|
+
import { Alert, Box, Button, Divider, FormControl, FormHelperText, IconButton, InputLabel, MenuItem, Select, Stack, Tab, TextField, Typography } from "@mui/material";
|
|
9
10
|
import { getIn } from "formik";
|
|
10
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
import "chartjs-adapter-dayjs-4";
|
|
11
13
|
import { Line } from "react-chartjs-2";
|
|
12
14
|
import { CategoryScale, Chart, Filler, Legend, LineElement, LinearScale, PointElement, TimeScale, Tooltip } from "chart.js";
|
|
13
|
-
import "chartjs-adapter-dayjs-4";
|
|
14
|
-
import { PrometheusDriver } from "prometheus-query";
|
|
15
15
|
import dayjs from "dayjs";
|
|
16
|
-
import
|
|
16
|
+
import { PrometheusDriver } from "prometheus-query";
|
|
17
17
|
import Color from "color";
|
|
18
18
|
import { satisfies } from "compare-versions";
|
|
19
19
|
import * as yup from "yup";
|
|
@@ -25,51 +25,73 @@ const resources = {
|
|
|
25
25
|
"addAnotherDisplayedQueryParameter": "Add another displayed query parameter",
|
|
26
26
|
"addAnotherQuery": "Add another query",
|
|
27
27
|
"advanced": "Advanced",
|
|
28
|
+
"credentialsHelper": "Credentials are optional. Fill in only if the instance requires authentication.",
|
|
28
29
|
"currentShift": "Current shift",
|
|
29
30
|
"customTitle": "Custom title",
|
|
30
31
|
"displayedQueryParameter": "Displayed query parameter",
|
|
32
|
+
"displayName": "PromQL chart",
|
|
31
33
|
"endpointUrl": "Endpoint URL",
|
|
34
|
+
"errorAuth": "Could not authenticate to Prometheus. Check the username and password in widget settings.",
|
|
35
|
+
"errorForbidden": "Authenticated, but the Prometheus user has no permission to read these metrics.",
|
|
36
|
+
"errorUnreachable": "Could not reach Prometheus at the configured URL.",
|
|
37
|
+
"insecureWarning": "Credentials will be sent over an unencrypted connection (HTTP). Use HTTPS to protect them.",
|
|
32
38
|
"name": "Name",
|
|
39
|
+
"password": "Password",
|
|
33
40
|
"period": "Period",
|
|
34
41
|
"previousShift": "Previous shift",
|
|
35
42
|
"query": "Query",
|
|
43
|
+
"removeParam": "Remove parameter",
|
|
44
|
+
"removeQuery": "Remove query",
|
|
45
|
+
"sectionAuthorization": "Authorization",
|
|
46
|
+
"sectionData": "Data",
|
|
36
47
|
"settings": "Settings",
|
|
37
48
|
"thisFieldIsRequired": "This field is required",
|
|
38
|
-
"xAxisUnit": "X axis unit",
|
|
39
|
-
"displayName": "PromQL chart",
|
|
40
|
-
"titleQueries_one": "{{count}} query",
|
|
41
|
-
"titleQueries_other": "{{count}} queries",
|
|
42
49
|
"titleCurrentShift": "current shift",
|
|
43
50
|
"titlePreviousShift": "previous shift",
|
|
51
|
+
"titleQueries_one": "{{count}} query",
|
|
52
|
+
"titleQueries_other": "{{count}} queries",
|
|
53
|
+
"username": "Username",
|
|
54
|
+
"xAxisUnit": "X axis unit",
|
|
44
55
|
"yAxisUnit": "Y axis unit"
|
|
45
56
|
} } },
|
|
46
57
|
pl: { translation: { prometheusWidget: {
|
|
47
58
|
"addAnotherDisplayedQueryParameter": "Dodaj kolejny wyświetlany parametr zapytania",
|
|
48
59
|
"addAnotherQuery": "Dodaj kolejne zapytanie",
|
|
49
60
|
"advanced": "Zaawansowane",
|
|
61
|
+
"credentialsHelper": "Dane autoryzacyjne są opcjonalne. Wypełnij tylko jeśli instancja wymaga uwierzytelniania.",
|
|
50
62
|
"currentShift": "Obecna zmiana",
|
|
51
63
|
"customTitle": "Własny tytuł",
|
|
52
64
|
"displayedQueryParameter": "Wyświetlany parametr zapytania",
|
|
65
|
+
"displayName": "Wykres PromQL",
|
|
53
66
|
"endpointUrl": "Adres URL",
|
|
67
|
+
"errorAuth": "Nie można uwierzytelnić się w Prometheusie. Sprawdź nazwę użytkownika i hasło w ustawieniach widgetu.",
|
|
68
|
+
"errorForbidden": "Uwierzytelnienie powiodło się, ale użytkownik Prometheusa nie ma uprawnień do tych metryk.",
|
|
69
|
+
"errorUnreachable": "Nie można połączyć się z Prometheusem pod skonfigurowanym adresem.",
|
|
70
|
+
"insecureWarning": "Dane logowania zostaną wysłane nieszyfrowanym połączeniem (HTTP). Użyj HTTPS, aby je chronić.",
|
|
54
71
|
"name": "Nazwa",
|
|
72
|
+
"password": "Hasło",
|
|
55
73
|
"period": "Okres",
|
|
56
74
|
"previousShift": "Poprzednia zmiana",
|
|
57
75
|
"query": "Zapytanie",
|
|
76
|
+
"removeParam": "Usuń parametr",
|
|
77
|
+
"removeQuery": "Usuń zapytanie",
|
|
78
|
+
"sectionAuthorization": "Autoryzacja",
|
|
79
|
+
"sectionData": "Dane",
|
|
58
80
|
"settings": "Ustawienia",
|
|
59
81
|
"thisFieldIsRequired": "To pole jest wymagane",
|
|
60
|
-
"xAxisUnit": "Jednostka osi X",
|
|
61
|
-
"displayName": "Wykres PromQL",
|
|
62
|
-
"titleQueries_one": "{{count}} zapytanie",
|
|
63
|
-
"titleQueries_few": "{{count}} zapytania",
|
|
64
|
-
"titleQueries_many": "{{count}} zapytań",
|
|
65
82
|
"titleCurrentShift": "obecna zmiana",
|
|
66
83
|
"titlePreviousShift": "poprzednia zmiana",
|
|
84
|
+
"titleQueries_few": "{{count}} zapytania",
|
|
85
|
+
"titleQueries_many": "{{count}} zapytań",
|
|
86
|
+
"titleQueries_one": "{{count}} zapytanie",
|
|
87
|
+
"username": "Nazwa użytkownika",
|
|
88
|
+
"xAxisUnit": "Jednostka osi X",
|
|
67
89
|
"yAxisUnit": "Jednostka osi Y"
|
|
68
90
|
} } }
|
|
69
91
|
};
|
|
70
92
|
//#endregion
|
|
71
93
|
//#region src/version.ts
|
|
72
|
-
const LIBRARY_VERSION = "1.3.
|
|
94
|
+
const LIBRARY_VERSION = "1.3.19";
|
|
73
95
|
//#endregion
|
|
74
96
|
//#region src/types.ts
|
|
75
97
|
let QueriesPeriod = /* @__PURE__ */ function(QueriesPeriod) {
|
|
@@ -78,14 +100,87 @@ let QueriesPeriod = /* @__PURE__ */ function(QueriesPeriod) {
|
|
|
78
100
|
return QueriesPeriod;
|
|
79
101
|
}({});
|
|
80
102
|
//#endregion
|
|
103
|
+
//#region src/components/SettingsFormContent/utils.ts
|
|
104
|
+
const isInsecureEndpoint = (url) => /^http:\/\//i.test(url);
|
|
105
|
+
//#endregion
|
|
106
|
+
//#region src/components/SettingsFormContent/styles.ts
|
|
107
|
+
const styles = {
|
|
108
|
+
sectionDivider: {
|
|
109
|
+
marginTop: 3,
|
|
110
|
+
marginBottom: 1,
|
|
111
|
+
color: (theme) => theme.palette.text.primary,
|
|
112
|
+
fontWeight: 600,
|
|
113
|
+
letterSpacing: "0.08em",
|
|
114
|
+
textTransform: "uppercase",
|
|
115
|
+
fontSize: "0.75rem",
|
|
116
|
+
"&::before, &::after": { borderColor: "rgba(255, 255, 255, 0.15)" }
|
|
117
|
+
},
|
|
118
|
+
formControl: { marginTop: 2 },
|
|
119
|
+
addButton: { marginTop: 2 },
|
|
120
|
+
credentialsHelper: {
|
|
121
|
+
marginTop: 1,
|
|
122
|
+
color: (theme) => theme.palette.text.primary
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
//#endregion
|
|
126
|
+
//#region src/components/SettingsFormContent/CredentialsFields/index.tsx
|
|
127
|
+
const CredentialsFields = ({ formProps }) => {
|
|
128
|
+
const [passwordInput, setPasswordInput] = useState("");
|
|
129
|
+
const { t } = useTranslation();
|
|
130
|
+
const handlePasswordChange = (event) => {
|
|
131
|
+
setPasswordInput(event.target.value);
|
|
132
|
+
formProps.setFieldValue("password", event.target.value);
|
|
133
|
+
};
|
|
134
|
+
const showInsecureWarning = isInsecureEndpoint(formProps.values.endpointUrl);
|
|
135
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
136
|
+
/* @__PURE__ */ jsx(FormHelperText, {
|
|
137
|
+
sx: styles.credentialsHelper,
|
|
138
|
+
"data-testid": "prometheus.settings.credentials-helper",
|
|
139
|
+
children: t("prometheusWidget.credentialsHelper")
|
|
140
|
+
}),
|
|
141
|
+
/* @__PURE__ */ jsx(FormControl, {
|
|
142
|
+
sx: styles.formControl,
|
|
143
|
+
fullWidth: true,
|
|
144
|
+
children: /* @__PURE__ */ jsx(TextField, {
|
|
145
|
+
name: "username",
|
|
146
|
+
label: t("prometheusWidget.username"),
|
|
147
|
+
value: formProps.values.username || "",
|
|
148
|
+
onChange: formProps.handleChange,
|
|
149
|
+
onBlur: formProps.handleBlur,
|
|
150
|
+
"data-testid": "prometheus.settings.username",
|
|
151
|
+
fullWidth: true
|
|
152
|
+
})
|
|
153
|
+
}),
|
|
154
|
+
/* @__PURE__ */ jsx(FormControl, {
|
|
155
|
+
sx: styles.formControl,
|
|
156
|
+
fullWidth: true,
|
|
157
|
+
children: /* @__PURE__ */ jsx(TextField, {
|
|
158
|
+
name: "password",
|
|
159
|
+
type: "password",
|
|
160
|
+
label: t("prometheusWidget.password"),
|
|
161
|
+
value: passwordInput,
|
|
162
|
+
onChange: handlePasswordChange,
|
|
163
|
+
onBlur: formProps.handleBlur,
|
|
164
|
+
"data-testid": "prometheus.settings.password",
|
|
165
|
+
fullWidth: true
|
|
166
|
+
})
|
|
167
|
+
}),
|
|
168
|
+
showInsecureWarning && /* @__PURE__ */ jsx(Alert, {
|
|
169
|
+
severity: "warning",
|
|
170
|
+
sx: styles.formControl,
|
|
171
|
+
"data-testid": "prometheus.settings.insecure-warning",
|
|
172
|
+
children: t("prometheusWidget.insecureWarning")
|
|
173
|
+
})
|
|
174
|
+
] });
|
|
175
|
+
};
|
|
176
|
+
//#endregion
|
|
81
177
|
//#region src/components/SettingsFormContent/index.tsx
|
|
178
|
+
const emptyQueryItem = {
|
|
179
|
+
query: "",
|
|
180
|
+
displayName: ""
|
|
181
|
+
};
|
|
82
182
|
const SettingsFormContent = ({ formProps }) => {
|
|
83
183
|
const [selectedTab, setSelectedTab] = useState("settings");
|
|
84
|
-
const emptyQueryItem = {
|
|
85
|
-
query: "",
|
|
86
|
-
displayName: ""
|
|
87
|
-
};
|
|
88
|
-
const formControlStyles = { mt: 2 };
|
|
89
184
|
const { t } = useTranslation();
|
|
90
185
|
const setPrometheusQuery = (i, item) => {
|
|
91
186
|
const queries = [...formProps.values.prometheusQueries || [emptyQueryItem]];
|
|
@@ -120,7 +215,7 @@ const SettingsFormContent = ({ formProps }) => {
|
|
|
120
215
|
};
|
|
121
216
|
const mapPeriodToLabel = (period) => {
|
|
122
217
|
switch (period) {
|
|
123
|
-
case
|
|
218
|
+
case "PREVIOUS_SHIFT": return t("prometheusWidget.previousShift");
|
|
124
219
|
default: return t("prometheusWidget.currentShift");
|
|
125
220
|
}
|
|
126
221
|
};
|
|
@@ -144,7 +239,7 @@ const SettingsFormContent = ({ formProps }) => {
|
|
|
144
239
|
mb: 2,
|
|
145
240
|
children: [
|
|
146
241
|
/* @__PURE__ */ jsx(FormControl, {
|
|
147
|
-
sx:
|
|
242
|
+
sx: styles.formControl,
|
|
148
243
|
fullWidth: true,
|
|
149
244
|
children: /* @__PURE__ */ jsx(TextField, {
|
|
150
245
|
name: "endpointUrl",
|
|
@@ -158,8 +253,17 @@ const SettingsFormContent = ({ formProps }) => {
|
|
|
158
253
|
fullWidth: true
|
|
159
254
|
})
|
|
160
255
|
}),
|
|
256
|
+
/* @__PURE__ */ jsx(Divider, {
|
|
257
|
+
sx: styles.sectionDivider,
|
|
258
|
+
children: t("prometheusWidget.sectionAuthorization")
|
|
259
|
+
}),
|
|
260
|
+
/* @__PURE__ */ jsx(CredentialsFields, { formProps }),
|
|
261
|
+
/* @__PURE__ */ jsx(Divider, {
|
|
262
|
+
sx: styles.sectionDivider,
|
|
263
|
+
children: t("prometheusWidget.sectionData")
|
|
264
|
+
}),
|
|
161
265
|
/* @__PURE__ */ jsxs(FormControl, {
|
|
162
|
-
sx:
|
|
266
|
+
sx: styles.formControl,
|
|
163
267
|
fullWidth: true,
|
|
164
268
|
children: [
|
|
165
269
|
/* @__PURE__ */ jsx(InputLabel, {
|
|
@@ -170,16 +274,16 @@ const SettingsFormContent = ({ formProps }) => {
|
|
|
170
274
|
variant: "outlined",
|
|
171
275
|
name: "queriesPeriod",
|
|
172
276
|
labelId: "queries-period-label",
|
|
173
|
-
value: formProps.values.queriesPeriod ||
|
|
277
|
+
value: formProps.values.queriesPeriod || "CURRENT_SHIFT",
|
|
174
278
|
onChange: formProps.handleChange,
|
|
175
279
|
onBlur: formProps.handleBlur,
|
|
176
280
|
error: formProps.touched.queriesPeriod && Boolean(formProps.errors.queriesPeriod),
|
|
177
281
|
"data-testid": "prometheus.settings.period-select",
|
|
178
282
|
fullWidth: true,
|
|
179
|
-
children: Object.
|
|
180
|
-
value
|
|
181
|
-
children: mapPeriodToLabel(
|
|
182
|
-
},
|
|
283
|
+
children: Object.values(QueriesPeriod).map((value) => /* @__PURE__ */ jsx(MenuItem, {
|
|
284
|
+
value,
|
|
285
|
+
children: mapPeriodToLabel(value)
|
|
286
|
+
}, value))
|
|
183
287
|
}),
|
|
184
288
|
/* @__PURE__ */ jsx(FormHelperText, {
|
|
185
289
|
error: true,
|
|
@@ -188,7 +292,7 @@ const SettingsFormContent = ({ formProps }) => {
|
|
|
188
292
|
]
|
|
189
293
|
}),
|
|
190
294
|
(formProps.values.prometheusQueries || [emptyQueryItem]).map(({ query, displayName }, i) => /* @__PURE__ */ jsx(FormControl, {
|
|
191
|
-
sx:
|
|
295
|
+
sx: styles.formControl,
|
|
192
296
|
fullWidth: true,
|
|
193
297
|
children: /* @__PURE__ */ jsxs(Stack, {
|
|
194
298
|
direction: "row",
|
|
@@ -220,6 +324,7 @@ const SettingsFormContent = ({ formProps }) => {
|
|
|
220
324
|
}),
|
|
221
325
|
/* @__PURE__ */ jsx(IconButton, {
|
|
222
326
|
color: "error",
|
|
327
|
+
"aria-label": t("prometheusWidget.removeQuery"),
|
|
223
328
|
onClick: () => removeQueryField(i),
|
|
224
329
|
"data-testid": `prometheus.settings.remove-query-${i}`,
|
|
225
330
|
children: /* @__PURE__ */ jsx(Clear, {})
|
|
@@ -230,13 +335,13 @@ const SettingsFormContent = ({ formProps }) => {
|
|
|
230
335
|
/* @__PURE__ */ jsx(Button, {
|
|
231
336
|
color: "secondary",
|
|
232
337
|
onClick: addQueryField,
|
|
233
|
-
sx:
|
|
338
|
+
sx: styles.addButton,
|
|
234
339
|
"data-testid": "prometheus.settings.add-query",
|
|
235
340
|
fullWidth: true,
|
|
236
341
|
children: t("prometheusWidget.addAnotherQuery")
|
|
237
342
|
}),
|
|
238
343
|
(formProps.values.displayedQueryParams || [""]).map((param, i) => /* @__PURE__ */ jsx(FormControl, {
|
|
239
|
-
sx:
|
|
344
|
+
sx: styles.formControl,
|
|
240
345
|
fullWidth: true,
|
|
241
346
|
children: /* @__PURE__ */ jsxs(Stack, {
|
|
242
347
|
direction: "row",
|
|
@@ -245,12 +350,13 @@ const SettingsFormContent = ({ formProps }) => {
|
|
|
245
350
|
label: t("prometheusWidget.displayedQueryParameter"),
|
|
246
351
|
value: param,
|
|
247
352
|
onChange: (e) => setDisplayedQueryParam(i, e.target.value),
|
|
248
|
-
error: formProps.touched.displayedQueryParams
|
|
249
|
-
helperText: formProps.touched.displayedQueryParams
|
|
353
|
+
error: Boolean(Array.isArray(formProps.touched.displayedQueryParams) && formProps.touched.displayedQueryParams[i] && getIn(formProps.errors, `displayedQueryParams.[${i}]`)),
|
|
354
|
+
helperText: Array.isArray(formProps.touched.displayedQueryParams) && formProps.touched.displayedQueryParams[i] ? getIn(formProps.errors, `displayedQueryParams.[${i}]`) : void 0,
|
|
250
355
|
"data-testid": `prometheus.settings.param-input-${i}`,
|
|
251
356
|
fullWidth: true
|
|
252
357
|
}), /* @__PURE__ */ jsx(IconButton, {
|
|
253
358
|
color: "error",
|
|
359
|
+
"aria-label": t("prometheusWidget.removeParam"),
|
|
254
360
|
onClick: () => removeDisplayedQueryParam(i),
|
|
255
361
|
"data-testid": `prometheus.settings.remove-param-${i}`,
|
|
256
362
|
children: /* @__PURE__ */ jsx(Clear, {})
|
|
@@ -260,13 +366,13 @@ const SettingsFormContent = ({ formProps }) => {
|
|
|
260
366
|
/* @__PURE__ */ jsx(Button, {
|
|
261
367
|
color: "secondary",
|
|
262
368
|
onClick: addDisplayedQueryParam,
|
|
263
|
-
sx:
|
|
369
|
+
sx: styles.addButton,
|
|
264
370
|
"data-testid": "prometheus.settings.add-param",
|
|
265
371
|
fullWidth: true,
|
|
266
372
|
children: t("prometheusWidget.addAnotherDisplayedQueryParameter")
|
|
267
373
|
}),
|
|
268
374
|
/* @__PURE__ */ jsx(FormControl, {
|
|
269
|
-
sx:
|
|
375
|
+
sx: styles.formControl,
|
|
270
376
|
fullWidth: true,
|
|
271
377
|
children: /* @__PURE__ */ jsx(TextField, {
|
|
272
378
|
name: "xAxisUnit",
|
|
@@ -281,7 +387,7 @@ const SettingsFormContent = ({ formProps }) => {
|
|
|
281
387
|
})
|
|
282
388
|
}),
|
|
283
389
|
/* @__PURE__ */ jsx(FormControl, {
|
|
284
|
-
sx:
|
|
390
|
+
sx: styles.formControl,
|
|
285
391
|
fullWidth: true,
|
|
286
392
|
children: /* @__PURE__ */ jsx(TextField, {
|
|
287
393
|
name: "yAxisUnit",
|
|
@@ -314,13 +420,21 @@ const SettingsFormContent = ({ formProps }) => {
|
|
|
314
420
|
};
|
|
315
421
|
//#endregion
|
|
316
422
|
//#region src/helpers.ts
|
|
423
|
+
const classifyFetchError = (err) => {
|
|
424
|
+
const e = err;
|
|
425
|
+
const status = e?.httpStatus ?? e?.response?.status;
|
|
426
|
+
if (status === 401) return "auth";
|
|
427
|
+
if (status === 403) return "forbidden";
|
|
428
|
+
return "unreachable";
|
|
429
|
+
};
|
|
430
|
+
const pickKeys = (obj, keys) => Object.fromEntries(keys.filter((k) => k in obj).map((k) => [k, obj[k]]));
|
|
317
431
|
const getQueriesTimeRange = (period, data) => {
|
|
318
432
|
const currentDate = dayjs();
|
|
319
433
|
const normalizedShifts = normalizeShifts(data?.shifts, currentDate);
|
|
320
434
|
const currentShift = getCurrentShift(currentDate, normalizedShifts);
|
|
321
435
|
const recentShift = getRecentShift(currentDate, normalizedShifts);
|
|
322
436
|
switch (period) {
|
|
323
|
-
case
|
|
437
|
+
case "CURRENT_SHIFT":
|
|
324
438
|
if (currentShift) return {
|
|
325
439
|
startedAt: currentShift.startedAt.toDate(),
|
|
326
440
|
finishedAt: currentShift.finishedAt.toDate()
|
|
@@ -330,7 +444,7 @@ const getQueriesTimeRange = (period, data) => {
|
|
|
330
444
|
finishedAt: recentShift.finishedAt.toDate()
|
|
331
445
|
};
|
|
332
446
|
return null;
|
|
333
|
-
case
|
|
447
|
+
case "PREVIOUS_SHIFT":
|
|
334
448
|
if (recentShift) return {
|
|
335
449
|
startedAt: recentShift.startedAt.toDate(),
|
|
336
450
|
finishedAt: recentShift.finishedAt.toDate()
|
|
@@ -340,6 +454,21 @@ const getQueriesTimeRange = (period, data) => {
|
|
|
340
454
|
}
|
|
341
455
|
};
|
|
342
456
|
//#endregion
|
|
457
|
+
//#region src/components/PrometheusChart/constants.ts
|
|
458
|
+
const COLORS = [
|
|
459
|
+
"#36A2EB",
|
|
460
|
+
"#FF6384",
|
|
461
|
+
"#4BC0C0",
|
|
462
|
+
"#FF9F40",
|
|
463
|
+
"#9966FF",
|
|
464
|
+
"#FFCD56",
|
|
465
|
+
"#C9CBCF",
|
|
466
|
+
"#7BC8A4",
|
|
467
|
+
"#E7E9ED",
|
|
468
|
+
"#FF6B6B"
|
|
469
|
+
];
|
|
470
|
+
const DEFAULT_FONT_COLOR = "rgba(255, 255, 255, 0.75)";
|
|
471
|
+
//#endregion
|
|
343
472
|
//#region src/components/PrometheusChart/GradientPlugin.ts
|
|
344
473
|
const createGradient = (ctx, area) => {
|
|
345
474
|
return ctx.createLinearGradient(0, area.bottom, 0, area.top);
|
|
@@ -367,31 +496,49 @@ const GradientPlugin = {
|
|
|
367
496
|
//#region src/components/PrometheusChart/index.tsx
|
|
368
497
|
Chart.register(CategoryScale, LinearScale, TimeScale, PointElement, LineElement, Filler, Legend, Tooltip);
|
|
369
498
|
Chart.defaults.font.size = 12;
|
|
370
|
-
Chart.defaults.color =
|
|
371
|
-
const
|
|
372
|
-
"
|
|
373
|
-
"
|
|
374
|
-
"
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
"
|
|
378
|
-
"
|
|
379
|
-
"
|
|
380
|
-
"
|
|
381
|
-
"
|
|
382
|
-
|
|
499
|
+
Chart.defaults.color = DEFAULT_FONT_COLOR;
|
|
500
|
+
const errorTranslationKey = {
|
|
501
|
+
auth: "prometheusWidget.errorAuth",
|
|
502
|
+
forbidden: "prometheusWidget.errorForbidden",
|
|
503
|
+
unreachable: "prometheusWidget.errorUnreachable"
|
|
504
|
+
};
|
|
505
|
+
const errorMessageStyles = {
|
|
506
|
+
width: "100%",
|
|
507
|
+
height: "100%",
|
|
508
|
+
display: "flex",
|
|
509
|
+
alignItems: "center",
|
|
510
|
+
justifyContent: "center",
|
|
511
|
+
textAlign: "center",
|
|
512
|
+
padding: 2
|
|
513
|
+
};
|
|
383
514
|
const PrometheusChart = ({ data, settings }) => {
|
|
384
515
|
const chart = useRef(null);
|
|
516
|
+
const hiddenSeriesRef = useRef({});
|
|
517
|
+
const fetchGenRef = useRef(0);
|
|
385
518
|
const [chartData, setChartData] = useState({
|
|
386
519
|
labels: [],
|
|
387
520
|
datasets: []
|
|
388
521
|
});
|
|
389
522
|
const [queriesTimeRange, setQueriesTimeRange] = useState(null);
|
|
390
523
|
const [timeLabels, setTimeLabels] = useState([]);
|
|
391
|
-
const
|
|
524
|
+
const [error, setError] = useState(null);
|
|
525
|
+
const driver = useMemo(() => {
|
|
526
|
+
const options = { endpoint: settings.endpointUrl };
|
|
527
|
+
if (settings.username && settings.password) options.auth = {
|
|
528
|
+
username: settings.username,
|
|
529
|
+
password: settings.password
|
|
530
|
+
};
|
|
531
|
+
return new PrometheusDriver(options);
|
|
532
|
+
}, [
|
|
533
|
+
settings.endpointUrl,
|
|
534
|
+
settings.username,
|
|
535
|
+
settings.password
|
|
536
|
+
]);
|
|
537
|
+
const { t } = useTranslation();
|
|
392
538
|
const fetchData = useCallback(async (timeRange) => {
|
|
393
539
|
if (!settings.endpointUrl || !settings.prometheusQueries?.length) return;
|
|
394
|
-
|
|
540
|
+
fetchGenRef.current += 1;
|
|
541
|
+
const gen = fetchGenRef.current;
|
|
395
542
|
const start = new Date(timeRange.startedAt);
|
|
396
543
|
const end = timeRange.finishedAt ? new Date(timeRange.finishedAt) : /* @__PURE__ */ new Date();
|
|
397
544
|
const step = 30;
|
|
@@ -399,39 +546,51 @@ const PrometheusChart = ({ data, settings }) => {
|
|
|
399
546
|
const ds = chart.current.data.datasets[i];
|
|
400
547
|
if (ds.label) hiddenSeriesRef.current[ds.label] = !chart.current.isDatasetVisible(i);
|
|
401
548
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
549
|
+
try {
|
|
550
|
+
const queries = settings.prometheusQueries.map(({ query }) => query);
|
|
551
|
+
const results = await Promise.all(queries.map((query) => driver.rangeQuery(query, start, end, step)));
|
|
552
|
+
if (gen !== fetchGenRef.current) return;
|
|
553
|
+
let seriesIndex = 0;
|
|
554
|
+
setChartData({
|
|
555
|
+
labels: [],
|
|
556
|
+
datasets: results.flatMap((result, queryIndex) => result.result.map((serie) => {
|
|
557
|
+
const idx = seriesIndex++;
|
|
558
|
+
const queryConfig = settings.prometheusQueries[queryIndex];
|
|
559
|
+
const metricLabels = serie.metric.labels || {};
|
|
560
|
+
const filteredValues = Object.values(pickKeys(metricLabels, settings.displayedQueryParams)).join(" - ");
|
|
561
|
+
let label;
|
|
562
|
+
if (queryConfig?.displayName) label = filteredValues ? `${queryConfig.displayName} - ${filteredValues}` : queryConfig.displayName;
|
|
563
|
+
else {
|
|
564
|
+
const metricName = serie.metric.name || queryConfig?.query || "";
|
|
565
|
+
label = filteredValues ? `${metricName} ${JSON.stringify(pickKeys(metricLabels, settings.displayedQueryParams))}` : metricName;
|
|
566
|
+
}
|
|
567
|
+
return {
|
|
568
|
+
label,
|
|
569
|
+
data: serie.values.map((v) => ({
|
|
570
|
+
x: v.time,
|
|
571
|
+
y: v.value
|
|
572
|
+
})),
|
|
573
|
+
fill: true,
|
|
574
|
+
tension: .4,
|
|
575
|
+
borderColor: COLORS[idx % COLORS.length],
|
|
576
|
+
backgroundColor: COLORS[idx % COLORS.length],
|
|
577
|
+
borderWidth: 3,
|
|
578
|
+
pointRadius: 0,
|
|
579
|
+
hidden: hiddenSeriesRef.current[label] || false
|
|
580
|
+
};
|
|
581
|
+
}))
|
|
582
|
+
});
|
|
583
|
+
setError(null);
|
|
584
|
+
} catch (err) {
|
|
585
|
+
if (gen !== fetchGenRef.current) return;
|
|
586
|
+
setError(classifyFetchError(err));
|
|
587
|
+
}
|
|
588
|
+
}, [
|
|
589
|
+
settings.endpointUrl,
|
|
590
|
+
settings.prometheusQueries,
|
|
591
|
+
settings.displayedQueryParams,
|
|
592
|
+
driver
|
|
593
|
+
]);
|
|
435
594
|
useEffect(() => {
|
|
436
595
|
if (queriesTimeRange) {
|
|
437
596
|
setTimeLabels(generateTimeRange(dayjs(queriesTimeRange.startedAt), dayjs(queriesTimeRange.finishedAt), "minutes", 15).map((d) => d.toDate()));
|
|
@@ -440,7 +599,7 @@ const PrometheusChart = ({ data, settings }) => {
|
|
|
440
599
|
}, [queriesTimeRange, fetchData]);
|
|
441
600
|
useEffect(() => {
|
|
442
601
|
setQueriesTimeRange(getQueriesTimeRange(settings.queriesPeriod, data));
|
|
443
|
-
if (settings?.queriesPeriod ===
|
|
602
|
+
if (settings?.queriesPeriod === "CURRENT_SHIFT") {
|
|
444
603
|
const intervalId = setInterval(() => {
|
|
445
604
|
setQueriesTimeRange(getQueriesTimeRange(settings.queriesPeriod, data));
|
|
446
605
|
}, 3e4);
|
|
@@ -450,6 +609,15 @@ const PrometheusChart = ({ data, settings }) => {
|
|
|
450
609
|
}
|
|
451
610
|
return () => {};
|
|
452
611
|
}, [data, settings]);
|
|
612
|
+
if (error) return /* @__PURE__ */ jsx(Box, {
|
|
613
|
+
sx: errorMessageStyles,
|
|
614
|
+
"data-testid": `prometheus-widget.error.${error}`,
|
|
615
|
+
children: /* @__PURE__ */ jsx(Typography, {
|
|
616
|
+
variant: "body2",
|
|
617
|
+
color: "text.primary",
|
|
618
|
+
children: t(errorTranslationKey[error])
|
|
619
|
+
})
|
|
620
|
+
});
|
|
453
621
|
return queriesTimeRange && /* @__PURE__ */ jsx(Line, {
|
|
454
622
|
ref: chart,
|
|
455
623
|
data: chartData,
|
|
@@ -505,13 +673,16 @@ const WidgetView = ({ data, settings }) => {
|
|
|
505
673
|
};
|
|
506
674
|
//#endregion
|
|
507
675
|
//#region src/components/Widget/utils.ts
|
|
676
|
+
const isLegacyQuery = (query) => typeof query === "string";
|
|
508
677
|
const getSettingsFormProps = (t) => {
|
|
509
678
|
yup.setLocale({ mixed: { required: t("prometheusWidget.thisFieldIsRequired") } });
|
|
510
679
|
return {
|
|
511
680
|
initialValues: {
|
|
512
681
|
customTitle: "",
|
|
513
682
|
endpointUrl: "",
|
|
514
|
-
|
|
683
|
+
username: "",
|
|
684
|
+
password: "",
|
|
685
|
+
queriesPeriod: "CURRENT_SHIFT",
|
|
515
686
|
prometheusQueries: [],
|
|
516
687
|
displayedQueryParams: [],
|
|
517
688
|
xAxisUnit: "",
|
|
@@ -519,6 +690,8 @@ const getSettingsFormProps = (t) => {
|
|
|
519
690
|
},
|
|
520
691
|
validationSchema: yup.object({
|
|
521
692
|
endpointUrl: yup.string().required(),
|
|
693
|
+
username: yup.string(),
|
|
694
|
+
password: yup.string(),
|
|
522
695
|
queriesPeriod: yup.string().required(),
|
|
523
696
|
prometheusQueries: yup.array().of(yup.object().shape({
|
|
524
697
|
query: yup.string().required(),
|
|
@@ -527,22 +700,26 @@ const getSettingsFormProps = (t) => {
|
|
|
527
700
|
displayedQueryParams: yup.array().of(yup.string().required()),
|
|
528
701
|
xAxisUnit: yup.string().required(),
|
|
529
702
|
yAxisUnit: yup.string().required()
|
|
530
|
-
})
|
|
703
|
+
}),
|
|
704
|
+
onSubmit: () => {}
|
|
531
705
|
};
|
|
532
706
|
};
|
|
533
707
|
const migrateSettings = (settings) => {
|
|
534
|
-
if (!satisfies(settings.version || "1.0.0", ">=1.2.5"))
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
708
|
+
if (!satisfies(settings.version || "1.0.0", ">=1.2.5")) {
|
|
709
|
+
const queries = settings.prometheusQueries;
|
|
710
|
+
return {
|
|
711
|
+
...settings,
|
|
712
|
+
prometheusQueries: queries.map((query) => isLegacyQuery(query) ? {
|
|
713
|
+
query,
|
|
714
|
+
displayName: ""
|
|
715
|
+
} : query)
|
|
716
|
+
};
|
|
717
|
+
}
|
|
541
718
|
return settings;
|
|
542
719
|
};
|
|
543
720
|
//#endregion
|
|
544
721
|
//#region src/components/Widget/index.tsx
|
|
545
|
-
const Widget = ({ url, wsUrl, lang, data, ...widgetProps }) => {
|
|
722
|
+
const Widget = ({ url, wsUrl, lang, data, sidePanelOpened = false, updateSidePanelProps = () => {}, ...widgetProps }) => {
|
|
546
723
|
const { graphqlSdk, gqlWsClient } = useGqlClients({
|
|
547
724
|
url,
|
|
548
725
|
wsUrl,
|
|
@@ -557,10 +734,11 @@ const Widget = ({ url, wsUrl, lang, data, ...widgetProps }) => {
|
|
|
557
734
|
}, [data, graphqlSdk]);
|
|
558
735
|
return /* @__PURE__ */ jsx(BaseWidget, {
|
|
559
736
|
...widgetProps,
|
|
560
|
-
url,
|
|
561
737
|
lang,
|
|
562
738
|
locales: resources,
|
|
563
739
|
data: widgetData,
|
|
740
|
+
sidePanelOpened,
|
|
741
|
+
updateSidePanelProps,
|
|
564
742
|
gqlClients: {
|
|
565
743
|
graphqlSdk,
|
|
566
744
|
gqlWsClient
|
|
@@ -591,10 +769,9 @@ const getTitle = (_data, settings, _filters, lang) => {
|
|
|
591
769
|
//#endregion
|
|
592
770
|
//#region src/index.tsx
|
|
593
771
|
registerTranslations(resources);
|
|
594
|
-
const thumbnail = void 0;
|
|
595
772
|
const requiredFeatures = ["feature.prometheus-widget"];
|
|
596
773
|
const extraPermissions = [];
|
|
597
774
|
//#endregion
|
|
598
|
-
export { Widget, extraPermissions, getDisplayName, getTitle, requiredFeatures, thumbnail, LIBRARY_VERSION as version };
|
|
775
|
+
export { Widget, extraPermissions, getDisplayName, getTitle, requiredFeatures, thumbnail_default as thumbnail, LIBRARY_VERSION as version };
|
|
599
776
|
|
|
600
777
|
//# sourceMappingURL=index.js.map
|