@perses-dev/timeseries-chart-plugin 0.13.0-beta.3 → 0.13.0-rc.1

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.
Files changed (37) hide show
  1. package/__mf/js/TimeSeriesChart.1b9392b7.js +7 -0
  2. package/__mf/js/async/208.b9f374ad.js +7 -0
  3. package/__mf/js/async/{52.0850e52c.js → 52.0d78de2b.js} +1 -1
  4. package/__mf/js/async/546.c53e636c.js +3 -0
  5. package/__mf/js/async/694.0fb9ee5a.js +2 -0
  6. package/__mf/js/async/{984.5778f693.js → 984.3fc3c480.js} +3 -3
  7. package/__mf/js/async/__federation_expose_TimeSeriesChart.8b44fc75.js +1 -0
  8. package/__mf/js/{main.046b2715.js → main.dc72f3eb.js} +2 -2
  9. package/lib/QuerySettingsEditor.d.ts.map +1 -1
  10. package/lib/QuerySettingsEditor.js +81 -4
  11. package/lib/QuerySettingsEditor.js.map +1 -1
  12. package/lib/TimeSeriesChartPanel.d.ts.map +1 -1
  13. package/lib/TimeSeriesChartPanel.js +17 -3
  14. package/lib/TimeSeriesChartPanel.js.map +1 -1
  15. package/lib/VisualOptionsEditor.js.map +1 -1
  16. package/lib/cjs/QuerySettingsEditor.js +80 -3
  17. package/lib/cjs/TimeSeriesChartPanel.js +17 -3
  18. package/lib/cjs/utils/data-transform.js +9 -13
  19. package/lib/time-series-chart-model.d.ts +7 -0
  20. package/lib/time-series-chart-model.d.ts.map +1 -1
  21. package/lib/time-series-chart-model.js.map +1 -1
  22. package/lib/utils/data-transform.d.ts +1 -0
  23. package/lib/utils/data-transform.d.ts.map +1 -1
  24. package/lib/utils/data-transform.js +9 -13
  25. package/lib/utils/data-transform.js.map +1 -1
  26. package/mf-manifest.json +17 -17
  27. package/mf-stats.json +17 -17
  28. package/package.json +5 -5
  29. package/__mf/js/TimeSeriesChart.693fccf6.js +0 -7
  30. package/__mf/js/async/247.b8cba23e.js +0 -7
  31. package/__mf/js/async/555.a66f6ab5.js +0 -2
  32. package/__mf/js/async/570.bafa9150.js +0 -3
  33. package/__mf/js/async/__federation_expose_TimeSeriesChart.5f574fcb.js +0 -1
  34. /package/__mf/css/async/{247.85c2cbf6.css → 208.85c2cbf6.css} +0 -0
  35. /package/__mf/js/async/{247.b8cba23e.js.LICENSE.txt → 208.b9f374ad.js.LICENSE.txt} +0 -0
  36. /package/__mf/js/async/{555.a66f6ab5.js.LICENSE.txt → 694.0fb9ee5a.js.LICENSE.txt} +0 -0
  37. /package/__mf/js/async/{984.5778f693.js.LICENSE.txt → 984.3fc3c480.js.LICENSE.txt} +0 -0
@@ -11,7 +11,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
11
11
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
- import { Box, Button, IconButton, Menu, MenuItem, Slider, Stack, TextField, ToggleButton, ToggleButtonGroup, Typography, useTheme } from '@mui/material';
14
+ import { Box, Button, IconButton, Menu, MenuItem, Slider, Stack, Switch, TextField, ToggleButton, ToggleButtonGroup, Typography, useTheme } from '@mui/material';
15
15
  import { FormatControls, OptionsColorPicker } from '@perses-dev/components';
16
16
  import React, { useEffect, useMemo, useRef, useState } from 'react';
17
17
  import DeleteIcon from 'mdi-material-ui/DeleteOutline';
@@ -169,11 +169,36 @@ export function QuerySettingsEditor(props) {
169
169
  qs.format = undefined;
170
170
  });
171
171
  };
172
+ const addStack = (i)=>{
173
+ updateQuerySettings(i, (qs)=>{
174
+ qs.stack = false;
175
+ });
176
+ };
177
+ const removeStack = (i)=>{
178
+ updateQuerySettings(i, (qs)=>{
179
+ qs.stack = undefined;
180
+ });
181
+ };
182
+ const handleStackChange = (i, checked)=>{
183
+ updateQuerySettings(i, (qs)=>{
184
+ qs.stack = checked;
185
+ });
186
+ };
172
187
  const handleFormatChange = (i, format)=>{
173
188
  updateQuerySettings(i, (qs)=>{
174
189
  qs.format = format;
175
190
  });
176
191
  };
192
+ const addNegativeY = (i)=>{
193
+ updateQuerySettings(i, (qs)=>{
194
+ qs.negativeY = true;
195
+ });
196
+ };
197
+ const removeNegativeY = (i)=>{
198
+ updateQuerySettings(i, (qs)=>{
199
+ qs.negativeY = undefined;
200
+ });
201
+ };
177
202
  const { queryDefinitions } = useDataQueriesContext();
178
203
  const queryCount = queryDefinitions.length;
179
204
  const queryNames = useMemo(()=>generateQueryNames(queryDefinitions), [
@@ -240,7 +265,12 @@ export function QuerySettingsEditor(props) {
240
265
  onRemoveAreaOpacity: ()=>removeAreaOpacity(i),
241
266
  onAddFormat: ()=>addFormat(i),
242
267
  onRemoveFormat: ()=>removeFormat(i),
243
- onFormatChange: (format)=>handleFormatChange(i, format)
268
+ onFormatChange: (format)=>handleFormatChange(i, format),
269
+ onAddNegativeY: ()=>addNegativeY(i),
270
+ onRemoveNegativeY: ()=>removeNegativeY(i),
271
+ onAddStack: ()=>addStack(i),
272
+ onRemoveStack: ()=>removeStack(i),
273
+ onStackChange: (checked)=>handleStackChange(i, checked)
244
274
  }, i)),
245
275
  queryCount > 0 && firstAvailableQueryIndex !== NO_INDEX_AVAILABLE && /*#__PURE__*/ _jsx(Button, {
246
276
  variant: "contained",
@@ -254,7 +284,7 @@ export function QuerySettingsEditor(props) {
254
284
  ]
255
285
  });
256
286
  }
257
- function QuerySettingsInput({ querySettings: { queryIndex, colorMode, colorValue, lineStyle, areaOpacity, format }, availableQueryIndexes, queryNames, onQueryIndexChange, onColorModeChange, onColorValueChange, onLineStyleChange, onAreaOpacityChange, onDelete, inputRef, onAddColor: onAddColor, onRemoveColor: onRemoveColor, onAddLineStyle, onRemoveLineStyle, onAddAreaOpacity, onRemoveAreaOpacity, onAddFormat, onRemoveFormat, onFormatChange }) {
287
+ function QuerySettingsInput({ querySettings: { queryIndex, colorMode, colorValue, lineStyle, areaOpacity, format, negativeY, stack }, availableQueryIndexes, queryNames, onQueryIndexChange, onColorModeChange, onColorValueChange, onLineStyleChange, onAreaOpacityChange, onDelete, inputRef, onAddColor: onAddColor, onRemoveColor: onRemoveColor, onAddLineStyle, onRemoveLineStyle, onAddAreaOpacity, onRemoveAreaOpacity, onAddFormat, onRemoveFormat, onFormatChange, onAddNegativeY, onRemoveNegativeY, onAddStack, onRemoveStack, onStackChange }) {
258
288
  // current query index should also be selectable
259
289
  const selectableQueryIndexes = availableQueryIndexes.concat(queryIndex).sort((a, b)=>a - b);
260
290
  // State for dropdown menu
@@ -282,16 +312,30 @@ function QuerySettingsInput({ querySettings: { queryIndex, colorMode, colorValue
282
312
  label: 'Format',
283
313
  action: onAddFormat
284
314
  });
315
+ if (!negativeY) options.push({
316
+ key: 'negativeY',
317
+ label: 'Negative Y',
318
+ action: onAddNegativeY
319
+ });
320
+ if (stack === undefined) options.push({
321
+ key: 'stack',
322
+ label: 'Stack',
323
+ action: onAddStack
324
+ });
285
325
  return options;
286
326
  }, [
287
327
  colorMode,
288
328
  lineStyle,
289
329
  areaOpacity,
290
330
  format,
331
+ negativeY,
332
+ stack,
291
333
  onAddColor,
292
334
  onAddLineStyle,
293
335
  onAddAreaOpacity,
294
- onAddFormat
336
+ onAddFormat,
337
+ onAddNegativeY,
338
+ onAddStack
295
339
  ]);
296
340
  const handleAddMenuClick = (event)=>{
297
341
  if (availableOptions.length === 1 && availableOptions[0]) {
@@ -435,6 +479,39 @@ function QuerySettingsInput({ querySettings: { queryIndex, colorMode, colorValue
435
479
  })
436
480
  })
437
481
  }),
482
+ negativeY && /*#__PURE__*/ _jsx(SettingsSection, {
483
+ label: "Negative Y",
484
+ onRemove: onRemoveNegativeY,
485
+ children: /*#__PURE__*/ _jsx(Typography, {
486
+ variant: "body2",
487
+ color: "text.secondary",
488
+ sx: {
489
+ flexGrow: 1,
490
+ py: 0.5
491
+ },
492
+ children: "Series rendered below the X axis"
493
+ })
494
+ }),
495
+ stack !== undefined && /*#__PURE__*/ _jsxs(SettingsSection, {
496
+ label: "Stack",
497
+ onRemove: onRemoveStack,
498
+ children: [
499
+ /*#__PURE__*/ _jsx(Switch, {
500
+ checked: stack,
501
+ onChange: (e)=>onStackChange(e.target.checked),
502
+ slotProps: {
503
+ input: {
504
+ 'aria-label': 'stack override'
505
+ }
506
+ }
507
+ }),
508
+ /*#__PURE__*/ _jsx(Box, {
509
+ sx: {
510
+ flexGrow: 1
511
+ }
512
+ })
513
+ ]
514
+ }),
438
515
  availableOptions.length > 0 && /*#__PURE__*/ _jsxs(_Fragment, {
439
516
  children: [
440
517
  /*#__PURE__*/ _jsx(IconButton, {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/QuerySettingsEditor.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport {\n Box,\n Button,\n IconButton,\n Menu,\n MenuItem,\n Slider,\n Stack,\n TextField,\n ToggleButton,\n ToggleButtonGroup,\n Typography,\n useTheme,\n} from '@mui/material';\nimport { FormatControls, FormatOptions, OptionsColorPicker } from '@perses-dev/components';\nimport React, { ReactElement, useEffect, useMemo, useRef, useState } from 'react';\nimport DeleteIcon from 'mdi-material-ui/DeleteOutline';\nimport AddIcon from 'mdi-material-ui/Plus';\nimport CloseIcon from 'mdi-material-ui/Close';\nimport { produce } from 'immer';\nimport { generateQueryNames, useDataQueriesContext } from '@perses-dev/plugin-system';\nimport {\n DEFAULT_AREA_OPACITY,\n LINE_STYLE_CONFIG,\n OPACITY_CONFIG,\n QuerySettingsOptions,\n TimeSeriesChartOptions,\n TimeSeriesChartOptionsEditorProps,\n} from './time-series-chart-model';\n\nconst DEFAULT_COLOR_VALUE = '#555';\nconst NO_INDEX_AVAILABLE = -1; // invalid array index value used to represent the fact that no query index is available\n\nexport function QuerySettingsEditor(props: TimeSeriesChartOptionsEditorProps): ReactElement {\n const { onChange, value } = props;\n const querySettingsList = value.querySettings;\n\n const handleQuerySettingsChange = (newQuerySettings: QuerySettingsOptions[]): void => {\n onChange(\n produce(value, (draft: TimeSeriesChartOptions) => {\n draft.querySettings = newQuerySettings;\n })\n );\n };\n // Every time a new query settings input is added, we want to focus the recently added input\n const recentlyAddedInputRef = useRef<HTMLInputElement | null>(null);\n const focusRef = useRef(false);\n useEffect(() => {\n if (!recentlyAddedInputRef.current || !focusRef.current) return;\n recentlyAddedInputRef.current?.focus();\n focusRef.current = false;\n }, [querySettingsList?.length]);\n\n const handleQueryIndexChange = (e: React.ChangeEvent<HTMLInputElement>, i: number): void => {\n if (querySettingsList !== undefined) {\n handleQuerySettingsChange(\n produce(querySettingsList, (draft) => {\n const querySettings = draft?.[i];\n if (querySettings) {\n querySettings.queryIndex = parseInt(e.target.value);\n }\n })\n );\n }\n };\n\n const handleColorModeChange = (e: React.ChangeEvent<HTMLInputElement>, i: number): void => {\n if (querySettingsList !== undefined) {\n handleQuerySettingsChange(\n produce(querySettingsList, (draft) => {\n if (draft !== undefined) {\n const querySettings = draft[i];\n if (querySettings) {\n const newColorMode = e.target.value;\n if (!newColorMode) {\n querySettings.colorMode = undefined;\n querySettings.colorValue = undefined;\n } else {\n querySettings.colorMode = newColorMode as QuerySettingsOptions['colorMode'];\n }\n }\n }\n })\n );\n }\n };\n\n const handleColorValueChange = (colorValue: string, i: number): void => {\n if (querySettingsList !== undefined) {\n handleQuerySettingsChange(\n produce(querySettingsList, (draft) => {\n if (draft !== undefined) {\n const querySettings = draft[i];\n if (querySettings) {\n querySettings.colorValue = colorValue;\n }\n }\n })\n );\n }\n };\n\n const handleLineStyleChange = (lineStyle: string, i: number): void => {\n if (querySettingsList !== undefined) {\n handleQuerySettingsChange(\n produce(querySettingsList, (draft) => {\n if (draft !== undefined) {\n const querySettings = draft[i];\n if (querySettings) {\n querySettings.lineStyle = lineStyle as QuerySettingsOptions['lineStyle'];\n }\n }\n })\n );\n }\n };\n\n const handleAreaOpacityChange = (_: Event, sliderValue: number | number[], i: number): void => {\n const newValue = Array.isArray(sliderValue) ? sliderValue[0] : sliderValue;\n if (querySettingsList !== undefined) {\n handleQuerySettingsChange(\n produce(querySettingsList, (draft) => {\n if (draft !== undefined) {\n const querySettings = draft[i];\n if (querySettings) {\n querySettings.areaOpacity = newValue;\n }\n }\n })\n );\n }\n };\n\n // Helper function to update query settings at a specific index\n const updateQuerySettings = (i: number, updater: (qs: QuerySettingsOptions) => void): void => {\n if (querySettingsList !== undefined) {\n handleQuerySettingsChange(\n produce(querySettingsList, (draft) => {\n const qs = draft[i];\n if (qs) {\n updater(qs);\n }\n })\n );\n }\n };\n\n const deleteQuerySettingsInput = (i: number): void => {\n if (querySettingsList !== undefined) {\n const updatedQuerySettingsList = produce(querySettingsList, (draft) => {\n draft.splice(i, 1);\n });\n handleQuerySettingsChange(updatedQuerySettingsList);\n }\n };\n\n const addColor = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.colorMode = 'fixed-single';\n qs.colorValue = DEFAULT_COLOR_VALUE;\n });\n };\n\n const removeColor = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.colorMode = undefined;\n qs.colorValue = undefined;\n });\n };\n\n const addLineStyle = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.lineStyle = 'solid';\n });\n };\n\n const removeLineStyle = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.lineStyle = undefined;\n });\n };\n\n const addAreaOpacity = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.areaOpacity = DEFAULT_AREA_OPACITY;\n });\n };\n\n const removeAreaOpacity = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.areaOpacity = undefined;\n });\n };\n\n const addFormat = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.format = { unit: 'decimal', shortValues: true };\n });\n };\n\n const removeFormat = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.format = undefined;\n });\n };\n\n const handleFormatChange = (i: number, format?: FormatOptions): void => {\n updateQuerySettings(i, (qs) => {\n qs.format = format;\n });\n };\n\n const { queryDefinitions } = useDataQueriesContext();\n const queryCount = queryDefinitions.length;\n const queryNames = useMemo(() => generateQueryNames(queryDefinitions), [queryDefinitions]);\n\n // Compute the list of query indexes for which query settings are not already defined.\n // This is to avoid already-booked indexes to still be selectable in the dropdown(s)\n const availableQueryIndexes = useMemo(() => {\n const bookedQueryIndexes = querySettingsList?.map((querySettings) => querySettings.queryIndex) ?? [];\n const allQueryIndexes = Array.from({ length: queryCount }, (_, i) => i);\n return allQueryIndexes.filter((_, queryIndex) => !bookedQueryIndexes.includes(queryIndex));\n }, [querySettingsList, queryCount]);\n\n const firstAvailableQueryIndex = useMemo(() => {\n return availableQueryIndexes[0] ?? NO_INDEX_AVAILABLE;\n }, [availableQueryIndexes]);\n\n const defaultQuerySettings: QuerySettingsOptions = {\n queryIndex: firstAvailableQueryIndex,\n };\n\n const addQuerySettingsInput = (): void => {\n focusRef.current = true;\n if (querySettingsList === undefined) {\n handleQuerySettingsChange([defaultQuerySettings]);\n } else {\n handleQuerySettingsChange(\n produce(querySettingsList, (draft) => {\n draft.push(defaultQuerySettings);\n })\n );\n }\n };\n\n return (\n <Stack>\n {queryCount === 0 ? (\n <Typography mb={2} fontStyle=\"italic\">\n No query defined\n </Typography>\n ) : (\n querySettingsList?.map((querySettings, i) => (\n <QuerySettingsInput\n inputRef={i === querySettingsList.length - 1 ? recentlyAddedInputRef : undefined}\n key={i}\n querySettings={querySettings}\n availableQueryIndexes={availableQueryIndexes}\n queryNames={queryNames}\n onQueryIndexChange={(e) => {\n handleQueryIndexChange(e, i);\n }}\n onColorModeChange={(e) => handleColorModeChange(e, i)}\n onColorValueChange={(color) => handleColorValueChange(color, i)}\n onLineStyleChange={(lineStyle) => handleLineStyleChange(lineStyle, i)}\n onAreaOpacityChange={(event, value) => handleAreaOpacityChange(event, value, i)}\n onDelete={() => {\n deleteQuerySettingsInput(i);\n }}\n onAddColor={() => addColor(i)}\n onRemoveColor={() => removeColor(i)}\n onAddLineStyle={() => addLineStyle(i)}\n onRemoveLineStyle={() => removeLineStyle(i)}\n onAddAreaOpacity={() => addAreaOpacity(i)}\n onRemoveAreaOpacity={() => removeAreaOpacity(i)}\n onAddFormat={() => addFormat(i)}\n onRemoveFormat={() => removeFormat(i)}\n onFormatChange={(format) => handleFormatChange(i, format)}\n />\n ))\n )}\n {queryCount > 0 && firstAvailableQueryIndex !== NO_INDEX_AVAILABLE && (\n <Button variant=\"contained\" startIcon={<AddIcon />} sx={{ marginTop: 1 }} onClick={addQuerySettingsInput}>\n Add Query Settings\n </Button>\n )}\n </Stack>\n );\n}\n\ninterface QuerySettingsInputProps {\n querySettings: QuerySettingsOptions;\n availableQueryIndexes: number[];\n queryNames: string[];\n onQueryIndexChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n onColorModeChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n onColorValueChange: (colorValue: string) => void;\n onLineStyleChange: (lineStyle: string) => void;\n onAreaOpacityChange: (event: Event, value: number | number[]) => void;\n onDelete: () => void;\n inputRef?: React.RefObject<HTMLInputElement | null>;\n // Optional control handlers\n onAddColor: () => void;\n onRemoveColor: () => void;\n onAddLineStyle: () => void;\n onRemoveLineStyle: () => void;\n onAddAreaOpacity: () => void;\n onRemoveAreaOpacity: () => void;\n onAddFormat: () => void;\n onRemoveFormat: () => void;\n onFormatChange: (format?: FormatOptions) => void;\n}\n\nfunction QuerySettingsInput({\n querySettings: { queryIndex, colorMode, colorValue, lineStyle, areaOpacity, format },\n availableQueryIndexes,\n queryNames,\n onQueryIndexChange,\n onColorModeChange,\n onColorValueChange,\n onLineStyleChange,\n onAreaOpacityChange,\n onDelete,\n inputRef,\n onAddColor: onAddColor,\n onRemoveColor: onRemoveColor,\n onAddLineStyle,\n onRemoveLineStyle,\n onAddAreaOpacity,\n onRemoveAreaOpacity,\n onAddFormat,\n onRemoveFormat,\n onFormatChange,\n}: QuerySettingsInputProps): ReactElement {\n // current query index should also be selectable\n const selectableQueryIndexes = availableQueryIndexes.concat(queryIndex).sort((a, b) => a - b);\n\n // State for dropdown menu\n const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n\n // Calculate available options\n const availableOptions = useMemo(() => {\n const options = [];\n if (!colorMode) options.push({ key: 'color', label: 'Color', action: onAddColor });\n if (!lineStyle) options.push({ key: 'lineStyle', label: 'Line Style', action: onAddLineStyle });\n if (areaOpacity === undefined) options.push({ key: 'opacity', label: 'Opacity', action: onAddAreaOpacity });\n if (format === undefined) options.push({ key: 'format', label: 'Format', action: onAddFormat });\n return options;\n }, [colorMode, lineStyle, areaOpacity, format, onAddColor, onAddLineStyle, onAddAreaOpacity, onAddFormat]);\n\n const handleAddMenuClick = (event: React.MouseEvent<HTMLElement>): void => {\n if (availableOptions.length === 1 && availableOptions[0]) {\n // If only one option left, add it directly\n availableOptions[0].action();\n } else {\n // Show dropdown\n setAnchorEl(event.currentTarget);\n }\n };\n\n const handleMenuClose = (): void => {\n setAnchorEl(null);\n };\n\n const handleMenuItemClick = (action: () => void): void => {\n action();\n handleMenuClose();\n };\n\n return (\n <Stack\n sx={{\n borderBottom: '1px solid',\n borderColor: 'divider',\n borderRadius: 1,\n p: 2,\n display: 'flex',\n flexWrap: 'nowrap',\n flexDirection: 'row',\n }}\n >\n <Stack direction=\"row\" alignItems=\"center\" sx={{ flexWrap: 'wrap', gap: 2, flexGrow: 1 }}>\n {/* Query Index Selection */}\n <TextField\n select\n inputRef={inputRef}\n value={queryIndex}\n label=\"Query\"\n onChange={onQueryIndexChange}\n sx={{ minWidth: '75px' }}\n >\n {selectableQueryIndexes.map((qi) => (\n <MenuItem key={`query-${qi}`} value={qi}>\n {queryNames[qi] ?? `#${qi + 1}`}\n </MenuItem>\n ))}\n </TextField>\n\n {/* Color section */}\n {colorMode && (\n <SettingsSection label=\"Color\" onRemove={onRemoveColor}>\n <TextField select value={colorMode} onChange={onColorModeChange} size=\"small\" sx={{ flexGrow: 1 }}>\n <MenuItem value=\"fixed-single\">Fixed (single)</MenuItem>\n <MenuItem value=\"fixed\">Fixed</MenuItem>\n </TextField>\n <OptionsColorPicker\n label={queryNames[queryIndex] ?? `Query n°${queryIndex + 1}`}\n color={colorValue || DEFAULT_COLOR_VALUE}\n onColorChange={onColorValueChange}\n />\n </SettingsSection>\n )}\n\n {/* Line Style section */}\n {lineStyle && (\n <SettingsSection label=\"Line Style\" onRemove={onRemoveLineStyle}>\n <ToggleButtonGroup\n color=\"primary\"\n exclusive\n value={lineStyle}\n onChange={(__, newValue) => {\n if (newValue !== null) {\n onLineStyleChange(newValue);\n }\n }}\n size=\"small\"\n >\n {Object.entries(LINE_STYLE_CONFIG).map(([styleValue, config]) => (\n <ToggleButton key={styleValue} value={styleValue} aria-label={`${styleValue} line style`}>\n {config.label}\n </ToggleButton>\n ))}\n </ToggleButtonGroup>\n {/* Spacer to push delete button to the right */}\n <Box sx={{ flexGrow: 1 }} />\n </SettingsSection>\n )}\n\n {/* Area Opacity section */}\n {areaOpacity !== undefined && (\n <SettingsSection label=\"Opacity\" onRemove={onRemoveAreaOpacity}>\n {/* Spacer as I don't want to add a prop to SettingsSection for left-padding just for that case.. */}\n <Box />\n <Slider\n value={areaOpacity}\n valueLabelDisplay=\"auto\"\n step={OPACITY_CONFIG.step}\n marks\n min={OPACITY_CONFIG.min}\n max={OPACITY_CONFIG.max}\n onChange={onAreaOpacityChange}\n sx={{ flexGrow: 1 }}\n />\n </SettingsSection>\n )}\n\n {/* Format section */}\n {format !== undefined && (\n <SettingsSection label=\"Format\" onRemove={onRemoveFormat}>\n <Box sx={{ minWidth: '180px', display: 'flex', gap: 1, flexDirection: 'column' }}>\n <FormatControls value={format} onChange={onFormatChange} />\n </Box>\n </SettingsSection>\n )}\n\n {/* Add Options Button - only show if there are available options */}\n {availableOptions.length > 0 && (\n <>\n <IconButton onClick={handleAddMenuClick} aria-label=\"Add option\">\n <AddIcon />\n </IconButton>\n\n {/* Dropdown Menu */}\n <Menu\n anchorEl={anchorEl}\n open={Boolean(anchorEl)}\n onClose={handleMenuClose}\n anchorOrigin={{\n vertical: 'bottom',\n horizontal: 'left',\n }}\n >\n {availableOptions.map((option) => (\n <MenuItem\n key={option.key}\n onClick={() => handleMenuItemClick(option.action)}\n sx={{ minWidth: '120px' }}\n >\n <AddIcon sx={{ mr: 1, fontSize: '1rem' }} />\n {option.label}\n </MenuItem>\n ))}\n </Menu>\n </>\n )}\n </Stack>\n {/* Delete Button for this query settings */}\n <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\n <IconButton\n aria-label={`delete settings for ${queryNames[queryIndex] ?? `query n°${queryIndex + 1}`}`}\n onClick={onDelete}\n >\n <DeleteIcon />\n </IconButton>\n </Box>\n </Stack>\n );\n}\n\ninterface SettingsSectionProps {\n label: string;\n children: React.ReactNode;\n onRemove: () => void;\n}\n\n// Reusable section component\nfunction SettingsSection(props: SettingsSectionProps): ReactElement {\n const { label, children, onRemove } = props;\n const theme = useTheme();\n\n return (\n <Box sx={{ position: 'relative', minWidth: '250px' }}>\n <Typography\n variant=\"caption\"\n sx={{\n position: 'absolute',\n top: -8,\n left: 12,\n backgroundColor: theme.palette.background.code,\n px: 0.5,\n color: 'text.secondary',\n zIndex: 1,\n }}\n >\n {label}\n </Typography>\n <Stack\n direction=\"row\"\n alignItems=\"center\"\n spacing={1}\n sx={{\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: 1,\n p: 1,\n }}\n >\n {children}\n <IconButton size=\"small\" onClick={onRemove} aria-label={`Remove ${label}`}>\n <CloseIcon />\n </IconButton>\n </Stack>\n </Box>\n );\n}\n"],"names":["Box","Button","IconButton","Menu","MenuItem","Slider","Stack","TextField","ToggleButton","ToggleButtonGroup","Typography","useTheme","FormatControls","OptionsColorPicker","React","useEffect","useMemo","useRef","useState","DeleteIcon","AddIcon","CloseIcon","produce","generateQueryNames","useDataQueriesContext","DEFAULT_AREA_OPACITY","LINE_STYLE_CONFIG","OPACITY_CONFIG","DEFAULT_COLOR_VALUE","NO_INDEX_AVAILABLE","QuerySettingsEditor","props","onChange","value","querySettingsList","querySettings","handleQuerySettingsChange","newQuerySettings","draft","recentlyAddedInputRef","focusRef","current","focus","length","handleQueryIndexChange","e","i","undefined","queryIndex","parseInt","target","handleColorModeChange","newColorMode","colorMode","colorValue","handleColorValueChange","handleLineStyleChange","lineStyle","handleAreaOpacityChange","_","sliderValue","newValue","Array","isArray","areaOpacity","updateQuerySettings","updater","qs","deleteQuerySettingsInput","updatedQuerySettingsList","splice","addColor","removeColor","addLineStyle","removeLineStyle","addAreaOpacity","removeAreaOpacity","addFormat","format","unit","shortValues","removeFormat","handleFormatChange","queryDefinitions","queryCount","queryNames","availableQueryIndexes","bookedQueryIndexes","map","allQueryIndexes","from","filter","includes","firstAvailableQueryIndex","defaultQuerySettings","addQuerySettingsInput","push","mb","fontStyle","QuerySettingsInput","inputRef","onQueryIndexChange","onColorModeChange","onColorValueChange","color","onLineStyleChange","onAreaOpacityChange","event","onDelete","onAddColor","onRemoveColor","onAddLineStyle","onRemoveLineStyle","onAddAreaOpacity","onRemoveAreaOpacity","onAddFormat","onRemoveFormat","onFormatChange","variant","startIcon","sx","marginTop","onClick","selectableQueryIndexes","concat","sort","a","b","anchorEl","setAnchorEl","availableOptions","options","key","label","action","handleAddMenuClick","currentTarget","handleMenuClose","handleMenuItemClick","borderBottom","borderColor","borderRadius","p","display","flexWrap","flexDirection","direction","alignItems","gap","flexGrow","select","minWidth","qi","SettingsSection","onRemove","size","onColorChange","exclusive","__","Object","entries","styleValue","config","aria-label","valueLabelDisplay","step","marks","min","max","open","Boolean","onClose","anchorOrigin","vertical","horizontal","option","mr","fontSize","justifyContent","children","theme","position","top","left","backgroundColor","palette","background","code","px","zIndex","spacing","border"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/QuerySettingsEditor.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport {\n Box,\n Button,\n IconButton,\n Menu,\n MenuItem,\n Slider,\n Stack,\n Switch,\n TextField,\n ToggleButton,\n ToggleButtonGroup,\n Typography,\n useTheme,\n} from '@mui/material';\nimport { FormatControls, FormatOptions, OptionsColorPicker } from '@perses-dev/components';\nimport React, { ReactElement, useEffect, useMemo, useRef, useState } from 'react';\nimport DeleteIcon from 'mdi-material-ui/DeleteOutline';\nimport AddIcon from 'mdi-material-ui/Plus';\nimport CloseIcon from 'mdi-material-ui/Close';\nimport { produce } from 'immer';\nimport { generateQueryNames, useDataQueriesContext } from '@perses-dev/plugin-system';\nimport {\n DEFAULT_AREA_OPACITY,\n LINE_STYLE_CONFIG,\n OPACITY_CONFIG,\n QuerySettingsOptions,\n TimeSeriesChartOptions,\n TimeSeriesChartOptionsEditorProps,\n} from './time-series-chart-model';\n\nconst DEFAULT_COLOR_VALUE = '#555';\nconst NO_INDEX_AVAILABLE = -1; // invalid array index value used to represent the fact that no query index is available\n\nexport function QuerySettingsEditor(props: TimeSeriesChartOptionsEditorProps): ReactElement {\n const { onChange, value } = props;\n const querySettingsList = value.querySettings;\n\n const handleQuerySettingsChange = (newQuerySettings: QuerySettingsOptions[]): void => {\n onChange(\n produce(value, (draft: TimeSeriesChartOptions) => {\n draft.querySettings = newQuerySettings;\n })\n );\n };\n // Every time a new query settings input is added, we want to focus the recently added input\n const recentlyAddedInputRef = useRef<HTMLInputElement | null>(null);\n const focusRef = useRef(false);\n useEffect(() => {\n if (!recentlyAddedInputRef.current || !focusRef.current) return;\n recentlyAddedInputRef.current?.focus();\n focusRef.current = false;\n }, [querySettingsList?.length]);\n\n const handleQueryIndexChange = (e: React.ChangeEvent<HTMLInputElement>, i: number): void => {\n if (querySettingsList !== undefined) {\n handleQuerySettingsChange(\n produce(querySettingsList, (draft) => {\n const querySettings = draft?.[i];\n if (querySettings) {\n querySettings.queryIndex = parseInt(e.target.value);\n }\n })\n );\n }\n };\n\n const handleColorModeChange = (e: React.ChangeEvent<HTMLInputElement>, i: number): void => {\n if (querySettingsList !== undefined) {\n handleQuerySettingsChange(\n produce(querySettingsList, (draft) => {\n if (draft !== undefined) {\n const querySettings = draft[i];\n if (querySettings) {\n const newColorMode = e.target.value;\n if (!newColorMode) {\n querySettings.colorMode = undefined;\n querySettings.colorValue = undefined;\n } else {\n querySettings.colorMode = newColorMode as QuerySettingsOptions['colorMode'];\n }\n }\n }\n })\n );\n }\n };\n\n const handleColorValueChange = (colorValue: string, i: number): void => {\n if (querySettingsList !== undefined) {\n handleQuerySettingsChange(\n produce(querySettingsList, (draft) => {\n if (draft !== undefined) {\n const querySettings = draft[i];\n if (querySettings) {\n querySettings.colorValue = colorValue;\n }\n }\n })\n );\n }\n };\n\n const handleLineStyleChange = (lineStyle: string, i: number): void => {\n if (querySettingsList !== undefined) {\n handleQuerySettingsChange(\n produce(querySettingsList, (draft) => {\n if (draft !== undefined) {\n const querySettings = draft[i];\n if (querySettings) {\n querySettings.lineStyle = lineStyle as QuerySettingsOptions['lineStyle'];\n }\n }\n })\n );\n }\n };\n\n const handleAreaOpacityChange = (_: Event, sliderValue: number | number[], i: number): void => {\n const newValue = Array.isArray(sliderValue) ? sliderValue[0] : sliderValue;\n if (querySettingsList !== undefined) {\n handleQuerySettingsChange(\n produce(querySettingsList, (draft) => {\n if (draft !== undefined) {\n const querySettings = draft[i];\n if (querySettings) {\n querySettings.areaOpacity = newValue;\n }\n }\n })\n );\n }\n };\n\n // Helper function to update query settings at a specific index\n const updateQuerySettings = (i: number, updater: (qs: QuerySettingsOptions) => void): void => {\n if (querySettingsList !== undefined) {\n handleQuerySettingsChange(\n produce(querySettingsList, (draft) => {\n const qs = draft[i];\n if (qs) {\n updater(qs);\n }\n })\n );\n }\n };\n\n const deleteQuerySettingsInput = (i: number): void => {\n if (querySettingsList !== undefined) {\n const updatedQuerySettingsList = produce(querySettingsList, (draft) => {\n draft.splice(i, 1);\n });\n handleQuerySettingsChange(updatedQuerySettingsList);\n }\n };\n\n const addColor = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.colorMode = 'fixed-single';\n qs.colorValue = DEFAULT_COLOR_VALUE;\n });\n };\n\n const removeColor = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.colorMode = undefined;\n qs.colorValue = undefined;\n });\n };\n\n const addLineStyle = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.lineStyle = 'solid';\n });\n };\n\n const removeLineStyle = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.lineStyle = undefined;\n });\n };\n\n const addAreaOpacity = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.areaOpacity = DEFAULT_AREA_OPACITY;\n });\n };\n\n const removeAreaOpacity = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.areaOpacity = undefined;\n });\n };\n\n const addFormat = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.format = { unit: 'decimal', shortValues: true };\n });\n };\n\n const removeFormat = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.format = undefined;\n });\n };\n\n const addStack = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.stack = false;\n });\n };\n\n const removeStack = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.stack = undefined;\n });\n };\n\n const handleStackChange = (i: number, checked: boolean): void => {\n updateQuerySettings(i, (qs) => {\n qs.stack = checked;\n });\n };\n\n const handleFormatChange = (i: number, format?: FormatOptions): void => {\n updateQuerySettings(i, (qs) => {\n qs.format = format;\n });\n };\n\n const addNegativeY = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.negativeY = true;\n });\n };\n\n const removeNegativeY = (i: number): void => {\n updateQuerySettings(i, (qs) => {\n qs.negativeY = undefined;\n });\n };\n\n const { queryDefinitions } = useDataQueriesContext();\n const queryCount = queryDefinitions.length;\n const queryNames = useMemo(() => generateQueryNames(queryDefinitions), [queryDefinitions]);\n\n // Compute the list of query indexes for which query settings are not already defined.\n // This is to avoid already-booked indexes to still be selectable in the dropdown(s)\n const availableQueryIndexes = useMemo(() => {\n const bookedQueryIndexes = querySettingsList?.map((querySettings) => querySettings.queryIndex) ?? [];\n const allQueryIndexes = Array.from({ length: queryCount }, (_, i) => i);\n return allQueryIndexes.filter((_, queryIndex) => !bookedQueryIndexes.includes(queryIndex));\n }, [querySettingsList, queryCount]);\n\n const firstAvailableQueryIndex = useMemo(() => {\n return availableQueryIndexes[0] ?? NO_INDEX_AVAILABLE;\n }, [availableQueryIndexes]);\n\n const defaultQuerySettings: QuerySettingsOptions = {\n queryIndex: firstAvailableQueryIndex,\n };\n\n const addQuerySettingsInput = (): void => {\n focusRef.current = true;\n if (querySettingsList === undefined) {\n handleQuerySettingsChange([defaultQuerySettings]);\n } else {\n handleQuerySettingsChange(\n produce(querySettingsList, (draft) => {\n draft.push(defaultQuerySettings);\n })\n );\n }\n };\n\n return (\n <Stack>\n {queryCount === 0 ? (\n <Typography mb={2} fontStyle=\"italic\">\n No query defined\n </Typography>\n ) : (\n querySettingsList?.map((querySettings, i) => (\n <QuerySettingsInput\n inputRef={i === querySettingsList.length - 1 ? recentlyAddedInputRef : undefined}\n key={i}\n querySettings={querySettings}\n availableQueryIndexes={availableQueryIndexes}\n queryNames={queryNames}\n onQueryIndexChange={(e) => {\n handleQueryIndexChange(e, i);\n }}\n onColorModeChange={(e) => handleColorModeChange(e, i)}\n onColorValueChange={(color) => handleColorValueChange(color, i)}\n onLineStyleChange={(lineStyle) => handleLineStyleChange(lineStyle, i)}\n onAreaOpacityChange={(event, value) => handleAreaOpacityChange(event, value, i)}\n onDelete={() => {\n deleteQuerySettingsInput(i);\n }}\n onAddColor={() => addColor(i)}\n onRemoveColor={() => removeColor(i)}\n onAddLineStyle={() => addLineStyle(i)}\n onRemoveLineStyle={() => removeLineStyle(i)}\n onAddAreaOpacity={() => addAreaOpacity(i)}\n onRemoveAreaOpacity={() => removeAreaOpacity(i)}\n onAddFormat={() => addFormat(i)}\n onRemoveFormat={() => removeFormat(i)}\n onFormatChange={(format) => handleFormatChange(i, format)}\n onAddNegativeY={() => addNegativeY(i)}\n onRemoveNegativeY={() => removeNegativeY(i)}\n onAddStack={() => addStack(i)}\n onRemoveStack={() => removeStack(i)}\n onStackChange={(checked) => handleStackChange(i, checked)}\n />\n ))\n )}\n {queryCount > 0 && firstAvailableQueryIndex !== NO_INDEX_AVAILABLE && (\n <Button variant=\"contained\" startIcon={<AddIcon />} sx={{ marginTop: 1 }} onClick={addQuerySettingsInput}>\n Add Query Settings\n </Button>\n )}\n </Stack>\n );\n}\n\ninterface QuerySettingsInputProps {\n querySettings: QuerySettingsOptions;\n availableQueryIndexes: number[];\n queryNames: string[];\n onQueryIndexChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n onColorModeChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n onColorValueChange: (colorValue: string) => void;\n onLineStyleChange: (lineStyle: string) => void;\n onAreaOpacityChange: (event: Event, value: number | number[]) => void;\n onDelete: () => void;\n inputRef?: React.RefObject<HTMLInputElement | null>;\n // Optional control handlers\n onAddColor: () => void;\n onRemoveColor: () => void;\n onAddLineStyle: () => void;\n onRemoveLineStyle: () => void;\n onAddAreaOpacity: () => void;\n onRemoveAreaOpacity: () => void;\n onAddFormat: () => void;\n onRemoveFormat: () => void;\n onFormatChange: (format?: FormatOptions) => void;\n onAddNegativeY: () => void;\n onRemoveNegativeY: () => void;\n onAddStack: () => void;\n onRemoveStack: () => void;\n onStackChange: (checked: boolean) => void;\n}\n\nfunction QuerySettingsInput({\n querySettings: { queryIndex, colorMode, colorValue, lineStyle, areaOpacity, format, negativeY, stack },\n availableQueryIndexes,\n queryNames,\n onQueryIndexChange,\n onColorModeChange,\n onColorValueChange,\n onLineStyleChange,\n onAreaOpacityChange,\n onDelete,\n inputRef,\n onAddColor: onAddColor,\n onRemoveColor: onRemoveColor,\n onAddLineStyle,\n onRemoveLineStyle,\n onAddAreaOpacity,\n onRemoveAreaOpacity,\n onAddFormat,\n onRemoveFormat,\n onFormatChange,\n onAddNegativeY,\n onRemoveNegativeY,\n onAddStack,\n onRemoveStack,\n onStackChange,\n}: QuerySettingsInputProps): ReactElement {\n // current query index should also be selectable\n const selectableQueryIndexes = availableQueryIndexes.concat(queryIndex).sort((a, b) => a - b);\n\n // State for dropdown menu\n const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n\n // Calculate available options\n const availableOptions = useMemo(() => {\n const options = [];\n if (!colorMode) options.push({ key: 'color', label: 'Color', action: onAddColor });\n if (!lineStyle) options.push({ key: 'lineStyle', label: 'Line Style', action: onAddLineStyle });\n if (areaOpacity === undefined) options.push({ key: 'opacity', label: 'Opacity', action: onAddAreaOpacity });\n if (format === undefined) options.push({ key: 'format', label: 'Format', action: onAddFormat });\n if (!negativeY) options.push({ key: 'negativeY', label: 'Negative Y', action: onAddNegativeY });\n if (stack === undefined) options.push({ key: 'stack', label: 'Stack', action: onAddStack });\n return options;\n }, [\n colorMode,\n lineStyle,\n areaOpacity,\n format,\n negativeY,\n stack,\n onAddColor,\n onAddLineStyle,\n onAddAreaOpacity,\n onAddFormat,\n onAddNegativeY,\n onAddStack,\n ]);\n\n const handleAddMenuClick = (event: React.MouseEvent<HTMLElement>): void => {\n if (availableOptions.length === 1 && availableOptions[0]) {\n // If only one option left, add it directly\n availableOptions[0].action();\n } else {\n // Show dropdown\n setAnchorEl(event.currentTarget);\n }\n };\n\n const handleMenuClose = (): void => {\n setAnchorEl(null);\n };\n\n const handleMenuItemClick = (action: () => void): void => {\n action();\n handleMenuClose();\n };\n\n return (\n <Stack\n sx={{\n borderBottom: '1px solid',\n borderColor: 'divider',\n borderRadius: 1,\n p: 2,\n display: 'flex',\n flexWrap: 'nowrap',\n flexDirection: 'row',\n }}\n >\n <Stack direction=\"row\" alignItems=\"center\" sx={{ flexWrap: 'wrap', gap: 2, flexGrow: 1 }}>\n {/* Query Index Selection */}\n <TextField\n select\n inputRef={inputRef}\n value={queryIndex}\n label=\"Query\"\n onChange={onQueryIndexChange}\n sx={{ minWidth: '75px' }}\n >\n {selectableQueryIndexes.map((qi) => (\n <MenuItem key={`query-${qi}`} value={qi}>\n {queryNames[qi] ?? `#${qi + 1}`}\n </MenuItem>\n ))}\n </TextField>\n\n {/* Color section */}\n {colorMode && (\n <SettingsSection label=\"Color\" onRemove={onRemoveColor}>\n <TextField select value={colorMode} onChange={onColorModeChange} size=\"small\" sx={{ flexGrow: 1 }}>\n <MenuItem value=\"fixed-single\">Fixed (single)</MenuItem>\n <MenuItem value=\"fixed\">Fixed</MenuItem>\n </TextField>\n <OptionsColorPicker\n label={queryNames[queryIndex] ?? `Query n°${queryIndex + 1}`}\n color={colorValue || DEFAULT_COLOR_VALUE}\n onColorChange={onColorValueChange}\n />\n </SettingsSection>\n )}\n\n {/* Line Style section */}\n {lineStyle && (\n <SettingsSection label=\"Line Style\" onRemove={onRemoveLineStyle}>\n <ToggleButtonGroup\n color=\"primary\"\n exclusive\n value={lineStyle}\n onChange={(__, newValue) => {\n if (newValue !== null) {\n onLineStyleChange(newValue);\n }\n }}\n size=\"small\"\n >\n {Object.entries(LINE_STYLE_CONFIG).map(([styleValue, config]) => (\n <ToggleButton key={styleValue} value={styleValue} aria-label={`${styleValue} line style`}>\n {config.label}\n </ToggleButton>\n ))}\n </ToggleButtonGroup>\n {/* Spacer to push delete button to the right */}\n <Box sx={{ flexGrow: 1 }} />\n </SettingsSection>\n )}\n\n {/* Area Opacity section */}\n {areaOpacity !== undefined && (\n <SettingsSection label=\"Opacity\" onRemove={onRemoveAreaOpacity}>\n {/* Spacer as I don't want to add a prop to SettingsSection for left-padding just for that case.. */}\n <Box />\n <Slider\n value={areaOpacity}\n valueLabelDisplay=\"auto\"\n step={OPACITY_CONFIG.step}\n marks\n min={OPACITY_CONFIG.min}\n max={OPACITY_CONFIG.max}\n onChange={onAreaOpacityChange}\n sx={{ flexGrow: 1 }}\n />\n </SettingsSection>\n )}\n\n {/* Format section */}\n {format !== undefined && (\n <SettingsSection label=\"Format\" onRemove={onRemoveFormat}>\n <Box sx={{ minWidth: '180px', display: 'flex', gap: 1, flexDirection: 'column' }}>\n <FormatControls value={format} onChange={onFormatChange} />\n </Box>\n </SettingsSection>\n )}\n\n {/* Negative Y section (presence-only flag) */}\n {negativeY && (\n <SettingsSection label=\"Negative Y\" onRemove={onRemoveNegativeY}>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ flexGrow: 1, py: 0.5 }}>\n Series rendered below the X axis\n </Typography>\n </SettingsSection>\n )}\n\n {/* Stack section */}\n {stack !== undefined && (\n <SettingsSection label=\"Stack\" onRemove={onRemoveStack}>\n <Switch\n checked={stack}\n onChange={(e) => onStackChange(e.target.checked)}\n slotProps={{ input: { 'aria-label': 'stack override' } }}\n />\n <Box sx={{ flexGrow: 1 }} />\n </SettingsSection>\n )}\n\n {/* Add Options Button - only show if there are available options */}\n {availableOptions.length > 0 && (\n <>\n <IconButton onClick={handleAddMenuClick} aria-label=\"Add option\">\n <AddIcon />\n </IconButton>\n\n {/* Dropdown Menu */}\n <Menu\n anchorEl={anchorEl}\n open={Boolean(anchorEl)}\n onClose={handleMenuClose}\n anchorOrigin={{\n vertical: 'bottom',\n horizontal: 'left',\n }}\n >\n {availableOptions.map((option) => (\n <MenuItem\n key={option.key}\n onClick={() => handleMenuItemClick(option.action)}\n sx={{ minWidth: '120px' }}\n >\n <AddIcon sx={{ mr: 1, fontSize: '1rem' }} />\n {option.label}\n </MenuItem>\n ))}\n </Menu>\n </>\n )}\n </Stack>\n {/* Delete Button for this query settings */}\n <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\n <IconButton\n aria-label={`delete settings for ${queryNames[queryIndex] ?? `query n°${queryIndex + 1}`}`}\n onClick={onDelete}\n >\n <DeleteIcon />\n </IconButton>\n </Box>\n </Stack>\n );\n}\n\ninterface SettingsSectionProps {\n label: string;\n children: React.ReactNode;\n onRemove: () => void;\n}\n\n// Reusable section component\nfunction SettingsSection(props: SettingsSectionProps): ReactElement {\n const { label, children, onRemove } = props;\n const theme = useTheme();\n\n return (\n <Box sx={{ position: 'relative', minWidth: '250px' }}>\n <Typography\n variant=\"caption\"\n sx={{\n position: 'absolute',\n top: -8,\n left: 12,\n backgroundColor: theme.palette.background.code,\n px: 0.5,\n color: 'text.secondary',\n zIndex: 1,\n }}\n >\n {label}\n </Typography>\n <Stack\n direction=\"row\"\n alignItems=\"center\"\n spacing={1}\n sx={{\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: 1,\n p: 1,\n }}\n >\n {children}\n <IconButton size=\"small\" onClick={onRemove} aria-label={`Remove ${label}`}>\n <CloseIcon />\n </IconButton>\n </Stack>\n </Box>\n );\n}\n"],"names":["Box","Button","IconButton","Menu","MenuItem","Slider","Stack","Switch","TextField","ToggleButton","ToggleButtonGroup","Typography","useTheme","FormatControls","OptionsColorPicker","React","useEffect","useMemo","useRef","useState","DeleteIcon","AddIcon","CloseIcon","produce","generateQueryNames","useDataQueriesContext","DEFAULT_AREA_OPACITY","LINE_STYLE_CONFIG","OPACITY_CONFIG","DEFAULT_COLOR_VALUE","NO_INDEX_AVAILABLE","QuerySettingsEditor","props","onChange","value","querySettingsList","querySettings","handleQuerySettingsChange","newQuerySettings","draft","recentlyAddedInputRef","focusRef","current","focus","length","handleQueryIndexChange","e","i","undefined","queryIndex","parseInt","target","handleColorModeChange","newColorMode","colorMode","colorValue","handleColorValueChange","handleLineStyleChange","lineStyle","handleAreaOpacityChange","_","sliderValue","newValue","Array","isArray","areaOpacity","updateQuerySettings","updater","qs","deleteQuerySettingsInput","updatedQuerySettingsList","splice","addColor","removeColor","addLineStyle","removeLineStyle","addAreaOpacity","removeAreaOpacity","addFormat","format","unit","shortValues","removeFormat","addStack","stack","removeStack","handleStackChange","checked","handleFormatChange","addNegativeY","negativeY","removeNegativeY","queryDefinitions","queryCount","queryNames","availableQueryIndexes","bookedQueryIndexes","map","allQueryIndexes","from","filter","includes","firstAvailableQueryIndex","defaultQuerySettings","addQuerySettingsInput","push","mb","fontStyle","QuerySettingsInput","inputRef","onQueryIndexChange","onColorModeChange","onColorValueChange","color","onLineStyleChange","onAreaOpacityChange","event","onDelete","onAddColor","onRemoveColor","onAddLineStyle","onRemoveLineStyle","onAddAreaOpacity","onRemoveAreaOpacity","onAddFormat","onRemoveFormat","onFormatChange","onAddNegativeY","onRemoveNegativeY","onAddStack","onRemoveStack","onStackChange","variant","startIcon","sx","marginTop","onClick","selectableQueryIndexes","concat","sort","a","b","anchorEl","setAnchorEl","availableOptions","options","key","label","action","handleAddMenuClick","currentTarget","handleMenuClose","handleMenuItemClick","borderBottom","borderColor","borderRadius","p","display","flexWrap","flexDirection","direction","alignItems","gap","flexGrow","select","minWidth","qi","SettingsSection","onRemove","size","onColorChange","exclusive","__","Object","entries","styleValue","config","aria-label","valueLabelDisplay","step","marks","min","max","py","slotProps","input","open","Boolean","onClose","anchorOrigin","vertical","horizontal","option","mr","fontSize","justifyContent","children","theme","position","top","left","backgroundColor","palette","background","code","px","zIndex","spacing","border"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TimeSeriesChartPanel.d.ts","sourceRoot":"","sources":["../../src/TimeSeriesChartPanel.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAA6B,MAAM,OAAO,CAAC;AAIhE,OAAO,EAEL,UAAU,EAMX,MAAM,2BAA2B,CAAC;AAqBnC,OAAO,EAAc,cAAc,EAAwB,MAAM,kBAAkB,CAAC;AAEpF,OAAO,EACL,sBAAsB,EAKvB,MAAM,2BAA2B,CAAC;AAYnC,MAAM,MAAM,oBAAoB,GAAG,UAAU,CAAC,sBAAsB,EAAE,cAAc,CAAC,CAAC;AAWtF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,oBAAoB,GAAG,YAAY,GAAG,IAAI,CAgcrF"}
1
+ {"version":3,"file":"TimeSeriesChartPanel.d.ts","sourceRoot":"","sources":["../../src/TimeSeriesChartPanel.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAA6B,MAAM,OAAO,CAAC;AAIhE,OAAO,EAEL,UAAU,EAMX,MAAM,2BAA2B,CAAC;AAqBnC,OAAO,EAAc,cAAc,EAAwB,MAAM,kBAAkB,CAAC;AAEpF,OAAO,EACL,sBAAsB,EAKvB,MAAM,2BAA2B,CAAC;AAYnC,MAAM,MAAM,oBAAoB,GAAG,UAAU,CAAC,sBAAsB,EAAE,cAAc,CAAC,CAAC;AAWtF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,oBAAoB,GAAG,YAAY,GAAG,IAAI,CA+crF"}
@@ -196,9 +196,21 @@ export function TimeSeriesChartPanel(props) {
196
196
  }
197
197
  }
198
198
  }
199
+ // When negativeY is set on this query, negate the rendered values so the
200
+ // series renders below the X axis. The original (positive) values are
201
+ // preserved in `timeSeries.values` (used for legend calculations) and in
202
+ // `queryResults` (used for CSV export).
203
+ const baseValues = getTimeSeriesValues(timeSeries, timeScale);
204
+ const renderedValues = querySettings?.negativeY ? baseValues.map((tuple)=>{
205
+ const [t, v] = tuple;
206
+ return [
207
+ t,
208
+ v === null ? null : -v
209
+ ];
210
+ }) : baseValues;
199
211
  timeChartData.push({
200
212
  name: formattedSeriesName,
201
- values: getTimeSeriesValues(timeSeries, timeScale)
213
+ values: renderedValues
202
214
  });
203
215
  }
204
216
  if (legend && legendItems) {
@@ -354,8 +366,10 @@ export function TimeSeriesChartPanel(props) {
354
366
  end: new Date(event.end)
355
367
  });
356
368
  };
357
- // Used to opt in to ECharts trigger item which show subgroup data accurately
358
- const isStackedBar = visual.display === 'bar' && visual.stack === 'all';
369
+ // Used to opt in to ECharts trigger item which show subgroup data accurately.
370
+ // Derived from the actual series mapping rather than `visual.stack` alone so that
371
+ // bar charts stacked only via per-query overrides also use the right tooltip mode.
372
+ const isStackedBar = visual.display === 'bar' && timeSeriesMapping.some((s)=>s?.type === 'bar' && s.stack === 'all');
359
373
  // Turn on tooltip pinning by default but opt out for stacked bar or if explicitly set in tooltip panel spec
360
374
  let enablePinning = true;
361
375
  if (isStackedBar) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/TimeSeriesChartPanel.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { ReactElement, useMemo, useRef, useState } from 'react';\nimport { Box, useTheme } from '@mui/material';\nimport type { GridComponentOption } from 'echarts';\nimport merge from 'lodash/merge';\nimport {\n LEGEND_VALUE_CONFIG,\n PanelProps,\n useTimeRange,\n validateLegendSpec,\n legendValues,\n getCalculations,\n CalculationType,\n} from '@perses-dev/plugin-system';\nimport {\n ChartInstance,\n YAxisLabel,\n ZoomEventData,\n useChartsTheme,\n SelectedLegendItemState,\n ContentWithLegend,\n TableColumnConfig,\n LegendItem,\n LegendProps,\n useId,\n TooltipConfig,\n DEFAULT_TOOLTIP_CONFIG,\n TimeChartSeriesMapping,\n getFormattedMultipleYAxes,\n DEFAULT_LEGEND,\n StepOptions,\n formatValue,\n getTimeSeriesValues,\n} from '@perses-dev/components';\nimport { TimeSeries, TimeSeriesData, TimeSeriesValueTuple } from '@perses-dev/spec';\nimport { useAnnotationsWithData } from '@perses-dev/dashboards';\nimport {\n TimeSeriesChartOptions,\n DEFAULT_FORMAT,\n DEFAULT_VISUAL,\n THRESHOLD_PLOT_INTERVAL,\n QuerySettingsOptions,\n} from './time-series-chart-model';\nimport {\n getTimeSeries,\n getCommonTimeScaleForQueries,\n convertPanelYAxis,\n getThresholdSeries,\n convertPercentThreshold,\n} from './utils/data-transform';\nimport { getSeriesColor } from './utils/palette-gen';\nimport { TimeSeriesChartBase } from './TimeSeriesChartBase';\nimport { convertAnnotationToTimeSeriesAnnotation, TimeSeriesAnnotation } from './utils/annotation';\n\nexport type TimeSeriesChartProps = PanelProps<TimeSeriesChartOptions, TimeSeriesData>;\n\n// Using an \"ALL\" value to handle the case on first loading the chart where we\n// want to select all, but do not want all of the legend items to be visually highlighted.\n// This helps us differentiate those cases more clearly instead of inferring it\n// based on the state of the data. This also helps us avoid some coding\n// complexity around initializing a full record for the initial load that would\n// currently require significantly more refactoring of this component.\n// TODO: simplify this if we switch the list-based legend UI to use checkboxes,\n// where we *would* want to visually select all items in this case.\n\nexport function TimeSeriesChartPanel(props: TimeSeriesChartProps): ReactElement | null {\n const {\n spec: { thresholds, yAxis, tooltip, querySettings: querySettingsList },\n contentDimensions,\n queryResults,\n } = props;\n const chartsTheme = useChartsTheme();\n const muiTheme = useTheme();\n const chartId = useId('time-series-panel');\n\n const chartRef = useRef<ChartInstance>(null);\n\n // ECharts theme comes from ChartsProvider, more info: https://echarts.apache.org/en/option.html#color\n // Colors are manually applied since our legend and tooltip are built custom with React.\n const categoricalPalette = chartsTheme.echartsTheme.color;\n\n // TODO: consider refactoring how the layout/spacing/alignment are calculated\n // the next time significant changes are made to the time series panel (e.g.\n // when making improvements to the legend to more closely match designs).\n // This may also want to include moving some of this logic down to the shared,\n // embeddable components.\n const contentPadding = chartsTheme.container.padding.default;\n const adjustedContentDimensions: typeof contentDimensions = contentDimensions\n ? {\n width: contentDimensions.width - contentPadding * 2,\n height: contentDimensions.height - contentPadding * 2,\n }\n : undefined;\n\n // populate default 'position' and other future properties\n const legend = useMemo(() => {\n return props.spec.legend && validateLegendSpec(props.spec.legend)\n ? merge({}, DEFAULT_LEGEND, props.spec.legend)\n : undefined;\n }, [props.spec.legend]);\n\n // TODO: add support for y_axis_alt.format\n const format = props.spec.yAxis?.format ?? DEFAULT_FORMAT;\n\n // ensures there are fallbacks for unset properties since most\n // users should not need to customize visual display\n const visual = useMemo(() => {\n return merge({}, DEFAULT_VISUAL, props.spec.visual);\n }, [props.spec.visual]);\n\n // convert Perses dashboard format to be ECharts compatible\n const echartsYAxis = useMemo(() => {\n return convertPanelYAxis(yAxis);\n }, [yAxis]);\n\n // Collect unique formats from query settings that differ from the base format\n // These will create additional Y axes on the right side\n const { additionalFormats, formatToYAxisIndex, seriesFormatMap } = useMemo(() => {\n const baseUnit = format?.unit ?? 'decimal';\n const additionalFormats: Array<typeof format> = [];\n const formatToYAxisIndex = new Map<string, number>();\n const seriesFormatMap = new Map<string, typeof format>();\n\n // Index 0 is reserved for the base Y axis\n formatToYAxisIndex.set(baseUnit, 0);\n\n // Collect unique formats from query settings\n for (const qs of querySettingsList ?? []) {\n if (qs.format?.unit && qs.format.unit !== baseUnit) {\n const unitKey = qs.format.unit;\n if (!formatToYAxisIndex.has(unitKey)) {\n // Add new format - index is 1 + position in additionalFormats array\n formatToYAxisIndex.set(unitKey, 1 + additionalFormats.length);\n additionalFormats.push(qs.format);\n }\n }\n }\n\n return { additionalFormats, formatToYAxisIndex, seriesFormatMap };\n }, [format, querySettingsList]);\n\n const [selectedLegendItems, setSelectedLegendItems] = useState<SelectedLegendItemState>('ALL');\n const [legendSorting, setLegendSorting] = useState<NonNullable<LegendProps['tableProps']>['sorting']>();\n\n const { setTimeRange } = useTimeRange();\n\n const annotationsWithData = useAnnotationsWithData();\n\n const annotations: TimeSeriesAnnotation[] = useMemo(\n () => convertAnnotationToTimeSeriesAnnotation(annotationsWithData),\n [annotationsWithData]\n );\n\n // Populate series data based on query results\n const {\n timeScale,\n timeChartData,\n timeSeriesMapping,\n legendItems,\n seriesFormatMap: computedSeriesFormatMap,\n maxValuesByFormat,\n } = useMemo(() => {\n const timeScale = getCommonTimeScaleForQueries(queryResults);\n if (timeScale === undefined) {\n return {\n timeChartData: [],\n timeSeriesMapping: [],\n seriesFormatMap: new Map(),\n maxValuesByFormat: new Map<string, number>(),\n };\n }\n\n const legendItems: LegendItem[] = [];\n\n // Utilizes ECharts dataset so raw data is separate from series option style properties\n // https://apache.github.io/echarts-handbook/en/concepts/dataset/\n const timeChartData: TimeSeries[] = [];\n const timeSeriesMapping: TimeChartSeriesMapping = [];\n\n // Track max values for each format unit (used for dynamic Y axis offset calculation)\n const maxValuesByFormat = new Map<string, number>();\n\n // Index is counted across multiple queries which ensures the categorical color palette does not reset for every query\n let seriesIndex = 0;\n\n // Mapping of each set of query results to be ECharts option compatible\n // TODO: Look into performance optimizations and moving parts of mapping to the lower level chart\n for (let queryIndex = 0; queryIndex < queryResults.length; queryIndex++) {\n const result = queryResults[queryIndex];\n\n // Retrieve querySettings for this query, if exists.\n // queries & querySettings indices do not necessarily match, so we have to check the tail value of the $ref attribute\n let querySettings: QuerySettingsOptions | undefined;\n for (const item of querySettingsList ?? []) {\n if (item.queryIndex === queryIndex) {\n querySettings = item;\n // We don't break the loop here just in case there are multiple querySettings defined for the\n // same queryIndex, because in that case we want the last one to take precedence.\n }\n }\n\n if (result) {\n for (let i = 0; i < result.data.series.length; i++) {\n const timeSeries: TimeSeries | undefined = result.data.series[i];\n if (timeSeries === undefined) {\n return { timeChartData: [], timeSeriesMapping: [], legendItems: [] };\n }\n\n // Format is determined by seriesNameFormat in query spec\n const formattedSeriesName = timeSeries.formattedName ?? timeSeries.name;\n\n // Color is used for line, tooltip, and legend\n const seriesColor = getSeriesColor({\n // ECharts type for color is not always an array but it is always an array in ChartsProvider\n categoricalPalette: categoricalPalette as string[],\n visual,\n muiPrimaryColor: muiTheme.palette.primary.main,\n seriesName: formattedSeriesName,\n seriesIndex,\n querySettings: querySettings,\n queryHasMultipleResults: (queryResults[queryIndex]?.data?.series?.length ?? 0) > 1,\n });\n\n // We add a unique id for the chart to disambiguate items across charts\n // when there are multiple on the page.\n const seriesId = chartId + timeSeries.name + seriesIndex;\n\n const legendCalculations = legend?.values\n ? getCalculations(timeSeries.values, legend.values as CalculationType[])\n : undefined;\n\n // When we initially load the chart, we want to show all series, but\n // DO NOT want to visualy highlight all the items in the legend.\n const isSelectAll = selectedLegendItems === 'ALL';\n const isSelected = !isSelectAll && !!selectedLegendItems[seriesId];\n const showTimeSeries = isSelected || isSelectAll;\n\n if (showTimeSeries) {\n // Use timeChartData.length to ensure the data that is passed into the tooltip accounts for\n // which legend items are selected. This must happen before timeChartData.push to avoid an\n // off-by-one error, seriesIndex cannot be used since it's needed to cycle through palette\n const datasetIndex = timeChartData.length;\n\n // Determine yAxisIndex based on the query's format setting\n const queryFormat = querySettings?.format;\n const yAxisIndex = queryFormat?.unit ? (formatToYAxisIndex.get(queryFormat.unit) ?? 0) : 0;\n\n // Each series is stored as a separate dataset source.\n // https://apache.github.io/echarts-handbook/en/concepts/dataset/#how-to-reference-several-datasets\n timeSeriesMapping.push(\n getTimeSeries(\n seriesId,\n datasetIndex,\n formattedSeriesName,\n visual,\n timeScale,\n seriesColor,\n querySettings,\n yAxisIndex\n )\n );\n\n // Store the format for this series for tooltip formatting\n if (queryFormat) {\n seriesFormatMap.set(seriesId, queryFormat);\n\n // Track max value for this format unit (used for dynamic Y axis offset calculation)\n const unitKey = queryFormat.unit;\n if (unitKey) {\n const seriesMax = Math.max(...timeSeries.values.map((v) => Math.abs(v[1] ?? 0)));\n const currentMax = maxValuesByFormat.get(unitKey) ?? 0;\n if (seriesMax > currentMax) {\n maxValuesByFormat.set(unitKey, seriesMax);\n }\n }\n }\n\n timeChartData.push({\n name: formattedSeriesName,\n values: getTimeSeriesValues(timeSeries, timeScale),\n });\n }\n\n if (legend && legendItems) {\n legendItems.push({\n id: seriesId, // Avoids duplicate key console errors when there are duplicate series names\n label: formattedSeriesName,\n color: seriesColor,\n data: legendCalculations,\n });\n }\n\n // Used for repeating colors in Categorical palette\n seriesIndex++;\n }\n }\n }\n\n // map thresholds only if there is at least one time series to avoid displaying thresholds without any data\n if (thresholds && thresholds.steps && timeChartData.length > 0) {\n // Convert how thresholds are defined in the panel spec to valid ECharts 'line' series.\n // These are styled with predefined colors and a dashed style to look different than series from query results.\n // Regular series are used instead of markLines since thresholds currently show in our React TimeSeriesTooltip.\n const thresholdsColors = chartsTheme.thresholds;\n const defaultThresholdColor = thresholds.defaultColor ?? thresholdsColors.defaultColor;\n thresholds.steps.forEach((step: StepOptions, index: number) => {\n const stepPaletteColor = thresholdsColors.palette[index] ?? defaultThresholdColor;\n const thresholdLineColor = step.color ?? stepPaletteColor;\n const stepOption: StepOptions = {\n color: thresholdLineColor,\n value:\n // yAxis is passed here since it corresponds to dashboard JSON instead of the already converted ECharts yAxis\n thresholds.mode === 'percent'\n ? convertPercentThreshold(step.value, timeChartData, yAxis?.max, yAxis?.min)\n : step.value,\n };\n const thresholdName = step.name ?? `Threshold ${index + 1}`;\n\n // Generates array of [time, step.value] where time ranges from timescale.startMs to timescale.endMs with an interval of 15s\n const thresholdTimeValueTuple: TimeSeriesValueTuple[] = [];\n let currentTimestamp = timeScale.startMs;\n while (currentTimestamp <= timeScale.endMs) {\n thresholdTimeValueTuple.push([currentTimestamp, stepOption.value]);\n // Used to plot fake thresholds datapoints so correct nearby threshold series shows in tooltip without flicker\n currentTimestamp += 1000 * THRESHOLD_PLOT_INTERVAL;\n }\n\n timeChartData.push({\n name: thresholdName,\n values: thresholdTimeValueTuple,\n });\n timeSeriesMapping.push(getThresholdSeries(thresholdName, stepOption, seriesIndex));\n seriesIndex++;\n });\n }\n\n return {\n timeScale,\n timeChartData,\n timeSeriesMapping,\n legendItems,\n seriesFormatMap,\n maxValuesByFormat,\n };\n }, [\n queryResults,\n thresholds,\n selectedLegendItems,\n legend,\n visual,\n querySettingsList,\n yAxis?.max,\n yAxis?.min,\n categoricalPalette,\n chartId,\n chartsTheme.thresholds,\n muiTheme.palette.primary.main,\n formatToYAxisIndex,\n seriesFormatMap,\n ]);\n\n // Create multiple Y axes if there are additional formats\n // Uses max values from data to compute dynamic offsets that adapt to label widths\n const multipleYAxes = useMemo(() => {\n if (additionalFormats.length === 0) {\n return undefined; // Use single Y axis (default behavior)\n }\n // Build array of max values for each additional format (in order)\n const maxValues = additionalFormats.map((fmt) => {\n const unitKey = fmt.unit;\n return unitKey ? (maxValuesByFormat?.get(unitKey) ?? 1000) : 1000;\n });\n return getFormattedMultipleYAxes(echartsYAxis, format, additionalFormats, maxValues);\n }, [echartsYAxis, format, additionalFormats, maxValuesByFormat]);\n\n // Translate the legend values into columns for the table legend.\n const legendColumns = useMemo(() => {\n if (!legend?.values) {\n return [];\n }\n\n // Iterating the predefined list of possible values to retain a specific\n // intended order of values.\n return legendValues.reduce(\n (columns, legendValue) => {\n const legendConfig = LEGEND_VALUE_CONFIG[legendValue];\n\n if (legendConfig && legend?.values?.includes(legendValue)) {\n columns.push({\n accessorKey: `data.${legendValue}`,\n header: legendConfig.label,\n headerDescription: legendConfig.description,\n // Intentionally hardcoding a column width to start based on discussions\n // with design around keeping this simple to start. This may need\n // revisiting in the future to handle edge cases with very large values.\n width: 72,\n align: 'right',\n cell: ({ getValue }) => {\n const cellValue = getValue();\n return typeof cellValue === 'number' && format ? formatValue(cellValue, format) : cellValue;\n },\n cellDescription: true,\n enableSorting: true,\n });\n }\n\n return columns;\n },\n [] as Array<TableColumnConfig<LegendItem>>\n );\n }, [legend?.values, format]);\n\n const gridOverrides: GridComponentOption = useMemo(() => {\n // When Y axes are hidden, disable containLabel to prevent auto-spacing, but add bottom padding for X axis\n return echartsYAxis.show === false\n ? {\n left: 0,\n right: 0,\n bottom: 30,\n containLabel: false,\n }\n : {\n left: yAxis && yAxis.label ? 30 : 20,\n // With containLabel: true in theme, ECharts auto-reserves space for axis labels.\n // For multiple right axes, add extra padding for the last axis labels that extend beyond the grid.\n right: additionalFormats.length > 0 ? 10 : 20,\n bottom: 0,\n containLabel: true,\n };\n }, [echartsYAxis.show, yAxis, additionalFormats.length]);\n\n if (adjustedContentDimensions === undefined) {\n return null;\n }\n\n const handleDataZoom = (event: ZoomEventData): void => {\n // TODO: add ECharts transition animation on zoom\n setTimeRange({ start: new Date(event.start), end: new Date(event.end) });\n };\n\n // Used to opt in to ECharts trigger item which show subgroup data accurately\n const isStackedBar = visual.display === 'bar' && visual.stack === 'all';\n\n // Turn on tooltip pinning by default but opt out for stacked bar or if explicitly set in tooltip panel spec\n let enablePinning = true;\n if (isStackedBar) {\n enablePinning = false;\n } else if (tooltip?.enablePinning !== undefined) {\n enablePinning = tooltip.enablePinning;\n }\n const tooltipConfig: TooltipConfig = {\n ...DEFAULT_TOOLTIP_CONFIG,\n enablePinning,\n };\n\n return (\n <Box sx={{ padding: `${contentPadding}px` }}>\n <ContentWithLegend\n width={adjustedContentDimensions.width}\n height={adjustedContentDimensions.height}\n // Making this small enough that the medium size doesn't get\n // responsive-handling-ed away when in the panel options editor.\n minChildrenHeight={50}\n legendSize={legend?.size}\n legendProps={\n legend && {\n options: legend,\n data: legendItems || [],\n selectedItems: selectedLegendItems,\n onSelectedItemsChange: setSelectedLegendItems,\n tableProps: {\n columns: legendColumns,\n sorting: legendSorting,\n onSortingChange: setLegendSorting,\n },\n onItemMouseOver: (e, { id }): void => {\n chartRef.current?.highlightSeries({ name: id });\n },\n onItemMouseOut: (): void => {\n chartRef.current?.clearHighlightedSeries();\n },\n }\n }\n >\n {({ height, width }) => {\n return (\n <Box style={{ height, width }}>\n {yAxis && yAxis.show && yAxis.label && <YAxisLabel name={yAxis.label} height={height} />}\n <TimeSeriesChartBase\n ref={chartRef}\n height={height}\n data={timeChartData}\n seriesMapping={timeSeriesMapping}\n annotations={annotations}\n timeScale={timeScale}\n yAxis={multipleYAxes ?? echartsYAxis}\n format={format}\n seriesFormatMap={computedSeriesFormatMap}\n grid={gridOverrides}\n isStackedBar={isStackedBar}\n tooltipConfig={tooltipConfig}\n syncGroup=\"default-panel-group\" // TODO: make configurable from dashboard settings and per panel-group overrides\n onDataZoom={handleDataZoom}\n // Show an empty chart when there is no data because the user unselected all items in\n // the legend. Otherwise, show a \"no data\" message.\n noDataVariant={!timeChartData.length && legendItems && legendItems.length > 0 ? 'chart' : 'message'}\n />\n </Box>\n );\n }}\n </ContentWithLegend>\n </Box>\n );\n}\n"],"names":["useMemo","useRef","useState","Box","useTheme","merge","LEGEND_VALUE_CONFIG","useTimeRange","validateLegendSpec","legendValues","getCalculations","YAxisLabel","useChartsTheme","ContentWithLegend","useId","DEFAULT_TOOLTIP_CONFIG","getFormattedMultipleYAxes","DEFAULT_LEGEND","formatValue","getTimeSeriesValues","useAnnotationsWithData","DEFAULT_FORMAT","DEFAULT_VISUAL","THRESHOLD_PLOT_INTERVAL","getTimeSeries","getCommonTimeScaleForQueries","convertPanelYAxis","getThresholdSeries","convertPercentThreshold","getSeriesColor","TimeSeriesChartBase","convertAnnotationToTimeSeriesAnnotation","TimeSeriesChartPanel","props","spec","thresholds","yAxis","tooltip","querySettings","querySettingsList","contentDimensions","queryResults","chartsTheme","muiTheme","chartId","chartRef","categoricalPalette","echartsTheme","color","contentPadding","container","padding","default","adjustedContentDimensions","width","height","undefined","legend","format","visual","echartsYAxis","additionalFormats","formatToYAxisIndex","seriesFormatMap","baseUnit","unit","Map","set","qs","unitKey","has","length","push","selectedLegendItems","setSelectedLegendItems","legendSorting","setLegendSorting","setTimeRange","annotationsWithData","annotations","timeScale","timeChartData","timeSeriesMapping","legendItems","computedSeriesFormatMap","maxValuesByFormat","seriesIndex","queryIndex","result","item","i","data","series","timeSeries","formattedSeriesName","formattedName","name","seriesColor","muiPrimaryColor","palette","primary","main","seriesName","queryHasMultipleResults","seriesId","legendCalculations","values","isSelectAll","isSelected","showTimeSeries","datasetIndex","queryFormat","yAxisIndex","get","seriesMax","Math","max","map","v","abs","currentMax","id","label","steps","thresholdsColors","defaultThresholdColor","defaultColor","forEach","step","index","stepPaletteColor","thresholdLineColor","stepOption","value","mode","min","thresholdName","thresholdTimeValueTuple","currentTimestamp","startMs","endMs","multipleYAxes","maxValues","fmt","legendColumns","reduce","columns","legendValue","legendConfig","includes","accessorKey","header","headerDescription","description","align","cell","getValue","cellValue","cellDescription","enableSorting","gridOverrides","show","left","right","bottom","containLabel","handleDataZoom","event","start","Date","end","isStackedBar","display","stack","enablePinning","tooltipConfig","sx","minChildrenHeight","legendSize","size","legendProps","options","selectedItems","onSelectedItemsChange","tableProps","sorting","onSortingChange","onItemMouseOver","e","current","highlightSeries","onItemMouseOut","clearHighlightedSeries","style","ref","seriesMapping","grid","syncGroup","onDataZoom","noDataVariant"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/TimeSeriesChartPanel.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { ReactElement, useMemo, useRef, useState } from 'react';\nimport { Box, useTheme } from '@mui/material';\nimport type { GridComponentOption } from 'echarts';\nimport merge from 'lodash/merge';\nimport {\n LEGEND_VALUE_CONFIG,\n PanelProps,\n useTimeRange,\n validateLegendSpec,\n legendValues,\n getCalculations,\n CalculationType,\n} from '@perses-dev/plugin-system';\nimport {\n ChartInstance,\n YAxisLabel,\n ZoomEventData,\n useChartsTheme,\n SelectedLegendItemState,\n ContentWithLegend,\n TableColumnConfig,\n LegendItem,\n LegendProps,\n useId,\n TooltipConfig,\n DEFAULT_TOOLTIP_CONFIG,\n TimeChartSeriesMapping,\n getFormattedMultipleYAxes,\n DEFAULT_LEGEND,\n StepOptions,\n formatValue,\n getTimeSeriesValues,\n} from '@perses-dev/components';\nimport { TimeSeries, TimeSeriesData, TimeSeriesValueTuple } from '@perses-dev/spec';\nimport { useAnnotationsWithData } from '@perses-dev/dashboards';\nimport {\n TimeSeriesChartOptions,\n DEFAULT_FORMAT,\n DEFAULT_VISUAL,\n THRESHOLD_PLOT_INTERVAL,\n QuerySettingsOptions,\n} from './time-series-chart-model';\nimport {\n getTimeSeries,\n getCommonTimeScaleForQueries,\n convertPanelYAxis,\n getThresholdSeries,\n convertPercentThreshold,\n} from './utils/data-transform';\nimport { getSeriesColor } from './utils/palette-gen';\nimport { TimeSeriesChartBase } from './TimeSeriesChartBase';\nimport { convertAnnotationToTimeSeriesAnnotation, TimeSeriesAnnotation } from './utils/annotation';\n\nexport type TimeSeriesChartProps = PanelProps<TimeSeriesChartOptions, TimeSeriesData>;\n\n// Using an \"ALL\" value to handle the case on first loading the chart where we\n// want to select all, but do not want all of the legend items to be visually highlighted.\n// This helps us differentiate those cases more clearly instead of inferring it\n// based on the state of the data. This also helps us avoid some coding\n// complexity around initializing a full record for the initial load that would\n// currently require significantly more refactoring of this component.\n// TODO: simplify this if we switch the list-based legend UI to use checkboxes,\n// where we *would* want to visually select all items in this case.\n\nexport function TimeSeriesChartPanel(props: TimeSeriesChartProps): ReactElement | null {\n const {\n spec: { thresholds, yAxis, tooltip, querySettings: querySettingsList },\n contentDimensions,\n queryResults,\n } = props;\n const chartsTheme = useChartsTheme();\n const muiTheme = useTheme();\n const chartId = useId('time-series-panel');\n\n const chartRef = useRef<ChartInstance>(null);\n\n // ECharts theme comes from ChartsProvider, more info: https://echarts.apache.org/en/option.html#color\n // Colors are manually applied since our legend and tooltip are built custom with React.\n const categoricalPalette = chartsTheme.echartsTheme.color;\n\n // TODO: consider refactoring how the layout/spacing/alignment are calculated\n // the next time significant changes are made to the time series panel (e.g.\n // when making improvements to the legend to more closely match designs).\n // This may also want to include moving some of this logic down to the shared,\n // embeddable components.\n const contentPadding = chartsTheme.container.padding.default;\n const adjustedContentDimensions: typeof contentDimensions = contentDimensions\n ? {\n width: contentDimensions.width - contentPadding * 2,\n height: contentDimensions.height - contentPadding * 2,\n }\n : undefined;\n\n // populate default 'position' and other future properties\n const legend = useMemo(() => {\n return props.spec.legend && validateLegendSpec(props.spec.legend)\n ? merge({}, DEFAULT_LEGEND, props.spec.legend)\n : undefined;\n }, [props.spec.legend]);\n\n // TODO: add support for y_axis_alt.format\n const format = props.spec.yAxis?.format ?? DEFAULT_FORMAT;\n\n // ensures there are fallbacks for unset properties since most\n // users should not need to customize visual display\n const visual = useMemo(() => {\n return merge({}, DEFAULT_VISUAL, props.spec.visual);\n }, [props.spec.visual]);\n\n // convert Perses dashboard format to be ECharts compatible\n const echartsYAxis = useMemo(() => {\n return convertPanelYAxis(yAxis);\n }, [yAxis]);\n\n // Collect unique formats from query settings that differ from the base format\n // These will create additional Y axes on the right side\n const { additionalFormats, formatToYAxisIndex, seriesFormatMap } = useMemo(() => {\n const baseUnit = format?.unit ?? 'decimal';\n const additionalFormats: Array<typeof format> = [];\n const formatToYAxisIndex = new Map<string, number>();\n const seriesFormatMap = new Map<string, typeof format>();\n\n // Index 0 is reserved for the base Y axis\n formatToYAxisIndex.set(baseUnit, 0);\n\n // Collect unique formats from query settings\n for (const qs of querySettingsList ?? []) {\n if (qs.format?.unit && qs.format.unit !== baseUnit) {\n const unitKey = qs.format.unit;\n if (!formatToYAxisIndex.has(unitKey)) {\n // Add new format - index is 1 + position in additionalFormats array\n formatToYAxisIndex.set(unitKey, 1 + additionalFormats.length);\n additionalFormats.push(qs.format);\n }\n }\n }\n\n return { additionalFormats, formatToYAxisIndex, seriesFormatMap };\n }, [format, querySettingsList]);\n\n const [selectedLegendItems, setSelectedLegendItems] = useState<SelectedLegendItemState>('ALL');\n const [legendSorting, setLegendSorting] = useState<NonNullable<LegendProps['tableProps']>['sorting']>();\n\n const { setTimeRange } = useTimeRange();\n\n const annotationsWithData = useAnnotationsWithData();\n\n const annotations: TimeSeriesAnnotation[] = useMemo(\n () => convertAnnotationToTimeSeriesAnnotation(annotationsWithData),\n [annotationsWithData]\n );\n\n // Populate series data based on query results\n const {\n timeScale,\n timeChartData,\n timeSeriesMapping,\n legendItems,\n seriesFormatMap: computedSeriesFormatMap,\n maxValuesByFormat,\n } = useMemo(() => {\n const timeScale = getCommonTimeScaleForQueries(queryResults);\n if (timeScale === undefined) {\n return {\n timeChartData: [],\n timeSeriesMapping: [],\n seriesFormatMap: new Map(),\n maxValuesByFormat: new Map<string, number>(),\n };\n }\n\n const legendItems: LegendItem[] = [];\n\n // Utilizes ECharts dataset so raw data is separate from series option style properties\n // https://apache.github.io/echarts-handbook/en/concepts/dataset/\n const timeChartData: TimeSeries[] = [];\n const timeSeriesMapping: TimeChartSeriesMapping = [];\n\n // Track max values for each format unit (used for dynamic Y axis offset calculation)\n const maxValuesByFormat = new Map<string, number>();\n\n // Index is counted across multiple queries which ensures the categorical color palette does not reset for every query\n let seriesIndex = 0;\n\n // Mapping of each set of query results to be ECharts option compatible\n // TODO: Look into performance optimizations and moving parts of mapping to the lower level chart\n for (let queryIndex = 0; queryIndex < queryResults.length; queryIndex++) {\n const result = queryResults[queryIndex];\n\n // Retrieve querySettings for this query, if exists.\n // queries & querySettings indices do not necessarily match, so we have to check the tail value of the $ref attribute\n let querySettings: QuerySettingsOptions | undefined;\n for (const item of querySettingsList ?? []) {\n if (item.queryIndex === queryIndex) {\n querySettings = item;\n // We don't break the loop here just in case there are multiple querySettings defined for the\n // same queryIndex, because in that case we want the last one to take precedence.\n }\n }\n\n if (result) {\n for (let i = 0; i < result.data.series.length; i++) {\n const timeSeries: TimeSeries | undefined = result.data.series[i];\n if (timeSeries === undefined) {\n return { timeChartData: [], timeSeriesMapping: [], legendItems: [] };\n }\n\n // Format is determined by seriesNameFormat in query spec\n const formattedSeriesName = timeSeries.formattedName ?? timeSeries.name;\n\n // Color is used for line, tooltip, and legend\n const seriesColor = getSeriesColor({\n // ECharts type for color is not always an array but it is always an array in ChartsProvider\n categoricalPalette: categoricalPalette as string[],\n visual,\n muiPrimaryColor: muiTheme.palette.primary.main,\n seriesName: formattedSeriesName,\n seriesIndex,\n querySettings: querySettings,\n queryHasMultipleResults: (queryResults[queryIndex]?.data?.series?.length ?? 0) > 1,\n });\n\n // We add a unique id for the chart to disambiguate items across charts\n // when there are multiple on the page.\n const seriesId = chartId + timeSeries.name + seriesIndex;\n\n const legendCalculations = legend?.values\n ? getCalculations(timeSeries.values, legend.values as CalculationType[])\n : undefined;\n\n // When we initially load the chart, we want to show all series, but\n // DO NOT want to visualy highlight all the items in the legend.\n const isSelectAll = selectedLegendItems === 'ALL';\n const isSelected = !isSelectAll && !!selectedLegendItems[seriesId];\n const showTimeSeries = isSelected || isSelectAll;\n\n if (showTimeSeries) {\n // Use timeChartData.length to ensure the data that is passed into the tooltip accounts for\n // which legend items are selected. This must happen before timeChartData.push to avoid an\n // off-by-one error, seriesIndex cannot be used since it's needed to cycle through palette\n const datasetIndex = timeChartData.length;\n\n // Determine yAxisIndex based on the query's format setting\n const queryFormat = querySettings?.format;\n const yAxisIndex = queryFormat?.unit ? (formatToYAxisIndex.get(queryFormat.unit) ?? 0) : 0;\n\n // Each series is stored as a separate dataset source.\n // https://apache.github.io/echarts-handbook/en/concepts/dataset/#how-to-reference-several-datasets\n timeSeriesMapping.push(\n getTimeSeries(\n seriesId,\n datasetIndex,\n formattedSeriesName,\n visual,\n timeScale,\n seriesColor,\n querySettings,\n yAxisIndex\n )\n );\n\n // Store the format for this series for tooltip formatting\n if (queryFormat) {\n seriesFormatMap.set(seriesId, queryFormat);\n\n // Track max value for this format unit (used for dynamic Y axis offset calculation)\n const unitKey = queryFormat.unit;\n if (unitKey) {\n const seriesMax = Math.max(...timeSeries.values.map((v) => Math.abs(v[1] ?? 0)));\n const currentMax = maxValuesByFormat.get(unitKey) ?? 0;\n if (seriesMax > currentMax) {\n maxValuesByFormat.set(unitKey, seriesMax);\n }\n }\n }\n\n // When negativeY is set on this query, negate the rendered values so the\n // series renders below the X axis. The original (positive) values are\n // preserved in `timeSeries.values` (used for legend calculations) and in\n // `queryResults` (used for CSV export).\n const baseValues: TimeSeriesValueTuple[] = getTimeSeriesValues(timeSeries, timeScale);\n const renderedValues: TimeSeriesValueTuple[] = querySettings?.negativeY\n ? baseValues.map((tuple: TimeSeriesValueTuple): TimeSeriesValueTuple => {\n const [t, v] = tuple;\n return [t, v === null ? null : -v];\n })\n : baseValues;\n\n timeChartData.push({\n name: formattedSeriesName,\n values: renderedValues,\n });\n }\n\n if (legend && legendItems) {\n legendItems.push({\n id: seriesId, // Avoids duplicate key console errors when there are duplicate series names\n label: formattedSeriesName,\n color: seriesColor,\n data: legendCalculations,\n });\n }\n\n // Used for repeating colors in Categorical palette\n seriesIndex++;\n }\n }\n }\n\n // map thresholds only if there is at least one time series to avoid displaying thresholds without any data\n if (thresholds && thresholds.steps && timeChartData.length > 0) {\n // Convert how thresholds are defined in the panel spec to valid ECharts 'line' series.\n // These are styled with predefined colors and a dashed style to look different than series from query results.\n // Regular series are used instead of markLines since thresholds currently show in our React TimeSeriesTooltip.\n const thresholdsColors = chartsTheme.thresholds;\n const defaultThresholdColor = thresholds.defaultColor ?? thresholdsColors.defaultColor;\n thresholds.steps.forEach((step: StepOptions, index: number) => {\n const stepPaletteColor = thresholdsColors.palette[index] ?? defaultThresholdColor;\n const thresholdLineColor = step.color ?? stepPaletteColor;\n const stepOption: StepOptions = {\n color: thresholdLineColor,\n value:\n // yAxis is passed here since it corresponds to dashboard JSON instead of the already converted ECharts yAxis\n thresholds.mode === 'percent'\n ? convertPercentThreshold(step.value, timeChartData, yAxis?.max, yAxis?.min)\n : step.value,\n };\n const thresholdName = step.name ?? `Threshold ${index + 1}`;\n\n // Generates array of [time, step.value] where time ranges from timescale.startMs to timescale.endMs with an interval of 15s\n const thresholdTimeValueTuple: TimeSeriesValueTuple[] = [];\n let currentTimestamp = timeScale.startMs;\n while (currentTimestamp <= timeScale.endMs) {\n thresholdTimeValueTuple.push([currentTimestamp, stepOption.value]);\n // Used to plot fake thresholds datapoints so correct nearby threshold series shows in tooltip without flicker\n currentTimestamp += 1000 * THRESHOLD_PLOT_INTERVAL;\n }\n\n timeChartData.push({\n name: thresholdName,\n values: thresholdTimeValueTuple,\n });\n timeSeriesMapping.push(getThresholdSeries(thresholdName, stepOption, seriesIndex));\n seriesIndex++;\n });\n }\n\n return {\n timeScale,\n timeChartData,\n timeSeriesMapping,\n legendItems,\n seriesFormatMap,\n maxValuesByFormat,\n };\n }, [\n queryResults,\n thresholds,\n selectedLegendItems,\n legend,\n visual,\n querySettingsList,\n yAxis?.max,\n yAxis?.min,\n categoricalPalette,\n chartId,\n chartsTheme.thresholds,\n muiTheme.palette.primary.main,\n formatToYAxisIndex,\n seriesFormatMap,\n ]);\n\n // Create multiple Y axes if there are additional formats\n // Uses max values from data to compute dynamic offsets that adapt to label widths\n const multipleYAxes = useMemo(() => {\n if (additionalFormats.length === 0) {\n return undefined; // Use single Y axis (default behavior)\n }\n // Build array of max values for each additional format (in order)\n const maxValues = additionalFormats.map((fmt) => {\n const unitKey = fmt.unit;\n return unitKey ? (maxValuesByFormat?.get(unitKey) ?? 1000) : 1000;\n });\n return getFormattedMultipleYAxes(echartsYAxis, format, additionalFormats, maxValues);\n }, [echartsYAxis, format, additionalFormats, maxValuesByFormat]);\n\n // Translate the legend values into columns for the table legend.\n const legendColumns = useMemo(() => {\n if (!legend?.values) {\n return [];\n }\n\n // Iterating the predefined list of possible values to retain a specific\n // intended order of values.\n return legendValues.reduce(\n (columns, legendValue) => {\n const legendConfig = LEGEND_VALUE_CONFIG[legendValue];\n\n if (legendConfig && legend?.values?.includes(legendValue)) {\n columns.push({\n accessorKey: `data.${legendValue}`,\n header: legendConfig.label,\n headerDescription: legendConfig.description,\n // Intentionally hardcoding a column width to start based on discussions\n // with design around keeping this simple to start. This may need\n // revisiting in the future to handle edge cases with very large values.\n width: 72,\n align: 'right',\n cell: ({ getValue }) => {\n const cellValue = getValue();\n return typeof cellValue === 'number' && format ? formatValue(cellValue, format) : cellValue;\n },\n cellDescription: true,\n enableSorting: true,\n });\n }\n\n return columns;\n },\n [] as Array<TableColumnConfig<LegendItem>>\n );\n }, [legend?.values, format]);\n\n const gridOverrides: GridComponentOption = useMemo(() => {\n // When Y axes are hidden, disable containLabel to prevent auto-spacing, but add bottom padding for X axis\n return echartsYAxis.show === false\n ? {\n left: 0,\n right: 0,\n bottom: 30,\n containLabel: false,\n }\n : {\n left: yAxis && yAxis.label ? 30 : 20,\n // With containLabel: true in theme, ECharts auto-reserves space for axis labels.\n // For multiple right axes, add extra padding for the last axis labels that extend beyond the grid.\n right: additionalFormats.length > 0 ? 10 : 20,\n bottom: 0,\n containLabel: true,\n };\n }, [echartsYAxis.show, yAxis, additionalFormats.length]);\n\n if (adjustedContentDimensions === undefined) {\n return null;\n }\n\n const handleDataZoom = (event: ZoomEventData): void => {\n // TODO: add ECharts transition animation on zoom\n setTimeRange({ start: new Date(event.start), end: new Date(event.end) });\n };\n\n // Used to opt in to ECharts trigger item which show subgroup data accurately.\n // Derived from the actual series mapping rather than `visual.stack` alone so that\n // bar charts stacked only via per-query overrides also use the right tooltip mode.\n const isStackedBar =\n visual.display === 'bar' && timeSeriesMapping.some((s) => s?.type === 'bar' && s.stack === 'all');\n\n // Turn on tooltip pinning by default but opt out for stacked bar or if explicitly set in tooltip panel spec\n let enablePinning = true;\n if (isStackedBar) {\n enablePinning = false;\n } else if (tooltip?.enablePinning !== undefined) {\n enablePinning = tooltip.enablePinning;\n }\n const tooltipConfig: TooltipConfig = {\n ...DEFAULT_TOOLTIP_CONFIG,\n enablePinning,\n };\n\n return (\n <Box sx={{ padding: `${contentPadding}px` }}>\n <ContentWithLegend\n width={adjustedContentDimensions.width}\n height={adjustedContentDimensions.height}\n // Making this small enough that the medium size doesn't get\n // responsive-handling-ed away when in the panel options editor.\n minChildrenHeight={50}\n legendSize={legend?.size}\n legendProps={\n legend && {\n options: legend,\n data: legendItems || [],\n selectedItems: selectedLegendItems,\n onSelectedItemsChange: setSelectedLegendItems,\n tableProps: {\n columns: legendColumns,\n sorting: legendSorting,\n onSortingChange: setLegendSorting,\n },\n onItemMouseOver: (e, { id }): void => {\n chartRef.current?.highlightSeries({ name: id });\n },\n onItemMouseOut: (): void => {\n chartRef.current?.clearHighlightedSeries();\n },\n }\n }\n >\n {({ height, width }) => {\n return (\n <Box style={{ height, width }}>\n {yAxis && yAxis.show && yAxis.label && <YAxisLabel name={yAxis.label} height={height} />}\n <TimeSeriesChartBase\n ref={chartRef}\n height={height}\n data={timeChartData}\n seriesMapping={timeSeriesMapping}\n annotations={annotations}\n timeScale={timeScale}\n yAxis={multipleYAxes ?? echartsYAxis}\n format={format}\n seriesFormatMap={computedSeriesFormatMap}\n grid={gridOverrides}\n isStackedBar={isStackedBar}\n tooltipConfig={tooltipConfig}\n syncGroup=\"default-panel-group\" // TODO: make configurable from dashboard settings and per panel-group overrides\n onDataZoom={handleDataZoom}\n // Show an empty chart when there is no data because the user unselected all items in\n // the legend. Otherwise, show a \"no data\" message.\n noDataVariant={!timeChartData.length && legendItems && legendItems.length > 0 ? 'chart' : 'message'}\n />\n </Box>\n );\n }}\n </ContentWithLegend>\n </Box>\n );\n}\n"],"names":["useMemo","useRef","useState","Box","useTheme","merge","LEGEND_VALUE_CONFIG","useTimeRange","validateLegendSpec","legendValues","getCalculations","YAxisLabel","useChartsTheme","ContentWithLegend","useId","DEFAULT_TOOLTIP_CONFIG","getFormattedMultipleYAxes","DEFAULT_LEGEND","formatValue","getTimeSeriesValues","useAnnotationsWithData","DEFAULT_FORMAT","DEFAULT_VISUAL","THRESHOLD_PLOT_INTERVAL","getTimeSeries","getCommonTimeScaleForQueries","convertPanelYAxis","getThresholdSeries","convertPercentThreshold","getSeriesColor","TimeSeriesChartBase","convertAnnotationToTimeSeriesAnnotation","TimeSeriesChartPanel","props","spec","thresholds","yAxis","tooltip","querySettings","querySettingsList","contentDimensions","queryResults","chartsTheme","muiTheme","chartId","chartRef","categoricalPalette","echartsTheme","color","contentPadding","container","padding","default","adjustedContentDimensions","width","height","undefined","legend","format","visual","echartsYAxis","additionalFormats","formatToYAxisIndex","seriesFormatMap","baseUnit","unit","Map","set","qs","unitKey","has","length","push","selectedLegendItems","setSelectedLegendItems","legendSorting","setLegendSorting","setTimeRange","annotationsWithData","annotations","timeScale","timeChartData","timeSeriesMapping","legendItems","computedSeriesFormatMap","maxValuesByFormat","seriesIndex","queryIndex","result","item","i","data","series","timeSeries","formattedSeriesName","formattedName","name","seriesColor","muiPrimaryColor","palette","primary","main","seriesName","queryHasMultipleResults","seriesId","legendCalculations","values","isSelectAll","isSelected","showTimeSeries","datasetIndex","queryFormat","yAxisIndex","get","seriesMax","Math","max","map","v","abs","currentMax","baseValues","renderedValues","negativeY","tuple","t","id","label","steps","thresholdsColors","defaultThresholdColor","defaultColor","forEach","step","index","stepPaletteColor","thresholdLineColor","stepOption","value","mode","min","thresholdName","thresholdTimeValueTuple","currentTimestamp","startMs","endMs","multipleYAxes","maxValues","fmt","legendColumns","reduce","columns","legendValue","legendConfig","includes","accessorKey","header","headerDescription","description","align","cell","getValue","cellValue","cellDescription","enableSorting","gridOverrides","show","left","right","bottom","containLabel","handleDataZoom","event","start","Date","end","isStackedBar","display","some","s","type","stack","enablePinning","tooltipConfig","sx","minChildrenHeight","legendSize","size","legendProps","options","selectedItems","onSelectedItemsChange","tableProps","sorting","onSortingChange","onItemMouseOver","e","current","highlightSeries","onItemMouseOut","clearHighlightedSeries","style","ref","seriesMapping","grid","syncGroup","onDataZoom","noDataVariant"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/VisualOptionsEditor.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { produce } from 'immer';\nimport { Slider, Switch, ToggleButton, ToggleButtonGroup } from '@mui/material';\nimport { OptionsEditorControl, OptionsEditorGroup, SettingsAutocomplete } from '@perses-dev/components';\nimport { ReactElement } from 'react';\nimport {\n DEFAULT_AREA_OPACITY,\n DEFAULT_CONNECT_NULLS,\n DEFAULT_LINE_WIDTH,\n DEFAULT_LINE_STYLE,\n DEFAULT_POINT_RADIUS,\n POINT_SIZE_OFFSET,\n STACK_CONFIG,\n StackOptions,\n STACK_OPTIONS,\n LINE_STYLE_CONFIG,\n VISUAL_CONFIG,\n TimeSeriesChartVisualOptions,\n DEFAULT_DISPLAY,\n} from './time-series-chart-model';\n\nexport interface VisualOptionsEditorProps {\n value: TimeSeriesChartVisualOptions;\n onChange: (visual: TimeSeriesChartVisualOptions) => void;\n}\n\nexport function VisualOptionsEditor({ value, onChange }: VisualOptionsEditorProps): ReactElement {\n const handleLineWidthChange = (_: Event, sliderValue: number | number[]): void => {\n const newValue = Array.isArray(sliderValue) ? sliderValue[0] : sliderValue;\n const symbolSize = newValue !== undefined ? newValue + POINT_SIZE_OFFSET : DEFAULT_POINT_RADIUS;\n onChange(\n produce(value, (draft) => {\n draft.lineWidth = newValue;\n draft.pointRadius = symbolSize;\n })\n );\n };\n\n const handleAreaOpacityChange = (_: Event, sliderValue: number | number[]): void => {\n const newValue = Array.isArray(sliderValue) ? sliderValue[0] : sliderValue;\n onChange(\n produce(value, (draft) => {\n draft.areaOpacity = newValue;\n })\n );\n };\n\n const currentStack: StackOptions = value.stack ?? 'none';\n const stackConfig = STACK_CONFIG[currentStack];\n\n return (\n <OptionsEditorGroup title=\"Visual\">\n <OptionsEditorControl\n label={VISUAL_CONFIG.stack.label}\n control={\n <SettingsAutocomplete\n value={{\n ...stackConfig,\n id: currentStack,\n }}\n options={STACK_OPTIONS}\n onChange={(__, newValue) => {\n const updatedValue: TimeSeriesChartVisualOptions = {\n ...value,\n stack: newValue.id === 'none' ? undefined : newValue.id, // stack is optional so remove property when 'None' is selected\n };\n // stacked area chart preset to automatically set area under a curve shading\n if (newValue.id === 'all' && !value.areaOpacity) {\n updatedValue.areaOpacity = 0.3;\n }\n onChange(updatedValue);\n }}\n disabled={value === undefined}\n disableClearable\n ></SettingsAutocomplete>\n }\n />\n <OptionsEditorControl\n label=\"Display\"\n control={\n <ToggleButtonGroup\n color=\"primary\"\n exclusive\n value={value.display ?? DEFAULT_DISPLAY}\n onChange={(__, newValue) => {\n onChange({\n ...value,\n display: newValue,\n });\n }}\n >\n <ToggleButton\n value=\"line\"\n selected={value.display === undefined || value.display === 'line'}\n aria-label=\"display line series\"\n >\n Line\n </ToggleButton>\n <ToggleButton value=\"bar\" aria-label=\"display bar series\">\n Bar\n </ToggleButton>\n </ToggleButtonGroup>\n }\n />\n {value.display === 'line' && (\n <>\n <OptionsEditorControl\n label={VISUAL_CONFIG.lineWidth.label}\n control={\n <Slider\n data-testid={VISUAL_CONFIG.lineWidth.testId}\n value={value.lineWidth ?? DEFAULT_LINE_WIDTH}\n valueLabelDisplay=\"auto\"\n step={VISUAL_CONFIG.lineWidth.step}\n marks\n min={VISUAL_CONFIG.lineWidth.min}\n max={VISUAL_CONFIG.lineWidth.max}\n onChange={handleLineWidthChange}\n />\n }\n />\n <OptionsEditorControl\n label={VISUAL_CONFIG.lineStyle.label}\n control={\n <ToggleButtonGroup\n color=\"primary\"\n exclusive\n value={value.lineStyle ?? DEFAULT_LINE_STYLE}\n onChange={(__, newValue) => {\n onChange({\n ...value,\n lineStyle: newValue,\n });\n }}\n >\n {Object.entries(LINE_STYLE_CONFIG).map(([styleValue, config]) => (\n <ToggleButton key={styleValue} value={styleValue} aria-label={`${styleValue} line style`}>\n {config.label}\n </ToggleButton>\n ))}\n </ToggleButtonGroup>\n }\n />\n <OptionsEditorControl\n label={VISUAL_CONFIG.areaOpacity.label}\n control={\n <Slider\n data-testid={VISUAL_CONFIG.areaOpacity.testId}\n value={value.areaOpacity ?? DEFAULT_AREA_OPACITY}\n valueLabelDisplay=\"auto\"\n step={VISUAL_CONFIG.areaOpacity.step}\n marks\n min={VISUAL_CONFIG.areaOpacity.min}\n max={VISUAL_CONFIG.areaOpacity.max}\n onChange={handleAreaOpacityChange}\n />\n }\n />\n <OptionsEditorControl\n label={VISUAL_CONFIG.connectNulls.label}\n control={\n <Switch\n checked={value.connectNulls ?? DEFAULT_CONNECT_NULLS}\n onChange={(e) => {\n onChange({\n ...value,\n connectNulls: e.target.checked,\n });\n }}\n />\n }\n />\n </>\n )}\n </OptionsEditorGroup>\n );\n}\n"],"names":["produce","Slider","Switch","ToggleButton","ToggleButtonGroup","OptionsEditorControl","OptionsEditorGroup","SettingsAutocomplete","DEFAULT_AREA_OPACITY","DEFAULT_CONNECT_NULLS","DEFAULT_LINE_WIDTH","DEFAULT_LINE_STYLE","DEFAULT_POINT_RADIUS","POINT_SIZE_OFFSET","STACK_CONFIG","STACK_OPTIONS","LINE_STYLE_CONFIG","VISUAL_CONFIG","DEFAULT_DISPLAY","VisualOptionsEditor","value","onChange","handleLineWidthChange","_","sliderValue","newValue","Array","isArray","symbolSize","undefined","draft","lineWidth","pointRadius","handleAreaOpacityChange","areaOpacity","currentStack","stack","stackConfig","title","label","control","id","options","__","updatedValue","disabled","disableClearable","color","exclusive","display","selected","aria-label","data-testid","testId","valueLabelDisplay","step","marks","min","max","lineStyle","Object","entries","map","styleValue","config","connectNulls","checked","e","target"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/VisualOptionsEditor.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { produce } from 'immer';\nimport { Slider, Switch, ToggleButton, ToggleButtonGroup } from '@mui/material';\nimport { OptionsEditorControl, OptionsEditorGroup, SettingsAutocomplete } from '@perses-dev/components';\nimport { ReactElement } from 'react';\nimport {\n DEFAULT_AREA_OPACITY,\n DEFAULT_CONNECT_NULLS,\n DEFAULT_LINE_WIDTH,\n DEFAULT_LINE_STYLE,\n DEFAULT_POINT_RADIUS,\n POINT_SIZE_OFFSET,\n STACK_CONFIG,\n StackOptions,\n STACK_OPTIONS,\n LINE_STYLE_CONFIG,\n VISUAL_CONFIG,\n TimeSeriesChartVisualOptions,\n DEFAULT_DISPLAY,\n} from './time-series-chart-model';\n\nexport interface VisualOptionsEditorProps {\n value: TimeSeriesChartVisualOptions;\n onChange: (visual: TimeSeriesChartVisualOptions) => void;\n}\n\nexport function VisualOptionsEditor({ value, onChange }: VisualOptionsEditorProps): ReactElement {\n const handleLineWidthChange = (_: Event, sliderValue: number | number[]): void => {\n const newValue = Array.isArray(sliderValue) ? sliderValue[0] : sliderValue;\n const symbolSize = newValue !== undefined ? newValue + POINT_SIZE_OFFSET : DEFAULT_POINT_RADIUS;\n onChange(\n produce(value, (draft) => {\n draft.lineWidth = newValue;\n draft.pointRadius = symbolSize;\n })\n );\n };\n\n const handleAreaOpacityChange = (_: Event, sliderValue: number | number[]): void => {\n const newValue = Array.isArray(sliderValue) ? sliderValue[0] : sliderValue;\n onChange(\n produce(value, (draft) => {\n draft.areaOpacity = newValue;\n })\n );\n };\n\n const currentStack: StackOptions = value.stack ?? 'none';\n const stackConfig = STACK_CONFIG[currentStack];\n\n return (\n <OptionsEditorGroup title=\"Visual\">\n <OptionsEditorControl\n label={VISUAL_CONFIG.stack.label}\n control={\n <SettingsAutocomplete\n value={{\n ...stackConfig,\n id: currentStack,\n }}\n options={STACK_OPTIONS}\n onChange={(__, newValue) => {\n const updatedValue: TimeSeriesChartVisualOptions = {\n ...value,\n stack: newValue.id === 'none' ? undefined : newValue.id,\n };\n // stacked area chart preset to automatically set area under a curve shading\n if (newValue.id === 'all' && !value.areaOpacity) {\n updatedValue.areaOpacity = 0.3;\n }\n onChange(updatedValue);\n }}\n disabled={value === undefined}\n disableClearable\n ></SettingsAutocomplete>\n }\n />\n <OptionsEditorControl\n label=\"Display\"\n control={\n <ToggleButtonGroup\n color=\"primary\"\n exclusive\n value={value.display ?? DEFAULT_DISPLAY}\n onChange={(__, newValue) => {\n onChange({\n ...value,\n display: newValue,\n });\n }}\n >\n <ToggleButton\n value=\"line\"\n selected={value.display === undefined || value.display === 'line'}\n aria-label=\"display line series\"\n >\n Line\n </ToggleButton>\n <ToggleButton value=\"bar\" aria-label=\"display bar series\">\n Bar\n </ToggleButton>\n </ToggleButtonGroup>\n }\n />\n {value.display === 'line' && (\n <>\n <OptionsEditorControl\n label={VISUAL_CONFIG.lineWidth.label}\n control={\n <Slider\n data-testid={VISUAL_CONFIG.lineWidth.testId}\n value={value.lineWidth ?? DEFAULT_LINE_WIDTH}\n valueLabelDisplay=\"auto\"\n step={VISUAL_CONFIG.lineWidth.step}\n marks\n min={VISUAL_CONFIG.lineWidth.min}\n max={VISUAL_CONFIG.lineWidth.max}\n onChange={handleLineWidthChange}\n />\n }\n />\n <OptionsEditorControl\n label={VISUAL_CONFIG.lineStyle.label}\n control={\n <ToggleButtonGroup\n color=\"primary\"\n exclusive\n value={value.lineStyle ?? DEFAULT_LINE_STYLE}\n onChange={(__, newValue) => {\n onChange({\n ...value,\n lineStyle: newValue,\n });\n }}\n >\n {Object.entries(LINE_STYLE_CONFIG).map(([styleValue, config]) => (\n <ToggleButton key={styleValue} value={styleValue} aria-label={`${styleValue} line style`}>\n {config.label}\n </ToggleButton>\n ))}\n </ToggleButtonGroup>\n }\n />\n <OptionsEditorControl\n label={VISUAL_CONFIG.areaOpacity.label}\n control={\n <Slider\n data-testid={VISUAL_CONFIG.areaOpacity.testId}\n value={value.areaOpacity ?? DEFAULT_AREA_OPACITY}\n valueLabelDisplay=\"auto\"\n step={VISUAL_CONFIG.areaOpacity.step}\n marks\n min={VISUAL_CONFIG.areaOpacity.min}\n max={VISUAL_CONFIG.areaOpacity.max}\n onChange={handleAreaOpacityChange}\n />\n }\n />\n <OptionsEditorControl\n label={VISUAL_CONFIG.connectNulls.label}\n control={\n <Switch\n checked={value.connectNulls ?? DEFAULT_CONNECT_NULLS}\n onChange={(e) => {\n onChange({\n ...value,\n connectNulls: e.target.checked,\n });\n }}\n />\n }\n />\n </>\n )}\n </OptionsEditorGroup>\n );\n}\n"],"names":["produce","Slider","Switch","ToggleButton","ToggleButtonGroup","OptionsEditorControl","OptionsEditorGroup","SettingsAutocomplete","DEFAULT_AREA_OPACITY","DEFAULT_CONNECT_NULLS","DEFAULT_LINE_WIDTH","DEFAULT_LINE_STYLE","DEFAULT_POINT_RADIUS","POINT_SIZE_OFFSET","STACK_CONFIG","STACK_OPTIONS","LINE_STYLE_CONFIG","VISUAL_CONFIG","DEFAULT_DISPLAY","VisualOptionsEditor","value","onChange","handleLineWidthChange","_","sliderValue","newValue","Array","isArray","symbolSize","undefined","draft","lineWidth","pointRadius","handleAreaOpacityChange","areaOpacity","currentStack","stack","stackConfig","title","label","control","id","options","__","updatedValue","disabled","disableClearable","color","exclusive","display","selected","aria-label","data-testid","testId","valueLabelDisplay","step","marks","min","max","lineStyle","Object","entries","map","styleValue","config","connectNulls","checked","e","target"],"mappings":"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"}