Skip to content

Commit 71e2bb7

Browse files
committed
[ENHANCEMENT/BREAKINGCHANGE] timneserieschart: add query name support for query settings
Signed-off-by: Guillaume LADORME <Gladorme@users.noreply.github.com>
1 parent 2f19a36 commit 71e2bb7

9 files changed

Lines changed: 67 additions & 60 deletions

File tree

timeserieschart/schemas/migrate/migrate.cue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ spec: {
192192
// migrate fixedColor overrides to querySettings when applicable
193193
#querySettings: [
194194
for i, target in (*#panel.targets | []) {
195-
queryIndex: i
195+
queryName: "Query #\(i)"
196196
for override in (*#panel.fieldConfig.overrides | [])
197197
if (override.matcher.id == "byName" || override.matcher.id == "byRegexp" || override.matcher.id == "byFrameRefID") && override.matcher.options != _|_
198198
for property in override.properties

timeserieschart/schemas/migrate/tests/color-based-on-legend-text/expected.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,28 @@
77
},
88
"querySettings": [
99
{
10-
"queryIndex": 0,
10+
"queryName": "Query #1",
1111
"colorMode": "fixed",
1212
"colorValue": "#EAB839"
1313
},
1414
{
15-
"queryIndex": 1,
15+
"queryName": "Query #2",
1616
"colorMode": "fixed",
1717
"colorValue": "#0A437C"
1818
},
1919
{
20-
"queryIndex": 2,
20+
"queryName": "Query #3",
2121
"colorMode": "fixed",
2222
"colorValue": "#890F02",
2323
"areaOpacity": 1
2424
},
2525
{
26-
"queryIndex": 4,
26+
"queryName": "Query #4",
2727
"colorMode": "fixed",
2828
"colorValue": "#6D1F62"
2929
},
3030
{
31-
"queryIndex": 5,
31+
"queryName": "Query #5",
3232
"colorMode": "fixed",
3333
"colorValue": "#052B51"
3434
}
@@ -47,4 +47,4 @@
4747
"min": 0
4848
}
4949
}
50-
}
50+
}

timeserieschart/schemas/migrate/tests/multiple-overrides/expected.json

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@
44
"legend": {
55
"position": "right",
66
"mode": "table",
7-
"values": [
8-
"min",
9-
"max",
10-
"mean"
11-
]
7+
"values": ["min", "max", "mean"]
128
},
139
"yAxis": {
1410
"format": {
@@ -25,25 +21,25 @@
2521
},
2622
"querySettings": [
2723
{
28-
"queryIndex": 1,
24+
"queryName": "Query #1",
2925
"colorMode": "fixed",
3026
"colorValue": "#5794F2",
3127
"lineStyle": "dashed",
3228
"areaOpacity": 0
3329
},
3430
{
35-
"queryIndex": 2,
31+
"queryName": "Query #2",
3632
"colorMode": "fixed",
3733
"colorValue": "#F2495C",
3834
"areaOpacity": 0
3935
},
4036
{
41-
"queryIndex": 3,
37+
"queryName": "Query #3",
4238
"colorMode": "fixed",
4339
"colorValue": "#3274D9"
4440
},
4541
{
46-
"queryIndex": 4,
42+
"queryName": "Query #4",
4743
"colorMode": "fixed",
4844
"colorValue": "#fade2a",
4945
"lineStyle": "dashed",

timeserieschart/schemas/time-series.cue

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
package model
1515

1616
import (
17+
"strings"
18+
1719
"github.com/perses/shared/cue/common"
1820
)
1921

@@ -60,12 +62,12 @@ spec: close({
6062
}
6163

6264
#querySettings: [...{
63-
queryIndex: int & >=0
64-
colorMode?: "fixed" | "fixed-single" // NB: "palette" could be added later
65-
colorValue?: =~"^#(?:[0-9a-fA-F]{3}){1,2}$" // hexadecimal color code
66-
lineStyle?: #lineStyle
67-
areaOpacity?: #areaOpacity
68-
format?: common.#format
65+
queryName: strings.MinRunes(1)
66+
colorMode?: "fixed" | "fixed-single" // NB: "palette" could be added later
67+
colorValue?: =~"^#(?:[0-9a-fA-F]{3}){1,2}$" // hexadecimal color code
68+
lineStyle?: #lineStyle
69+
areaOpacity?: #areaOpacity
70+
format?: common.#format
6971
}]
7072

7173
#lineStyle: "solid" | "dashed" | "dotted"

timeserieschart/sdk/go/time-series.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ const (
121121
)
122122

123123
type QuerySettingsItem struct {
124-
QueryIndex uint `json:"queryIndex" yaml:"queryIndex"`
124+
QueryName string `json:"queryName" yaml:"queryName"`
125125
ColorMode ColorMode `json:"colorMode,omitempty" yaml:"colorMode,omitempty"`
126126
ColorValue string `json:"colorValue,omitempty" yaml:"colorValue,omitempty"`
127127
LineStyle string `json:"lineStyle,omitempty" yaml:"lineStyle,omitempty"`

timeserieschart/src/QuerySettingsEditor.tsx

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,7 @@ import DeleteIcon from 'mdi-material-ui/DeleteOutline';
3131
import AddIcon from 'mdi-material-ui/Plus';
3232
import CloseIcon from 'mdi-material-ui/Close';
3333
import { produce } from 'immer';
34-
import { useDataQueriesContext } from '@perses-dev/plugin-system';
35-
import { QueryDefinition } from '@perses-dev/spec';
34+
import { generateQueryNames, useDataQueriesContext } from '@perses-dev/plugin-system';
3635
import {
3736
DEFAULT_AREA_OPACITY,
3837
LINE_STYLE_CONFIG,
@@ -65,13 +64,13 @@ export function QuerySettingsEditor(props: TimeSeriesChartOptionsEditorProps): R
6564
focusRef.current = false;
6665
}, [querySettingsList?.length]);
6766

68-
const handleQueryIndexChange = (e: React.ChangeEvent<HTMLInputElement>, i: number): void => {
67+
const handleQueryNameChange = (e: React.ChangeEvent<HTMLInputElement>, i: number): void => {
6968
if (querySettingsList !== undefined) {
7069
handleQuerySettingsChange(
7170
produce(querySettingsList, (draft) => {
7271
const querySettings = draft?.[i];
7372
if (querySettings) {
74-
querySettings.queryIndex = e.target.value;
73+
querySettings.queryName = e.target.value;
7574
}
7675
})
7776
);
@@ -226,26 +225,23 @@ export function QuerySettingsEditor(props: TimeSeriesChartOptionsEditorProps): R
226225

227226
const { queryDefinitions } = useDataQueriesContext();
228227

229-
const queryNames: string[] = useMemo(
230-
() => queryDefinitions.map((queryDef: QueryDefinition, index: number) => queryDef.spec.name ?? `#${index}`),
231-
[queryDefinitions]
232-
);
228+
const queryNames: string[] = useMemo(() => generateQueryNames(queryDefinitions), [queryDefinitions]);
233229

234230
// Compute the list of query indexes for which query settings are not already defined.
235231
// This is to avoid already-booked indexes to still be selectable in the dropdown(s)
236-
const availableQueryIndexes = useMemo(() => {
232+
const availableQueryNames = useMemo(() => {
237233
return queryNames.filter((name) => {
238-
return !querySettingsList?.some((qs) => qs.queryIndex === name);
234+
return !querySettingsList?.some((qs) => qs.queryName === name);
239235
});
240236
}, [queryNames, querySettingsList]);
241237

242238
// TODO; hide add button if no more query index is available
243-
const firstAvailableQueryIndex = useMemo(() => {
244-
return availableQueryIndexes[0] ?? NO_INDEX_AVAILABLE;
245-
}, [availableQueryIndexes]);
239+
const firstAvailableQueryName = useMemo(() => {
240+
return availableQueryNames[0] ?? NO_INDEX_AVAILABLE;
241+
}, [availableQueryNames]);
246242

247243
const defaultQuerySettings: QuerySettingsOptions = {
248-
queryIndex: firstAvailableQueryIndex,
244+
queryName: firstAvailableQueryName,
249245
};
250246

251247
const addQuerySettingsInput = (): void => {
@@ -273,9 +269,9 @@ export function QuerySettingsEditor(props: TimeSeriesChartOptionsEditorProps): R
273269
inputRef={i === querySettingsList.length - 1 ? recentlyAddedInputRef : undefined}
274270
key={i}
275271
querySettings={querySettings}
276-
availableQueryIndexes={availableQueryIndexes}
277-
onQueryIndexChange={(e) => {
278-
handleQueryIndexChange(e, i);
272+
availableQueryNames={availableQueryNames}
273+
onQueryNameChange={(e) => {
274+
handleQueryNameChange(e, i);
279275
}}
280276
onColorModeChange={(e) => handleColorModeChange(e, i)}
281277
onColorValueChange={(color) => handleColorValueChange(color, i)}
@@ -296,7 +292,7 @@ export function QuerySettingsEditor(props: TimeSeriesChartOptionsEditorProps): R
296292
/>
297293
))
298294
)}
299-
{queryDefinitions.length > 0 && firstAvailableQueryIndex !== NO_INDEX_AVAILABLE && (
295+
{queryDefinitions.length > 0 && firstAvailableQueryName !== NO_INDEX_AVAILABLE && (
300296
<Button variant="contained" startIcon={<AddIcon />} sx={{ marginTop: 1 }} onClick={addQuerySettingsInput}>
301297
Add Query Settings
302298
</Button>
@@ -307,8 +303,8 @@ export function QuerySettingsEditor(props: TimeSeriesChartOptionsEditorProps): R
307303

308304
interface QuerySettingsInputProps {
309305
querySettings: QuerySettingsOptions;
310-
availableQueryIndexes: string[];
311-
onQueryIndexChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
306+
availableQueryNames: string[];
307+
onQueryNameChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
312308
onColorModeChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
313309
onColorValueChange: (colorValue: string) => void;
314310
onLineStyleChange: (lineStyle: string) => void;
@@ -328,9 +324,9 @@ interface QuerySettingsInputProps {
328324
}
329325

330326
function QuerySettingsInput({
331-
querySettings: { queryIndex, colorMode, colorValue, lineStyle, areaOpacity, format },
332-
availableQueryIndexes,
333-
onQueryIndexChange,
327+
querySettings: { queryName, colorMode, colorValue, lineStyle, areaOpacity, format },
328+
availableQueryNames,
329+
onQueryNameChange,
334330
onColorModeChange,
335331
onColorValueChange,
336332
onLineStyleChange,
@@ -348,7 +344,7 @@ function QuerySettingsInput({
348344
onFormatChange,
349345
}: QuerySettingsInputProps): ReactElement {
350346
// current query index should also be selectable
351-
const selectableQueryIndexes = availableQueryIndexes.sort((a, b) => a.localeCompare(b));
347+
const selectableQueryName = availableQueryNames.sort((a, b) => a.localeCompare(b));
352348

353349
// State for dropdown menu
354350
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
@@ -399,13 +395,13 @@ function QuerySettingsInput({
399395
<TextField
400396
select
401397
inputRef={inputRef}
402-
value={queryIndex}
398+
value={queryName}
403399
label="Query"
404-
onChange={onQueryIndexChange}
400+
onChange={onQueryNameChange}
405401
sx={{ minWidth: '75px' }}
406402
>
407-
<MenuItem value={queryIndex}>{queryIndex}</MenuItem>
408-
{selectableQueryIndexes.map((qi) => (
403+
<MenuItem value={queryName}>{queryName}</MenuItem>
404+
{selectableQueryName.map((qi) => (
409405
<MenuItem key={`query-${qi}`} value={qi}>
410406
{qi}
411407
</MenuItem>
@@ -420,7 +416,7 @@ function QuerySettingsInput({
420416
<MenuItem value="fixed">Fixed</MenuItem>
421417
</TextField>
422418
<OptionsColorPicker
423-
label={`Query n°${queryIndex + 1}`}
419+
label={queryName}
424420
color={colorValue || DEFAULT_COLOR_VALUE}
425421
onColorChange={onColorValueChange}
426422
/>
@@ -512,7 +508,7 @@ function QuerySettingsInput({
512508
</Stack>
513509
{/* Delete Button for this query settings */}
514510
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
515-
<IconButton aria-label={`delete settings for query '${queryIndex}'`} onClick={onDelete}>
511+
<IconButton aria-label={`delete settings for query '${queryName}'`} onClick={onDelete}>
516512
<DeleteIcon />
517513
</IconButton>
518514
</Box>

timeserieschart/src/TimeSeriesChartPanel.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
useTimeRange,
2222
validateLegendSpec,
2323
legendValues,
24+
getQueryName,
2425
getCalculations,
2526
CalculationType,
2627
} from '@perses-dev/plugin-system';
@@ -163,6 +164,10 @@ export function TimeSeriesChartPanel(props: TimeSeriesChartProps): ReactElement
163164
[annotationsWithData]
164165
);
165166

167+
const queryDefinitions = useMemo(() => {
168+
return queryResults.map((queryResult) => queryResult.definition);
169+
}, [queryResults]);
170+
166171
// Populate series data based on query results
167172
const {
168173
timeScale,
@@ -199,12 +204,19 @@ export function TimeSeriesChartPanel(props: TimeSeriesChartProps): ReactElement
199204
// TODO: Look into performance optimizations and moving parts of mapping to the lower level chart
200205
for (let queryIndex = 0; queryIndex < queryResults.length; queryIndex++) {
201206
const result = queryResults[queryIndex];
207+
if (result === undefined) {
208+
console.warn(
209+
'Something went wrong with the query result mapping, result is undefined for query index',
210+
queryIndex
211+
);
212+
continue;
213+
}
202214

203215
// Retrieve querySettings for this query, if exists.
204216
// queries & querySettings indices do not necessarily match, so we have to check the tail value of the $ref attribute
205217
let querySettings: QuerySettingsOptions | undefined;
206218
for (const item of querySettingsList ?? []) {
207-
if (item.queryIndex === queryIndex) {
219+
if (item.queryName === getQueryName(queryDefinitions, result.definition)) {
208220
querySettings = item;
209221
// We don't break the loop here just in case there are multiple querySettings defined for the
210222
// same queryIndex, because in that case we want the last one to take precedence.
@@ -230,7 +242,7 @@ export function TimeSeriesChartPanel(props: TimeSeriesChartProps): ReactElement
230242
seriesName: formattedSeriesName,
231243
seriesIndex,
232244
querySettings: querySettings,
233-
queryHasMultipleResults: (queryResults[queryIndex]?.data?.series?.length ?? 0) > 1,
245+
queryHasMultipleResults: (result.data?.series?.length ?? 0) > 1,
234246
});
235247

236248
// We add a unique id for the chart to disambiguate items across charts

timeserieschart/src/time-series-chart-model.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export interface TimeSeriesChartOptions {
4040
}
4141

4242
export interface QuerySettingsOptions {
43-
queryIndex: string;
43+
queryName: string;
4444
colorMode?: 'fixed' | 'fixed-single';
4545
colorValue?: string;
4646
lineStyle?: LineStyleType;

timeserieschart/src/utils/palette-gen.test.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
// See the License for the specific language governing permissions and
1212
// limitations under the License.
1313

14+
import { defaultQueryName } from '@perses-dev/plugin-system';
1415
import { TimeSeriesChartVisualOptions } from '../time-series-chart-model';
1516
import { getSeriesColor, getAutoPaletteColor, getCategoricalPaletteColor, SeriesColorProps } from './palette-gen';
1617

@@ -119,7 +120,7 @@ describe('getSeriesColor', () => {
119120
seriesName: testSeriesName,
120121
seriesIndex: 0,
121122
querySettings: {
122-
queryIndex: 0,
123+
queryName: defaultQueryName(0),
123124
colorMode: 'fixed',
124125
colorValue: '#000',
125126
},
@@ -142,7 +143,7 @@ describe('getSeriesColor', () => {
142143
seriesName: testSeriesName,
143144
seriesIndex: 0,
144145
querySettings: {
145-
queryIndex: 0,
146+
queryName: defaultQueryName(0),
146147
colorMode: 'fixed',
147148
colorValue: '#000',
148149
},
@@ -165,7 +166,7 @@ describe('getSeriesColor', () => {
165166
seriesName: testSeriesName,
166167
seriesIndex: 0,
167168
querySettings: {
168-
queryIndex: 0,
169+
queryName: defaultQueryName(0),
169170
colorMode: 'fixed-single',
170171
colorValue: '#000',
171172
},
@@ -188,7 +189,7 @@ describe('getSeriesColor', () => {
188189
seriesName: testSeriesName,
189190
seriesIndex: 0,
190191
querySettings: {
191-
queryIndex: 0,
192+
queryName: defaultQueryName(0),
192193
colorMode: 'fixed-single',
193194
colorValue: '#000',
194195
},

0 commit comments

Comments
 (0)