@perses-dev/components 0.55.0-beta.6 → 0.55.0-beta.7

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.
@@ -15,14 +15,14 @@ const DEFAULT_ACTIVE_CELL = {
15
15
  row: 0,
16
16
  column: 0
17
17
  };
18
- const ARROW_KEYS = [
18
+ const ARROW_KEYS = new Set([
19
19
  'ArrowRight',
20
20
  'ArrowLeft',
21
21
  'ArrowUp',
22
22
  'ArrowDown'
23
- ];
23
+ ]);
24
24
  function isArrowKey(key) {
25
- return ARROW_KEYS.includes(key);
25
+ return ARROW_KEYS.has(key);
26
26
  }
27
27
  /**
28
28
  * Hook for managing keyboard navigation for table components. It is intended
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/Table/hooks/useTableKeyboardNav.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 type { FocusEventHandler, KeyboardEventHandler } from 'react';\nimport { useCallback, useState } from 'react';\n\nexport interface UseTableKeyboardNavProps {\n maxRows: number;\n maxColumns: number;\n\n /**\n * Function used to modify the active table cell based on the keyboard event,\n * the current position, and the default recommended next position (this value\n * will be `undefined` in cases where there is no default handler like `PageUp`\n * and `PageDown`). This can be used to modify the next position that will be\n * used and/or to handle side effects related to the new position (e.g.\n * pagination, scrolling the active cell into view).\n */\n onActiveCellChange?: (\n e: React.KeyboardEvent<HTMLTableElement>,\n currentActiveCell: TableCellPosition,\n defaultNextActiveCell: TableCellPosition | undefined,\n ) => TableCellPosition | undefined;\n}\n\ntype TableCellPosition = {\n row: number;\n column: number;\n};\n\nconst DEFAULT_ACTIVE_CELL: TableCellPosition = {\n row: 0,\n column: 0,\n};\n\nconst ARROW_KEYS = ['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'];\n\nfunction isArrowKey(key: string): boolean {\n return ARROW_KEYS.includes(key);\n}\n\n/**\n * Hook for managing keyboard navigation for table components. It is intended\n * to be wrapped by implementation-specific tables to account for differences\n * like pagination, infinite scroll, and virtualization. See `useVirtualizedKeyboardNav`\n * for an example.\n */\nexport function useTableKeyboardNav({ maxRows, maxColumns, onActiveCellChange }: UseTableKeyboardNavProps): {\n activeCell: TableCellPosition;\n isActive: boolean;\n onTableKeyDown: KeyboardEventHandler<HTMLTableElement>;\n onCellFocus: (cellPosition: TableCellPosition) => void;\n onTableBlur: FocusEventHandler<HTMLTableElement>;\n} {\n const [activeCell, setActiveCell] = useState<TableCellPosition>(DEFAULT_ACTIVE_CELL);\n const [isActive, setIsActive] = useState(false);\n\n const handleCellFocus = (cellPosition: TableCellPosition): void => {\n if (cellPosition.column === activeCell.column && cellPosition.row === activeCell.row && isActive) {\n return;\n }\n setIsActive(true);\n setActiveCell(cellPosition);\n };\n\n const handleKeyDown: React.KeyboardEventHandler<HTMLTableElement> = useCallback(\n (e) => {\n // Including some of the basic a11y keyboard interaction patterns from:\n // https://www.w3.org/WAI/ARIA/apg/patterns/grid/\n // TODO: add other keyboard combos.\n const key = e.key;\n\n if (isArrowKey(key) || key === 'Home' || key === 'End' || key === 'PageDown' || key === 'PageUp') {\n setActiveCell((curActiveCell) => {\n let nextRow: number = curActiveCell.row;\n let nextColumn: number = curActiveCell.column;\n\n if (key === 'ArrowRight' && nextColumn < maxColumns - 1) {\n e.preventDefault();\n nextColumn += 1;\n } else if (key === 'ArrowLeft' && nextColumn > 0) {\n e.preventDefault();\n nextColumn -= 1;\n } else if (key === 'ArrowDown' && nextRow < maxRows - 1) {\n e.preventDefault();\n nextRow += 1;\n } else if (key === 'ArrowUp' && nextRow > 0) {\n e.preventDefault();\n nextRow -= 1;\n } else if (key === 'Home') {\n e.preventDefault();\n nextRow = 0;\n nextColumn = 0;\n } else if (key === 'End') {\n e.preventDefault();\n nextRow = maxRows - 1;\n nextColumn = maxColumns - 1;\n }\n\n const defaultNewPosition = { column: nextColumn, row: nextRow };\n\n const newPosition = onActiveCellChange?.(e, curActiveCell, defaultNewPosition) || defaultNewPosition;\n\n if (newPosition.row === curActiveCell.row && newPosition.column === curActiveCell.column) {\n // Return original to avoid creating a new object if nothing\n // changed.\n return curActiveCell;\n }\n\n return newPosition;\n });\n }\n },\n [maxColumns, maxRows, onActiveCellChange],\n );\n\n const handleTableBlur: FocusEventHandler<HTMLTableElement> = useCallback((e) => {\n if (!e.currentTarget.contains(e.relatedTarget as Node)) {\n setIsActive(false);\n setActiveCell(DEFAULT_ACTIVE_CELL);\n }\n }, []);\n\n return {\n activeCell,\n isActive,\n onTableKeyDown: handleKeyDown,\n onCellFocus: handleCellFocus,\n onTableBlur: handleTableBlur,\n };\n}\n"],"names":["useCallback","useState","DEFAULT_ACTIVE_CELL","row","column","ARROW_KEYS","isArrowKey","key","includes","useTableKeyboardNav","maxRows","maxColumns","onActiveCellChange","activeCell","setActiveCell","isActive","setIsActive","handleCellFocus","cellPosition","handleKeyDown","e","curActiveCell","nextRow","nextColumn","preventDefault","defaultNewPosition","newPosition","handleTableBlur","currentTarget","contains","relatedTarget","onTableKeyDown","onCellFocus","onTableBlur"],"mappings":"AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAGjC,SAASA,WAAW,EAAEC,QAAQ,QAAQ,QAAQ;AA0B9C,MAAMC,sBAAyC;IAC7CC,KAAK;IACLC,QAAQ;AACV;AAEA,MAAMC,aAAa;IAAC;IAAc;IAAa;IAAW;CAAY;AAEtE,SAASC,WAAWC,GAAW;IAC7B,OAAOF,WAAWG,QAAQ,CAACD;AAC7B;AAEA;;;;;CAKC,GACD,OAAO,SAASE,oBAAoB,EAAEC,OAAO,EAAEC,UAAU,EAAEC,kBAAkB,EAA4B;IAOvG,MAAM,CAACC,YAAYC,cAAc,GAAGb,SAA4BC;IAChE,MAAM,CAACa,UAAUC,YAAY,GAAGf,SAAS;IAEzC,MAAMgB,kBAAkB,CAACC;QACvB,IAAIA,aAAad,MAAM,KAAKS,WAAWT,MAAM,IAAIc,aAAaf,GAAG,KAAKU,WAAWV,GAAG,IAAIY,UAAU;YAChG;QACF;QACAC,YAAY;QACZF,cAAcI;IAChB;IAEA,MAAMC,gBAA8DnB,YAClE,CAACoB;QACC,uEAAuE;QACvE,iDAAiD;QACjD,mCAAmC;QACnC,MAAMb,MAAMa,EAAEb,GAAG;QAEjB,IAAID,WAAWC,QAAQA,QAAQ,UAAUA,QAAQ,SAASA,QAAQ,cAAcA,QAAQ,UAAU;YAChGO,cAAc,CAACO;gBACb,IAAIC,UAAkBD,cAAclB,GAAG;gBACvC,IAAIoB,aAAqBF,cAAcjB,MAAM;gBAE7C,IAAIG,QAAQ,gBAAgBgB,aAAaZ,aAAa,GAAG;oBACvDS,EAAEI,cAAc;oBAChBD,cAAc;gBAChB,OAAO,IAAIhB,QAAQ,eAAegB,aAAa,GAAG;oBAChDH,EAAEI,cAAc;oBAChBD,cAAc;gBAChB,OAAO,IAAIhB,QAAQ,eAAee,UAAUZ,UAAU,GAAG;oBACvDU,EAAEI,cAAc;oBAChBF,WAAW;gBACb,OAAO,IAAIf,QAAQ,aAAae,UAAU,GAAG;oBAC3CF,EAAEI,cAAc;oBAChBF,WAAW;gBACb,OAAO,IAAIf,QAAQ,QAAQ;oBACzBa,EAAEI,cAAc;oBAChBF,UAAU;oBACVC,aAAa;gBACf,OAAO,IAAIhB,QAAQ,OAAO;oBACxBa,EAAEI,cAAc;oBAChBF,UAAUZ,UAAU;oBACpBa,aAAaZ,aAAa;gBAC5B;gBAEA,MAAMc,qBAAqB;oBAAErB,QAAQmB;oBAAYpB,KAAKmB;gBAAQ;gBAE9D,MAAMI,cAAcd,qBAAqBQ,GAAGC,eAAeI,uBAAuBA;gBAElF,IAAIC,YAAYvB,GAAG,KAAKkB,cAAclB,GAAG,IAAIuB,YAAYtB,MAAM,KAAKiB,cAAcjB,MAAM,EAAE;oBACxF,4DAA4D;oBAC5D,WAAW;oBACX,OAAOiB;gBACT;gBAEA,OAAOK;YACT;QACF;IACF,GACA;QAACf;QAAYD;QAASE;KAAmB;IAG3C,MAAMe,kBAAuD3B,YAAY,CAACoB;QACxE,IAAI,CAACA,EAAEQ,aAAa,CAACC,QAAQ,CAACT,EAAEU,aAAa,GAAW;YACtDd,YAAY;YACZF,cAAcZ;QAChB;IACF,GAAG,EAAE;IAEL,OAAO;QACLW;QACAE;QACAgB,gBAAgBZ;QAChBa,aAAaf;QACbgB,aAAaN;IACf;AACF"}
1
+ {"version":3,"sources":["../../../src/Table/hooks/useTableKeyboardNav.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 type { FocusEventHandler, KeyboardEventHandler } from 'react';\nimport { useCallback, useState } from 'react';\n\nexport interface UseTableKeyboardNavProps {\n maxRows: number;\n maxColumns: number;\n\n /**\n * Function used to modify the active table cell based on the keyboard event,\n * the current position, and the default recommended next position (this value\n * will be `undefined` in cases where there is no default handler like `PageUp`\n * and `PageDown`). This can be used to modify the next position that will be\n * used and/or to handle side effects related to the new position (e.g.\n * pagination, scrolling the active cell into view).\n */\n onActiveCellChange?: (\n e: React.KeyboardEvent<HTMLTableElement>,\n currentActiveCell: TableCellPosition,\n defaultNextActiveCell: TableCellPosition | undefined,\n ) => TableCellPosition | undefined;\n}\n\ntype TableCellPosition = {\n row: number;\n column: number;\n};\n\nconst DEFAULT_ACTIVE_CELL: TableCellPosition = {\n row: 0,\n column: 0,\n};\n\nconst ARROW_KEYS = new Set(['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown']);\n\nfunction isArrowKey(key: string): boolean {\n return ARROW_KEYS.has(key);\n}\n\n/**\n * Hook for managing keyboard navigation for table components. It is intended\n * to be wrapped by implementation-specific tables to account for differences\n * like pagination, infinite scroll, and virtualization. See `useVirtualizedKeyboardNav`\n * for an example.\n */\nexport function useTableKeyboardNav({ maxRows, maxColumns, onActiveCellChange }: UseTableKeyboardNavProps): {\n activeCell: TableCellPosition;\n isActive: boolean;\n onTableKeyDown: KeyboardEventHandler<HTMLTableElement>;\n onCellFocus: (cellPosition: TableCellPosition) => void;\n onTableBlur: FocusEventHandler<HTMLTableElement>;\n} {\n const [activeCell, setActiveCell] = useState<TableCellPosition>(DEFAULT_ACTIVE_CELL);\n const [isActive, setIsActive] = useState(false);\n\n const handleCellFocus = (cellPosition: TableCellPosition): void => {\n if (cellPosition.column === activeCell.column && cellPosition.row === activeCell.row && isActive) {\n return;\n }\n setIsActive(true);\n setActiveCell(cellPosition);\n };\n\n const handleKeyDown: React.KeyboardEventHandler<HTMLTableElement> = useCallback(\n (e) => {\n // Including some of the basic a11y keyboard interaction patterns from:\n // https://www.w3.org/WAI/ARIA/apg/patterns/grid/\n // TODO: add other keyboard combos.\n const key = e.key;\n\n if (isArrowKey(key) || key === 'Home' || key === 'End' || key === 'PageDown' || key === 'PageUp') {\n setActiveCell((curActiveCell) => {\n let nextRow: number = curActiveCell.row;\n let nextColumn: number = curActiveCell.column;\n\n if (key === 'ArrowRight' && nextColumn < maxColumns - 1) {\n e.preventDefault();\n nextColumn += 1;\n } else if (key === 'ArrowLeft' && nextColumn > 0) {\n e.preventDefault();\n nextColumn -= 1;\n } else if (key === 'ArrowDown' && nextRow < maxRows - 1) {\n e.preventDefault();\n nextRow += 1;\n } else if (key === 'ArrowUp' && nextRow > 0) {\n e.preventDefault();\n nextRow -= 1;\n } else if (key === 'Home') {\n e.preventDefault();\n nextRow = 0;\n nextColumn = 0;\n } else if (key === 'End') {\n e.preventDefault();\n nextRow = maxRows - 1;\n nextColumn = maxColumns - 1;\n }\n\n const defaultNewPosition = { column: nextColumn, row: nextRow };\n\n const newPosition = onActiveCellChange?.(e, curActiveCell, defaultNewPosition) || defaultNewPosition;\n\n if (newPosition.row === curActiveCell.row && newPosition.column === curActiveCell.column) {\n // Return original to avoid creating a new object if nothing\n // changed.\n return curActiveCell;\n }\n\n return newPosition;\n });\n }\n },\n [maxColumns, maxRows, onActiveCellChange],\n );\n\n const handleTableBlur: FocusEventHandler<HTMLTableElement> = useCallback((e) => {\n if (!e.currentTarget.contains(e.relatedTarget as Node)) {\n setIsActive(false);\n setActiveCell(DEFAULT_ACTIVE_CELL);\n }\n }, []);\n\n return {\n activeCell,\n isActive,\n onTableKeyDown: handleKeyDown,\n onCellFocus: handleCellFocus,\n onTableBlur: handleTableBlur,\n };\n}\n"],"names":["useCallback","useState","DEFAULT_ACTIVE_CELL","row","column","ARROW_KEYS","Set","isArrowKey","key","has","useTableKeyboardNav","maxRows","maxColumns","onActiveCellChange","activeCell","setActiveCell","isActive","setIsActive","handleCellFocus","cellPosition","handleKeyDown","e","curActiveCell","nextRow","nextColumn","preventDefault","defaultNewPosition","newPosition","handleTableBlur","currentTarget","contains","relatedTarget","onTableKeyDown","onCellFocus","onTableBlur"],"mappings":"AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAGjC,SAASA,WAAW,EAAEC,QAAQ,QAAQ,QAAQ;AA0B9C,MAAMC,sBAAyC;IAC7CC,KAAK;IACLC,QAAQ;AACV;AAEA,MAAMC,aAAa,IAAIC,IAAI;IAAC;IAAc;IAAa;IAAW;CAAY;AAE9E,SAASC,WAAWC,GAAW;IAC7B,OAAOH,WAAWI,GAAG,CAACD;AACxB;AAEA;;;;;CAKC,GACD,OAAO,SAASE,oBAAoB,EAAEC,OAAO,EAAEC,UAAU,EAAEC,kBAAkB,EAA4B;IAOvG,MAAM,CAACC,YAAYC,cAAc,GAAGd,SAA4BC;IAChE,MAAM,CAACc,UAAUC,YAAY,GAAGhB,SAAS;IAEzC,MAAMiB,kBAAkB,CAACC;QACvB,IAAIA,aAAaf,MAAM,KAAKU,WAAWV,MAAM,IAAIe,aAAahB,GAAG,KAAKW,WAAWX,GAAG,IAAIa,UAAU;YAChG;QACF;QACAC,YAAY;QACZF,cAAcI;IAChB;IAEA,MAAMC,gBAA8DpB,YAClE,CAACqB;QACC,uEAAuE;QACvE,iDAAiD;QACjD,mCAAmC;QACnC,MAAMb,MAAMa,EAAEb,GAAG;QAEjB,IAAID,WAAWC,QAAQA,QAAQ,UAAUA,QAAQ,SAASA,QAAQ,cAAcA,QAAQ,UAAU;YAChGO,cAAc,CAACO;gBACb,IAAIC,UAAkBD,cAAcnB,GAAG;gBACvC,IAAIqB,aAAqBF,cAAclB,MAAM;gBAE7C,IAAII,QAAQ,gBAAgBgB,aAAaZ,aAAa,GAAG;oBACvDS,EAAEI,cAAc;oBAChBD,cAAc;gBAChB,OAAO,IAAIhB,QAAQ,eAAegB,aAAa,GAAG;oBAChDH,EAAEI,cAAc;oBAChBD,cAAc;gBAChB,OAAO,IAAIhB,QAAQ,eAAee,UAAUZ,UAAU,GAAG;oBACvDU,EAAEI,cAAc;oBAChBF,WAAW;gBACb,OAAO,IAAIf,QAAQ,aAAae,UAAU,GAAG;oBAC3CF,EAAEI,cAAc;oBAChBF,WAAW;gBACb,OAAO,IAAIf,QAAQ,QAAQ;oBACzBa,EAAEI,cAAc;oBAChBF,UAAU;oBACVC,aAAa;gBACf,OAAO,IAAIhB,QAAQ,OAAO;oBACxBa,EAAEI,cAAc;oBAChBF,UAAUZ,UAAU;oBACpBa,aAAaZ,aAAa;gBAC5B;gBAEA,MAAMc,qBAAqB;oBAAEtB,QAAQoB;oBAAYrB,KAAKoB;gBAAQ;gBAE9D,MAAMI,cAAcd,qBAAqBQ,GAAGC,eAAeI,uBAAuBA;gBAElF,IAAIC,YAAYxB,GAAG,KAAKmB,cAAcnB,GAAG,IAAIwB,YAAYvB,MAAM,KAAKkB,cAAclB,MAAM,EAAE;oBACxF,4DAA4D;oBAC5D,WAAW;oBACX,OAAOkB;gBACT;gBAEA,OAAOK;YACT;QACF;IACF,GACA;QAACf;QAAYD;QAASE;KAAmB;IAG3C,MAAMe,kBAAuD5B,YAAY,CAACqB;QACxE,IAAI,CAACA,EAAEQ,aAAa,CAACC,QAAQ,CAACT,EAAEU,aAAa,GAAW;YACtDd,YAAY;YACZF,cAAcb;QAChB;IACF,GAAG,EAAE;IAEL,OAAO;QACLY;QACAE;QACAgB,gBAAgBZ;QAChBa,aAAaf;QACbgB,aAAaN;IACf;AACF"}
@@ -200,7 +200,7 @@ export function ThresholdsEditor({ thresholds, onChange, hideDefault, disablePer
200
200
  deleteThreshold(i);
201
201
  },
202
202
  onBlur: handleThresholdBlur
203
- }, i)).reverse(),
203
+ }, i)).toReversed(),
204
204
  !hideDefault && /*#__PURE__*/ _jsxs(Stack, {
205
205
  flex: 1,
206
206
  direction: "row",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ThresholdsEditor/ThresholdsEditor.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 { IconButton, ToggleButton, ToggleButtonGroup, Typography } from '@mui/material';\nimport { Stack } from '@mui/system';\nimport { produce } from 'immer';\nimport PlusIcon from 'mdi-material-ui/Plus';\nimport type { ReactElement } from 'react';\nimport React, { useEffect, useRef } from 'react';\n\nimport { OptionsColorPicker } from '../ColorPicker/OptionsColorPicker';\nimport { useChartsTheme } from '../context/ChartsProvider';\nimport { InfoTooltip } from '../InfoTooltip';\nimport type { ThresholdOptions } from '../model';\nimport { OptionsEditorControl, OptionsEditorGroup } from '../OptionsEditorLayout';\nimport { ThresholdInput } from './ThresholdInput';\n\nexport interface ThresholdsEditorProps {\n onChange: (thresholds: ThresholdOptions) => void;\n thresholds?: ThresholdOptions;\n hideDefault?: boolean;\n disablePercentMode?: boolean;\n}\n\nconst DEFAULT_STEP = 10;\n\nexport function ThresholdsEditor({\n thresholds,\n onChange,\n hideDefault,\n disablePercentMode,\n}: ThresholdsEditorProps): ReactElement {\n const chartsTheme = useChartsTheme();\n const {\n thresholds: { defaultColor, palette },\n } = chartsTheme;\n const defaultThresholdColor = thresholds?.defaultColor ?? defaultColor;\n\n const steps = thresholds?.steps;\n // every time a new threshold 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 }, [steps?.length]);\n\n const handleThresholdValueChange = (e: React.ChangeEvent<HTMLInputElement>, i: number): void => {\n if (thresholds !== undefined) {\n onChange(\n produce(thresholds, (draft) => {\n const step = draft.steps?.[i];\n if (step) {\n step.value = Number(e.target.value);\n }\n }),\n );\n }\n };\n\n const handleThresholdColorChange = (color: string, i: number): void => {\n if (thresholds !== undefined) {\n onChange(\n produce(thresholds, (draft) => {\n if (draft.steps !== undefined) {\n const step = draft.steps[i];\n if (step) {\n step.color = color;\n }\n }\n }),\n );\n }\n };\n\n const handleDefaultColorChange = (color: string): void => {\n if (thresholds !== undefined) {\n onChange(\n produce(thresholds, (draft) => {\n draft.defaultColor = color;\n }),\n );\n } else {\n onChange({\n defaultColor: color,\n });\n }\n };\n\n // sort thresholds in ascending order every time an input blurs\n const handleThresholdBlur = (): void => {\n if (steps !== undefined) {\n const sortedSteps = [...steps];\n sortedSteps.sort((a, b) => a.value - b.value);\n if (thresholds !== undefined) {\n onChange(\n produce(thresholds, (draft) => {\n draft.steps = sortedSteps;\n }),\n );\n }\n }\n };\n\n const deleteThreshold = (i: number): void => {\n if (thresholds !== undefined) {\n const updatedThresholds = produce(thresholds, (draft) => {\n if (draft.steps) {\n draft.steps.splice(i, 1);\n }\n });\n onChange(updatedThresholds);\n }\n };\n\n const addThresholdInput = (): void => {\n focusRef.current = true;\n if (thresholds === undefined) {\n onChange({\n steps: [{ value: DEFAULT_STEP }],\n });\n } else if (thresholds && thresholds.steps === undefined) {\n onChange(\n produce(thresholds, (draft) => {\n draft.steps = [{ value: DEFAULT_STEP }];\n }),\n );\n } else {\n onChange(\n produce(thresholds, (draft) => {\n const steps = draft.steps;\n if (steps?.length) {\n const lastStep = steps[steps.length - 1];\n const color = palette[steps.length] ?? getRandomColor(); // we will assign color from the palette first, then generate random color\n steps.push({ color, value: (lastStep?.value ?? 0) + DEFAULT_STEP }); // set new threshold value to last step value + 10\n } else if (steps) {\n steps.push({ value: DEFAULT_STEP });\n }\n }),\n );\n }\n };\n\n const handleModeChange = (event: React.MouseEvent, value: string): void => {\n const mode = value === 'percent' ? 'percent' : undefined;\n if (thresholds !== undefined) {\n onChange(\n produce(thresholds, (draft) => {\n draft.mode = mode;\n }),\n );\n } else {\n onChange({ mode });\n }\n };\n\n return (\n <OptionsEditorGroup\n title=\"Thresholds\"\n icon={\n <InfoTooltip description=\"Add threshold\">\n <IconButton size=\"small\" aria-label=\"add threshold\" onClick={addThresholdInput}>\n <PlusIcon />\n </IconButton>\n </InfoTooltip>\n }\n >\n <OptionsEditorControl\n label=\"Mode\"\n description=\"Percentage means thresholds relative to min & max\"\n control={\n <ToggleButtonGroup\n exclusive\n disabled={disablePercentMode}\n value={thresholds?.mode ?? 'absolute'}\n onChange={handleModeChange}\n sx={{ height: '36px', marginLeft: 'auto' }}\n >\n <ToggleButton aria-label=\"absolute\" value=\"absolute\" sx={{ fontWeight: 500 }}>\n Absolute\n </ToggleButton>\n <ToggleButton aria-label=\"percent\" value=\"percent\" sx={{ fontWeight: 500 }}>\n Percent\n </ToggleButton>\n </ToggleButtonGroup>\n }\n />\n {steps &&\n steps\n .map((step, i) => (\n <ThresholdInput\n inputRef={i === steps.length - 1 ? recentlyAddedInputRef : undefined}\n key={i}\n label={`T${i + 1}`}\n color={step.color ?? palette[i] ?? defaultThresholdColor}\n value={step.value}\n mode={thresholds?.mode}\n onColorChange={(color) => handleThresholdColorChange(color, i)}\n onChange={(e) => {\n handleThresholdValueChange(e, i);\n }}\n onDelete={() => {\n deleteThreshold(i);\n }}\n onBlur={handleThresholdBlur}\n />\n ))\n .reverse()}\n {!hideDefault && (\n <Stack flex={1} direction=\"row\" alignItems=\"center\" spacing={1}>\n <OptionsColorPicker label=\"default\" color={defaultThresholdColor} onColorChange={handleDefaultColorChange} />\n <Typography>Default</Typography>\n </Stack>\n )}\n </OptionsEditorGroup>\n );\n}\n\n// https://www.paulirish.com/2009/random-hex-color-code-snippets/\nconst getRandomColor = (): string => {\n return (\n '#' +\n Math.floor(Math.random() * 16777216)\n .toString(16)\n .padStart(6, '0')\n );\n};\n"],"names":["IconButton","ToggleButton","ToggleButtonGroup","Typography","Stack","produce","PlusIcon","React","useEffect","useRef","OptionsColorPicker","useChartsTheme","InfoTooltip","OptionsEditorControl","OptionsEditorGroup","ThresholdInput","DEFAULT_STEP","ThresholdsEditor","thresholds","onChange","hideDefault","disablePercentMode","chartsTheme","defaultColor","palette","defaultThresholdColor","steps","recentlyAddedInputRef","focusRef","current","focus","length","handleThresholdValueChange","e","i","undefined","draft","step","value","Number","target","handleThresholdColorChange","color","handleDefaultColorChange","handleThresholdBlur","sortedSteps","sort","a","b","deleteThreshold","updatedThresholds","splice","addThresholdInput","lastStep","getRandomColor","push","handleModeChange","event","mode","title","icon","description","size","aria-label","onClick","label","control","exclusive","disabled","sx","height","marginLeft","fontWeight","map","inputRef","onColorChange","onDelete","onBlur","reverse","flex","direction","alignItems","spacing","Math","floor","random","toString","padStart"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/ThresholdsEditor/ThresholdsEditor.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 { IconButton, ToggleButton, ToggleButtonGroup, Typography } from '@mui/material';\nimport { Stack } from '@mui/system';\nimport { produce } from 'immer';\nimport PlusIcon from 'mdi-material-ui/Plus';\nimport type { ReactElement } from 'react';\nimport React, { useEffect, useRef } from 'react';\n\nimport { OptionsColorPicker } from '../ColorPicker/OptionsColorPicker';\nimport { useChartsTheme } from '../context/ChartsProvider';\nimport { InfoTooltip } from '../InfoTooltip';\nimport type { ThresholdOptions } from '../model';\nimport { OptionsEditorControl, OptionsEditorGroup } from '../OptionsEditorLayout';\nimport { ThresholdInput } from './ThresholdInput';\n\nexport interface ThresholdsEditorProps {\n onChange: (thresholds: ThresholdOptions) => void;\n thresholds?: ThresholdOptions;\n hideDefault?: boolean;\n disablePercentMode?: boolean;\n}\n\nconst DEFAULT_STEP = 10;\n\nexport function ThresholdsEditor({\n thresholds,\n onChange,\n hideDefault,\n disablePercentMode,\n}: ThresholdsEditorProps): ReactElement {\n const chartsTheme = useChartsTheme();\n const {\n thresholds: { defaultColor, palette },\n } = chartsTheme;\n const defaultThresholdColor = thresholds?.defaultColor ?? defaultColor;\n\n const steps = thresholds?.steps;\n // every time a new threshold 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 }, [steps?.length]);\n\n const handleThresholdValueChange = (e: React.ChangeEvent<HTMLInputElement>, i: number): void => {\n if (thresholds !== undefined) {\n onChange(\n produce(thresholds, (draft) => {\n const step = draft.steps?.[i];\n if (step) {\n step.value = Number(e.target.value);\n }\n }),\n );\n }\n };\n\n const handleThresholdColorChange = (color: string, i: number): void => {\n if (thresholds !== undefined) {\n onChange(\n produce(thresholds, (draft) => {\n if (draft.steps !== undefined) {\n const step = draft.steps[i];\n if (step) {\n step.color = color;\n }\n }\n }),\n );\n }\n };\n\n const handleDefaultColorChange = (color: string): void => {\n if (thresholds !== undefined) {\n onChange(\n produce(thresholds, (draft) => {\n draft.defaultColor = color;\n }),\n );\n } else {\n onChange({\n defaultColor: color,\n });\n }\n };\n\n // sort thresholds in ascending order every time an input blurs\n const handleThresholdBlur = (): void => {\n if (steps !== undefined) {\n const sortedSteps = [...steps];\n sortedSteps.sort((a, b) => a.value - b.value);\n if (thresholds !== undefined) {\n onChange(\n produce(thresholds, (draft) => {\n draft.steps = sortedSteps;\n }),\n );\n }\n }\n };\n\n const deleteThreshold = (i: number): void => {\n if (thresholds !== undefined) {\n const updatedThresholds = produce(thresholds, (draft) => {\n if (draft.steps) {\n draft.steps.splice(i, 1);\n }\n });\n onChange(updatedThresholds);\n }\n };\n\n const addThresholdInput = (): void => {\n focusRef.current = true;\n if (thresholds === undefined) {\n onChange({\n steps: [{ value: DEFAULT_STEP }],\n });\n } else if (thresholds && thresholds.steps === undefined) {\n onChange(\n produce(thresholds, (draft) => {\n draft.steps = [{ value: DEFAULT_STEP }];\n }),\n );\n } else {\n onChange(\n produce(thresholds, (draft) => {\n const steps = draft.steps;\n if (steps?.length) {\n const lastStep = steps[steps.length - 1];\n const color = palette[steps.length] ?? getRandomColor(); // we will assign color from the palette first, then generate random color\n steps.push({ color, value: (lastStep?.value ?? 0) + DEFAULT_STEP }); // set new threshold value to last step value + 10\n } else if (steps) {\n steps.push({ value: DEFAULT_STEP });\n }\n }),\n );\n }\n };\n\n const handleModeChange = (event: React.MouseEvent, value: string): void => {\n const mode = value === 'percent' ? 'percent' : undefined;\n if (thresholds !== undefined) {\n onChange(\n produce(thresholds, (draft) => {\n draft.mode = mode;\n }),\n );\n } else {\n onChange({ mode });\n }\n };\n\n return (\n <OptionsEditorGroup\n title=\"Thresholds\"\n icon={\n <InfoTooltip description=\"Add threshold\">\n <IconButton size=\"small\" aria-label=\"add threshold\" onClick={addThresholdInput}>\n <PlusIcon />\n </IconButton>\n </InfoTooltip>\n }\n >\n <OptionsEditorControl\n label=\"Mode\"\n description=\"Percentage means thresholds relative to min & max\"\n control={\n <ToggleButtonGroup\n exclusive\n disabled={disablePercentMode}\n value={thresholds?.mode ?? 'absolute'}\n onChange={handleModeChange}\n sx={{ height: '36px', marginLeft: 'auto' }}\n >\n <ToggleButton aria-label=\"absolute\" value=\"absolute\" sx={{ fontWeight: 500 }}>\n Absolute\n </ToggleButton>\n <ToggleButton aria-label=\"percent\" value=\"percent\" sx={{ fontWeight: 500 }}>\n Percent\n </ToggleButton>\n </ToggleButtonGroup>\n }\n />\n {steps &&\n steps\n .map((step, i) => (\n <ThresholdInput\n inputRef={i === steps.length - 1 ? recentlyAddedInputRef : undefined}\n key={i}\n label={`T${i + 1}`}\n color={step.color ?? palette[i] ?? defaultThresholdColor}\n value={step.value}\n mode={thresholds?.mode}\n onColorChange={(color) => handleThresholdColorChange(color, i)}\n onChange={(e) => {\n handleThresholdValueChange(e, i);\n }}\n onDelete={() => {\n deleteThreshold(i);\n }}\n onBlur={handleThresholdBlur}\n />\n ))\n .toReversed()}\n {!hideDefault && (\n <Stack flex={1} direction=\"row\" alignItems=\"center\" spacing={1}>\n <OptionsColorPicker label=\"default\" color={defaultThresholdColor} onColorChange={handleDefaultColorChange} />\n <Typography>Default</Typography>\n </Stack>\n )}\n </OptionsEditorGroup>\n );\n}\n\n// https://www.paulirish.com/2009/random-hex-color-code-snippets/\nconst getRandomColor = (): string => {\n return (\n '#' +\n Math.floor(Math.random() * 16777216)\n .toString(16)\n .padStart(6, '0')\n );\n};\n"],"names":["IconButton","ToggleButton","ToggleButtonGroup","Typography","Stack","produce","PlusIcon","React","useEffect","useRef","OptionsColorPicker","useChartsTheme","InfoTooltip","OptionsEditorControl","OptionsEditorGroup","ThresholdInput","DEFAULT_STEP","ThresholdsEditor","thresholds","onChange","hideDefault","disablePercentMode","chartsTheme","defaultColor","palette","defaultThresholdColor","steps","recentlyAddedInputRef","focusRef","current","focus","length","handleThresholdValueChange","e","i","undefined","draft","step","value","Number","target","handleThresholdColorChange","color","handleDefaultColorChange","handleThresholdBlur","sortedSteps","sort","a","b","deleteThreshold","updatedThresholds","splice","addThresholdInput","lastStep","getRandomColor","push","handleModeChange","event","mode","title","icon","description","size","aria-label","onClick","label","control","exclusive","disabled","sx","height","marginLeft","fontWeight","map","inputRef","onColorChange","onDelete","onBlur","toReversed","flex","direction","alignItems","spacing","Math","floor","random","toString","padStart"],"mappings":"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"}
@@ -18,7 +18,7 @@ export function TooltipContent(props) {
18
18
  const { series, wrapLabels } = props;
19
19
  const sortedFocusedSeries = useMemo(()=>{
20
20
  if (series === null) return null;
21
- return series.sort((a, b)=>a.y > b.y ? -1 : 1);
21
+ return series.toSorted((a, b)=>a.y > b.y ? -1 : 1);
22
22
  }, [
23
23
  series
24
24
  ]);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/TimeSeriesTooltip/TooltipContent.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 { Box } from '@mui/material';\nimport type { ReactElement } from 'react';\nimport { useMemo } from 'react';\n\nimport { SeriesInfo } from './SeriesInfo';\nimport type { NearbySeriesArray } from './types';\n\nexport interface TooltipContentProps {\n series: NearbySeriesArray | null;\n wrapLabels?: boolean;\n}\n\nexport function TooltipContent(props: TooltipContentProps): ReactElement | null {\n const { series, wrapLabels } = props;\n\n const sortedFocusedSeries = useMemo(() => {\n if (series === null) return null;\n return series.sort((a, b) => (a.y > b.y ? -1 : 1));\n }, [series]);\n\n if (series === null || sortedFocusedSeries === null) {\n return null;\n }\n // TODO: use react-virtuoso to improve performance\n return (\n <Box\n sx={(theme) => ({\n display: 'table',\n padding: theme.spacing(0.5, 2),\n })}\n >\n {sortedFocusedSeries.map(({ datumIdx, seriesIdx, seriesName, y, formattedY, markerColor, isClosestToCursor }) => {\n if (datumIdx === null || seriesIdx === null) return null;\n const key = seriesIdx.toString() + datumIdx.toString();\n\n return (\n <SeriesInfo\n key={key}\n seriesName={seriesName}\n y={y}\n formattedY={formattedY}\n markerColor={markerColor}\n totalSeries={sortedFocusedSeries.length}\n wrapLabels={wrapLabels}\n emphasizeText={isClosestToCursor}\n />\n );\n })}\n </Box>\n );\n}\n"],"names":["Box","useMemo","SeriesInfo","TooltipContent","props","series","wrapLabels","sortedFocusedSeries","sort","a","b","y","sx","theme","display","padding","spacing","map","datumIdx","seriesIdx","seriesName","formattedY","markerColor","isClosestToCursor","key","toString","totalSeries","length","emphasizeText"],"mappings":";AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAASA,GAAG,QAAQ,gBAAgB;AAEpC,SAASC,OAAO,QAAQ,QAAQ;AAEhC,SAASC,UAAU,QAAQ,kBAAe;AAQ1C,OAAO,SAASC,eAAeC,KAA0B;IACvD,MAAM,EAAEC,MAAM,EAAEC,UAAU,EAAE,GAAGF;IAE/B,MAAMG,sBAAsBN,QAAQ;QAClC,IAAII,WAAW,MAAM,OAAO;QAC5B,OAAOA,OAAOG,IAAI,CAAC,CAACC,GAAGC,IAAOD,EAAEE,CAAC,GAAGD,EAAEC,CAAC,GAAG,CAAC,IAAI;IACjD,GAAG;QAACN;KAAO;IAEX,IAAIA,WAAW,QAAQE,wBAAwB,MAAM;QACnD,OAAO;IACT;IACA,kDAAkD;IAClD,qBACE,KAACP;QACCY,IAAI,CAACC,QAAW,CAAA;gBACdC,SAAS;gBACTC,SAASF,MAAMG,OAAO,CAAC,KAAK;YAC9B,CAAA;kBAECT,oBAAoBU,GAAG,CAAC,CAAC,EAAEC,QAAQ,EAAEC,SAAS,EAAEC,UAAU,EAAET,CAAC,EAAEU,UAAU,EAAEC,WAAW,EAAEC,iBAAiB,EAAE;YAC1G,IAAIL,aAAa,QAAQC,cAAc,MAAM,OAAO;YACpD,MAAMK,MAAML,UAAUM,QAAQ,KAAKP,SAASO,QAAQ;YAEpD,qBACE,KAACvB;gBAECkB,YAAYA;gBACZT,GAAGA;gBACHU,YAAYA;gBACZC,aAAaA;gBACbI,aAAanB,oBAAoBoB,MAAM;gBACvCrB,YAAYA;gBACZsB,eAAeL;eAPVC;QAUX;;AAGN"}
1
+ {"version":3,"sources":["../../src/TimeSeriesTooltip/TooltipContent.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 { Box } from '@mui/material';\nimport type { ReactElement } from 'react';\nimport { useMemo } from 'react';\n\nimport { SeriesInfo } from './SeriesInfo';\nimport type { NearbySeriesArray } from './types';\n\nexport interface TooltipContentProps {\n series: NearbySeriesArray | null;\n wrapLabels?: boolean;\n}\n\nexport function TooltipContent(props: TooltipContentProps): ReactElement | null {\n const { series, wrapLabels } = props;\n\n const sortedFocusedSeries = useMemo(() => {\n if (series === null) return null;\n return series.toSorted((a, b) => (a.y > b.y ? -1 : 1));\n }, [series]);\n\n if (series === null || sortedFocusedSeries === null) {\n return null;\n }\n // TODO: use react-virtuoso to improve performance\n return (\n <Box\n sx={(theme) => ({\n display: 'table',\n padding: theme.spacing(0.5, 2),\n })}\n >\n {sortedFocusedSeries.map(({ datumIdx, seriesIdx, seriesName, y, formattedY, markerColor, isClosestToCursor }) => {\n if (datumIdx === null || seriesIdx === null) return null;\n const key = seriesIdx.toString() + datumIdx.toString();\n\n return (\n <SeriesInfo\n key={key}\n seriesName={seriesName}\n y={y}\n formattedY={formattedY}\n markerColor={markerColor}\n totalSeries={sortedFocusedSeries.length}\n wrapLabels={wrapLabels}\n emphasizeText={isClosestToCursor}\n />\n );\n })}\n </Box>\n );\n}\n"],"names":["Box","useMemo","SeriesInfo","TooltipContent","props","series","wrapLabels","sortedFocusedSeries","toSorted","a","b","y","sx","theme","display","padding","spacing","map","datumIdx","seriesIdx","seriesName","formattedY","markerColor","isClosestToCursor","key","toString","totalSeries","length","emphasizeText"],"mappings":";AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAASA,GAAG,QAAQ,gBAAgB;AAEpC,SAASC,OAAO,QAAQ,QAAQ;AAEhC,SAASC,UAAU,QAAQ,kBAAe;AAQ1C,OAAO,SAASC,eAAeC,KAA0B;IACvD,MAAM,EAAEC,MAAM,EAAEC,UAAU,EAAE,GAAGF;IAE/B,MAAMG,sBAAsBN,QAAQ;QAClC,IAAII,WAAW,MAAM,OAAO;QAC5B,OAAOA,OAAOG,QAAQ,CAAC,CAACC,GAAGC,IAAOD,EAAEE,CAAC,GAAGD,EAAEC,CAAC,GAAG,CAAC,IAAI;IACrD,GAAG;QAACN;KAAO;IAEX,IAAIA,WAAW,QAAQE,wBAAwB,MAAM;QACnD,OAAO;IACT;IACA,kDAAkD;IAClD,qBACE,KAACP;QACCY,IAAI,CAACC,QAAW,CAAA;gBACdC,SAAS;gBACTC,SAASF,MAAMG,OAAO,CAAC,KAAK;YAC9B,CAAA;kBAECT,oBAAoBU,GAAG,CAAC,CAAC,EAAEC,QAAQ,EAAEC,SAAS,EAAEC,UAAU,EAAET,CAAC,EAAEU,UAAU,EAAEC,WAAW,EAAEC,iBAAiB,EAAE;YAC1G,IAAIL,aAAa,QAAQC,cAAc,MAAM,OAAO;YACpD,MAAMK,MAAML,UAAUM,QAAQ,KAAKP,SAASO,QAAQ;YAEpD,qBACE,KAACvB;gBAECkB,YAAYA;gBACZT,GAAGA;gBACHU,YAAYA;gBACZC,aAAaA;gBACbI,aAAanB,oBAAoBoB,MAAM;gBACvCrB,YAAYA;gBACZsB,eAAeL;eAPVC;QAUX;;AAGN"}
@@ -32,7 +32,7 @@ function gatherCandidates(data, seriesMapping, closestTimestamp, cursorX, cursor
32
32
  sortedTimestamps.push(ts);
33
33
  }
34
34
  }
35
- sortedTimestamps = sortedTimestamps.sort((a, b)=>a - b);
35
+ sortedTimestamps = sortedTimestamps.toSorted((a, b)=>a - b);
36
36
  }
37
37
  // Bar-only indexes: ECharts groups bars independently of lines, so bar-relative index and count must exclude line series.
38
38
  const barSeriesIndexes = [];
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/TimeSeriesTooltip/nearby-series.ts"],"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 type { TimeSeries, TimeSeriesValueTuple } from '@perses-dev/spec';\nimport type { BarSeriesOption } from 'echarts/charts';\nimport type { ECharts as EChartsInstance } from 'echarts/core';\n\nimport type { EChartsDataFormat, TimeChartSeriesMapping, DatapointInfo, FormatOptions } from '../model';\nimport { OPTIMIZED_MODE_SERIES_LIMIT, formatValue } from '../model';\nimport { batchDispatchNearbySeriesActions, getPointInGrid, getClosestTimestamp } from '../utils';\nimport type { CursorCoordinates, CursorData } from './tooltip-model';\nimport { EMPTY_TOOLTIP_DATA } from './tooltip-model';\nimport type { Candidate, GetYBufferParams, IsWithinPercentageRangeParams, NearbySeriesArray } from './types';\nimport {\n calculateBarBandwidth,\n calculateBarSegmentBounds,\n calculateBarYBounds,\n calculateVisualYForSeries,\n getPixelXFromGrid,\n} from './utils';\n\nexport type { NearbySeriesArray, NearbySeriesInfo } from './types';\n\n// increase multipliers to show more series in tooltip\nexport const INCREASE_NEARBY_SERIES_MULTIPLIER = 5.5; // adjusts how many series show in tooltip (higher == more series shown)\nexport const DYNAMIC_NEARBY_SERIES_MULTIPLIER = 30; // used for adjustment after series number divisor\nexport const SHOW_FEWER_SERIES_LIMIT = 5;\n\nfunction gatherCandidates(\n data: TimeSeries[],\n seriesMapping: TimeChartSeriesMapping,\n closestTimestamp: number,\n cursorX: number,\n cursorY: number,\n cursorXPixel: number | null,\n cursorPixelY: number | undefined,\n yBuffer: number,\n yBufferPixels: number | null,\n chart: EChartsInstance,\n): Candidate[] {\n const candidates: Candidate[] = [];\n const totalSeries = data.length;\n\n const stackTotals = new Map<string, number>();\n\n let sortedTimestamps: number[] = [];\n const firstValues = data[0]?.values;\n if (firstValues && firstValues.length > 0) {\n const seen = new Set<number>();\n for (const [ts] of firstValues) {\n if (!seen.has(ts)) {\n seen.add(ts);\n sortedTimestamps.push(ts);\n }\n }\n sortedTimestamps = sortedTimestamps.sort((a, b) => a - b);\n }\n\n // Bar-only indexes: ECharts groups bars independently of lines, so bar-relative index and count must exclude line series.\n const barSeriesIndexes: number[] = [];\n for (let i = 0; i < totalSeries; i++) {\n if ((seriesMapping[i]?.type ?? 'line') === 'bar') barSeriesIndexes.push(i);\n }\n\n // Computed once outside the loop — both depend only on the timestamp, not the series index.\n let barBandwidth: number | null = null;\n let barCenterPixelX: number | null = null;\n if (barSeriesIndexes.length > 0 && cursorXPixel !== null) {\n barBandwidth = calculateBarBandwidth(closestTimestamp, sortedTimestamps, chart);\n barCenterPixelX = getPixelXFromGrid(closestTimestamp, chart);\n }\n\n for (let seriesIdx = 0; seriesIdx < totalSeries; seriesIdx++) {\n const currentSeries = seriesMapping[seriesIdx];\n if (!currentSeries) continue;\n\n const currentDataset = data[seriesIdx];\n if (!currentDataset) continue;\n\n const currentDatasetValues: TimeSeriesValueTuple[] | undefined = currentDataset.values;\n if (!currentDatasetValues || !Array.isArray(currentDatasetValues)) continue;\n\n const seriesType = currentSeries.type ?? 'line';\n const currentSeriesName = currentSeries.name ? currentSeries.name.toString() : '';\n const seriesId = currentSeries.id ? currentSeries.id.toString() : '';\n const markerColor = (currentSeries.color ?? '#000').toString();\n\n let datumIdx = -1;\n let xValue = 0;\n let yValue: number | null | undefined;\n for (let i = 0; i < currentDatasetValues.length; i++) {\n const tuple = currentDatasetValues[i];\n if (!tuple) continue;\n if (tuple[0] === closestTimestamp) {\n datumIdx = i;\n xValue = tuple[0];\n yValue = tuple[1];\n break;\n }\n }\n if (datumIdx === -1) continue;\n\n if (yValue === null || yValue === undefined) continue;\n\n let isCandidate = false;\n let visualY = yValue;\n let distance = Infinity;\n\n if (seriesType === 'line') {\n visualY = calculateVisualYForSeries(seriesIdx, yValue, seriesMapping, stackTotals);\n\n if (cursorPixelY !== undefined && yBufferPixels !== null) {\n try {\n const dataPointPixel = chart.convertToPixel({ seriesIndex: seriesIdx }, [datumIdx, visualY]);\n if (dataPointPixel && dataPointPixel[1] !== undefined) {\n const pixelDistance = Math.abs(cursorPixelY - dataPointPixel[1]);\n isCandidate = pixelDistance <= yBufferPixels;\n distance = pixelDistance;\n } else {\n const verticalDistance = Math.abs(visualY - cursorY);\n isCandidate = verticalDistance <= yBuffer;\n distance = verticalDistance;\n }\n } catch {\n const verticalDistance = Math.abs(visualY - cursorY);\n isCandidate = verticalDistance <= yBuffer;\n distance = verticalDistance;\n }\n } else {\n const verticalDistance = Math.abs(visualY - cursorY);\n isCandidate = verticalDistance <= yBuffer;\n distance = verticalDistance;\n }\n } else if (seriesType === 'bar') {\n if (cursorXPixel === null || barBandwidth === null || barCenterPixelX === null) continue;\n\n const barRelativeIdx = barSeriesIndexes.indexOf(seriesIdx);\n if (barRelativeIdx === -1) continue;\n\n const segmentBounds = calculateBarSegmentBounds(\n barRelativeIdx,\n barBandwidth,\n barCenterPixelX,\n barSeriesIndexes.length,\n );\n\n const isWithinXBounds = cursorXPixel >= segmentBounds.left && cursorXPixel <= segmentBounds.right;\n if (!isWithinXBounds) continue;\n\n const stackId = (currentSeries as BarSeriesOption).stack;\n let isHoveringYBounds = true;\n\n if (stackId) {\n const stackIdStr = stackId.toString();\n const visualYBottom = stackTotals.get(stackIdStr) ?? 0;\n visualY = calculateVisualYForSeries(seriesIdx, yValue, seriesMapping, stackTotals);\n const yBounds = calculateBarYBounds(visualYBottom, visualY, chart);\n\n if (yBounds) {\n const cursorYPixel = chart.convertToPixel('grid', [0, cursorY]);\n if (cursorYPixel && cursorYPixel[1] !== undefined) {\n isHoveringYBounds = cursorYPixel[1] >= yBounds.top && cursorYPixel[1] <= yBounds.bottom;\n }\n }\n } else {\n visualY = yValue;\n }\n\n if (!isHoveringYBounds) continue;\n\n const segmentCenter = (segmentBounds.left + segmentBounds.right) / 2;\n distance = Math.abs(cursorXPixel - segmentCenter);\n isCandidate = true;\n }\n\n if (isCandidate) {\n candidates.push({\n seriesIdx,\n datumIdx,\n seriesId,\n seriesName: currentSeriesName,\n date: closestTimestamp,\n markerColor,\n x: xValue,\n y: yValue,\n visualY,\n distance,\n });\n }\n }\n\n return candidates;\n}\n\nfunction findClosestCandidate(candidates: Candidate[]): Candidate | null {\n if (candidates.length === 0) return null;\n let winner: Candidate | null = null;\n for (const candidate of candidates) {\n if (winner === null || candidate.distance < winner.distance) {\n winner = candidate;\n }\n }\n return winner;\n}\n\nfunction processCandidates(\n candidates: Candidate[],\n winner: Candidate | null,\n format: FormatOptions | undefined,\n seriesFormatMap: Map<string, FormatOptions> | undefined,\n chart: EChartsInstance,\n nonCandidateSeriesIndexes: number[],\n): NearbySeriesArray {\n const nearbySeriesIndexes: number[] = [];\n const emphasizedSeriesIndexes: number[] = [];\n const nonEmphasizedSeriesIndexes: number[] = [...nonCandidateSeriesIndexes];\n const emphasizedDatapoints: DatapointInfo[] = [];\n const duplicateDatapoints: DatapointInfo[] = [];\n const yValueCounts: Map<number, number> = new Map();\n\n const result: NearbySeriesArray = [];\n\n for (const candidate of candidates) {\n const seriesFormat = seriesFormatMap?.get(candidate.seriesId) ?? format;\n // Use raw y, not visualY — visualY is for proximity detection only.\n const displayY = candidate.y;\n const formattedY = formatValue(displayY, seriesFormat);\n const isClosestToCursor = winner !== null && candidate.seriesIdx === winner.seriesIdx;\n\n if (isClosestToCursor) {\n emphasizedSeriesIndexes.push(candidate.seriesIdx);\n\n const duplicateValuesCount = yValueCounts.get(displayY) ?? 0;\n yValueCounts.set(displayY, duplicateValuesCount + 1);\n if (duplicateValuesCount > 0) {\n duplicateDatapoints.push({\n seriesIndex: candidate.seriesIdx,\n dataIndex: candidate.datumIdx,\n seriesName: candidate.seriesName,\n yValue: displayY,\n });\n }\n\n emphasizedDatapoints.push({\n seriesIndex: candidate.seriesIdx,\n dataIndex: candidate.datumIdx,\n seriesName: candidate.seriesName,\n yValue: displayY,\n });\n } else {\n nonEmphasizedSeriesIndexes.push(candidate.seriesIdx);\n }\n\n result.push({\n seriesIdx: candidate.seriesIdx,\n datumIdx: candidate.datumIdx,\n seriesName: candidate.seriesName,\n date: candidate.date,\n x: candidate.x,\n y: displayY,\n formattedY,\n markerColor: candidate.markerColor,\n isClosestToCursor,\n });\n\n nearbySeriesIndexes.push(candidate.seriesIdx);\n }\n\n batchDispatchNearbySeriesActions(\n chart,\n nearbySeriesIndexes,\n emphasizedSeriesIndexes,\n nonEmphasizedSeriesIndexes,\n emphasizedDatapoints,\n duplicateDatapoints,\n );\n\n return result;\n}\n\n/**\n * Returns formatted series data for the points that are close to the user's cursor.\n * Adjust xBuffer and yBuffer to increase or decrease number of series shown.\n */\nexport function checkforNearbyTimeSeries(\n data: TimeSeries[],\n seriesMapping: TimeChartSeriesMapping,\n pointInGrid: number[],\n yBuffer: number,\n chart: EChartsInstance,\n format?: FormatOptions,\n seriesFormatMap?: Map<string, FormatOptions>,\n // in the case of multi-axis, we need the cursor Y position in pixel space\n cursorPixelY?: number,\n cursorXPixel?: number | null,\n): NearbySeriesArray {\n const cursorX: number | null = pointInGrid[0] ?? null;\n const cursorY: number | null = pointInGrid[1] ?? null;\n\n if (cursorX === null || cursorY === null) return EMPTY_TOOLTIP_DATA;\n if (chart.dispatchAction === undefined) return EMPTY_TOOLTIP_DATA;\n if (!Array.isArray(data)) return EMPTY_TOOLTIP_DATA;\n\n // All series share the same x-axis timestamps (enforced by getCommonTimeScale).\n const firstTimeSeriesValues = data[0]?.values;\n const closestTimestamp = getClosestTimestamp(firstTimeSeriesValues, cursorX);\n if (closestTimestamp === null) return EMPTY_TOOLTIP_DATA;\n\n let yBufferPixels: number | null = null;\n if (cursorPixelY !== undefined) {\n const cursorPoint = chart.convertToPixel('grid', [0, cursorY]);\n const bufferPoint = chart.convertToPixel('grid', [0, cursorY + yBuffer]);\n if (cursorPoint && bufferPoint && cursorPoint[1] !== undefined && bufferPoint[1] !== undefined) {\n yBufferPixels = Math.abs(bufferPoint[1] - cursorPoint[1]);\n }\n }\n\n const resolvedCursorXPixel = cursorXPixel ?? getPixelXFromGrid(closestTimestamp, chart);\n\n const candidates = gatherCandidates(\n data,\n seriesMapping,\n closestTimestamp,\n cursorX,\n cursorY,\n resolvedCursorXPixel,\n cursorPixelY,\n yBuffer,\n yBufferPixels,\n chart,\n );\n\n const winner = findClosestCandidate(candidates);\n\n const candidateIndexes = new Set<number>();\n for (const candidate of candidates) candidateIndexes.add(candidate.seriesIdx);\n const nonCandidateSeriesIndexes: number[] = [];\n for (let idx = 0; idx < data.length; idx++) {\n if (!candidateIndexes.has(idx)) nonCandidateSeriesIndexes.push(idx);\n }\n\n return processCandidates(candidates, winner, format, seriesFormatMap, chart, nonCandidateSeriesIndexes);\n}\n\n/**\n * [DEPRECATED] Returns formatted series data for the points that are close to the user's cursor\n * Adjust yBuffer to increase or decrease number of series shown\n */\nexport function legacyCheckforNearbySeries(\n data: EChartsDataFormat,\n pointInGrid: number[],\n yBuffer: number,\n chart?: EChartsInstance,\n format?: FormatOptions,\n): NearbySeriesArray {\n const currentNearbySeriesData: NearbySeriesArray = [];\n const cursorX: number | null = pointInGrid[0] ?? null;\n const cursorY: number | null = pointInGrid[1] ?? null;\n\n if (cursorX === null || cursorY === null) {\n return currentNearbySeriesData;\n }\n\n const nearbySeriesIndexes: number[] = [];\n const emphasizedSeriesIndexes: number[] = [];\n const nonEmphasizedSeriesIndexes: number[] = [];\n const totalSeries = data.timeSeries.length;\n if (Array.isArray(data.xAxis) && Array.isArray(data.timeSeries)) {\n for (let seriesIdx = 0; seriesIdx < totalSeries; seriesIdx++) {\n const currentSeries = data.timeSeries[seriesIdx];\n if (currentSeries === undefined) break;\n if (currentNearbySeriesData.length >= OPTIMIZED_MODE_SERIES_LIMIT) break;\n\n const currentSeriesName = currentSeries.name ? currentSeries.name.toString() : '';\n const markerColor = currentSeries.color ?? '#000';\n if (Array.isArray(currentSeries.data)) {\n for (let datumIdx = 0; datumIdx < currentSeries.data.length; datumIdx++) {\n const xValue = data.xAxis[datumIdx] ?? 0;\n const yValue = currentSeries.data[datumIdx];\n // ensure null values not displayed in tooltip\n if (yValue !== undefined && yValue !== null && cursorX === datumIdx) {\n if (yValue !== '-' && cursorY <= yValue + yBuffer && cursorY >= yValue - yBuffer) {\n // show fewer bold series in tooltip when many total series\n const minPercentRange = totalSeries > SHOW_FEWER_SERIES_LIMIT ? 2 : 5;\n const percentRangeToCheck = Math.max(minPercentRange, 100 / totalSeries);\n const isClosestToCursor = isWithinPercentageRange({\n valueToCheck: cursorY,\n baseValue: yValue,\n percentage: percentRangeToCheck,\n });\n if (isClosestToCursor) {\n emphasizedSeriesIndexes.push(seriesIdx);\n } else {\n nonEmphasizedSeriesIndexes.push(seriesIdx);\n // ensure series not close to cursor are not highlighted\n if (chart?.dispatchAction !== undefined) {\n chart.dispatchAction({\n type: 'downplay',\n seriesIndex: seriesIdx,\n });\n }\n }\n\n // determine whether to convert timestamp to ms, see: https://stackoverflow.com/a/23982005/17575201\n const xValueMilliSeconds = xValue > 99999999999 ? xValue : xValue * 1000;\n const formattedY = formatValue(yValue, format);\n currentNearbySeriesData.push({\n seriesIdx: seriesIdx,\n datumIdx: datumIdx,\n seriesName: currentSeriesName,\n date: xValueMilliSeconds,\n x: xValue,\n y: yValue,\n formattedY: formattedY,\n markerColor: markerColor.toString(),\n isClosestToCursor,\n });\n nearbySeriesIndexes.push(seriesIdx);\n }\n }\n }\n }\n }\n }\n if (chart?.dispatchAction !== undefined) {\n // Clears emphasis state of all lines that are not emphasized.\n // Emphasized is a subset of just the nearby series that are closest to cursor.\n chart.dispatchAction({\n type: 'downplay',\n seriesIndex: nonEmphasizedSeriesIndexes,\n });\n\n // https://echarts.apache.org/en/api.html#action.highlight\n if (emphasizedSeriesIndexes.length > 0) {\n // Fadeout opacity of all series not closest to cursor.\n chart.dispatchAction({\n type: 'highlight',\n seriesIndex: emphasizedSeriesIndexes,\n notBlur: false, // ensure blur IS triggered, this is default but setting so it is explicit\n escapeConnect: true, // shared crosshair should not emphasize series on adjacent charts\n });\n } else {\n // When no emphasized series with bold text, notBlur allows opacity fadeout to not trigger.\n chart.dispatchAction({\n type: 'highlight',\n seriesIndex: nearbySeriesIndexes,\n notBlur: true, // do not trigger blur state when cursor is not immediately close to any series\n escapeConnect: true, // shared crosshair should not emphasize series on adjacent charts\n });\n }\n }\n\n return currentNearbySeriesData;\n}\n\n/**\n * Uses mouse position to determine whether user is hovering over a chart canvas\n * If yes, convert from pixel values to logical cartesian coordinates and return all nearby series\n */\nexport function getNearbySeriesData({\n mousePos,\n pinnedPos,\n data,\n seriesMapping,\n chart,\n format,\n seriesFormatMap,\n showAllSeries = false,\n}: {\n mousePos: CursorData['coords'];\n pinnedPos: CursorCoordinates | null;\n data: TimeSeries[];\n seriesMapping: TimeChartSeriesMapping;\n chart?: EChartsInstance;\n format?: FormatOptions;\n seriesFormatMap?: Map<string, FormatOptions>;\n showAllSeries?: boolean;\n}): NearbySeriesArray {\n if (chart === undefined || mousePos === null) return EMPTY_TOOLTIP_DATA;\n\n // prevents multiple tooltips showing from adjacent charts unless tooltip is pinned\n let cursorTargetMatchesChart = false;\n if (mousePos.target !== null) {\n const currentParent = (<HTMLElement>mousePos.target).parentElement;\n if (currentParent !== null) {\n const currentGrandparent = currentParent.parentElement;\n if (currentGrandparent !== null) {\n const chartDom = chart.getDom();\n if (chartDom === currentGrandparent) {\n cursorTargetMatchesChart = true;\n }\n }\n }\n }\n\n // allows moving cursor inside tooltip without it fading away\n if (pinnedPos !== null) {\n mousePos = pinnedPos;\n cursorTargetMatchesChart = true;\n }\n\n if (cursorTargetMatchesChart === false || data === null || chart['_model'] === undefined) return EMPTY_TOOLTIP_DATA;\n\n if (mousePos.plotCanvas.x === undefined || mousePos.plotCanvas.y === undefined) return EMPTY_TOOLTIP_DATA;\n\n const cursorPixelY = mousePos.plotCanvas.y;\n const cursorXPixel = mousePos.plotCanvas.x;\n const pointInGrid = getPointInGrid(cursorXPixel, cursorPixelY, chart);\n if (pointInGrid !== null) {\n const chartModel = chart['_model'];\n const yAxisScale = chartModel.getComponent('yAxis').axis.scale;\n const isLogScale = yAxisScale.type === 'log';\n let yInterval = yAxisScale._interval;\n // For log scales, convert from log-space extent to actual data range and use 1% as the interval.\n if (isLogScale && yAxisScale.base) {\n const logBase = yAxisScale.base;\n const extent = yAxisScale._extent;\n // e.g. extent [0, 2] → 10^0..10^2\n const actualMin = logBase ** extent[0];\n const actualMax = logBase ** extent[1];\n yInterval = (actualMax - actualMin) / 100;\n }\n const totalSeries = data.length;\n const yBuffer = getYBuffer({ yInterval, totalSeries, showAllSeries });\n\n const hasMultipleYAxes = seriesMapping.some((series) => series.yAxisIndex !== undefined && series.yAxisIndex > 0);\n\n return checkforNearbyTimeSeries(\n data,\n seriesMapping,\n pointInGrid,\n yBuffer,\n chart,\n format,\n seriesFormatMap,\n hasMultipleYAxes ? cursorPixelY : undefined,\n cursorXPixel,\n );\n }\n\n // no nearby series found\n return EMPTY_TOOLTIP_DATA;\n}\n\n/*\n * Check if two numbers are within a specified percentage range\n */\nexport function isWithinPercentageRange({\n valueToCheck,\n baseValue,\n percentage,\n}: IsWithinPercentageRangeParams): boolean {\n const range = (percentage / 100) * baseValue;\n const lowerBound = baseValue - range;\n const upperBound = baseValue + range;\n return valueToCheck >= lowerBound && valueToCheck <= upperBound;\n}\n\n/*\n * Get range to check within for nearby series to show in tooltip.\n */\nexport function getYBuffer({ yInterval, totalSeries, showAllSeries = false }: GetYBufferParams): number {\n if (showAllSeries) {\n return yInterval * 10; // roughly correlates with grid so entire canvas is searched\n }\n // never let nearby series range be less than roughly the size of a single tick\n const yBufferMin = yInterval * 0.3;\n\n // tooltip trigger area gets smaller with more series\n if (totalSeries > SHOW_FEWER_SERIES_LIMIT) {\n const adjustedBuffer = (yInterval * DYNAMIC_NEARBY_SERIES_MULTIPLIER) / totalSeries;\n return Math.max(yBufferMin, adjustedBuffer);\n }\n // increase multiplier to expand nearby series range\n return Math.max(yBufferMin, yInterval * INCREASE_NEARBY_SERIES_MULTIPLIER);\n}\n"],"names":["OPTIMIZED_MODE_SERIES_LIMIT","formatValue","batchDispatchNearbySeriesActions","getPointInGrid","getClosestTimestamp","EMPTY_TOOLTIP_DATA","calculateBarBandwidth","calculateBarSegmentBounds","calculateBarYBounds","calculateVisualYForSeries","getPixelXFromGrid","INCREASE_NEARBY_SERIES_MULTIPLIER","DYNAMIC_NEARBY_SERIES_MULTIPLIER","SHOW_FEWER_SERIES_LIMIT","gatherCandidates","data","seriesMapping","closestTimestamp","cursorX","cursorY","cursorXPixel","cursorPixelY","yBuffer","yBufferPixels","chart","candidates","totalSeries","length","stackTotals","Map","sortedTimestamps","firstValues","values","seen","Set","ts","has","add","push","sort","a","b","barSeriesIndexes","i","type","barBandwidth","barCenterPixelX","seriesIdx","currentSeries","currentDataset","currentDatasetValues","Array","isArray","seriesType","currentSeriesName","name","toString","seriesId","id","markerColor","color","datumIdx","xValue","yValue","tuple","undefined","isCandidate","visualY","distance","Infinity","dataPointPixel","convertToPixel","seriesIndex","pixelDistance","Math","abs","verticalDistance","barRelativeIdx","indexOf","segmentBounds","isWithinXBounds","left","right","stackId","stack","isHoveringYBounds","stackIdStr","visualYBottom","get","yBounds","cursorYPixel","top","bottom","segmentCenter","seriesName","date","x","y","findClosestCandidate","winner","candidate","processCandidates","format","seriesFormatMap","nonCandidateSeriesIndexes","nearbySeriesIndexes","emphasizedSeriesIndexes","nonEmphasizedSeriesIndexes","emphasizedDatapoints","duplicateDatapoints","yValueCounts","result","seriesFormat","displayY","formattedY","isClosestToCursor","duplicateValuesCount","set","dataIndex","checkforNearbyTimeSeries","pointInGrid","dispatchAction","firstTimeSeriesValues","cursorPoint","bufferPoint","resolvedCursorXPixel","candidateIndexes","idx","legacyCheckforNearbySeries","currentNearbySeriesData","timeSeries","xAxis","minPercentRange","percentRangeToCheck","max","isWithinPercentageRange","valueToCheck","baseValue","percentage","xValueMilliSeconds","notBlur","escapeConnect","getNearbySeriesData","mousePos","pinnedPos","showAllSeries","cursorTargetMatchesChart","target","currentParent","parentElement","currentGrandparent","chartDom","getDom","plotCanvas","chartModel","yAxisScale","getComponent","axis","scale","isLogScale","yInterval","_interval","base","logBase","extent","_extent","actualMin","actualMax","getYBuffer","hasMultipleYAxes","some","series","yAxisIndex","range","lowerBound","upperBound","yBufferMin","adjustedBuffer"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/TimeSeriesTooltip/nearby-series.ts"],"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 type { TimeSeries, TimeSeriesValueTuple } from '@perses-dev/spec';\nimport type { BarSeriesOption } from 'echarts/charts';\nimport type { ECharts as EChartsInstance } from 'echarts/core';\n\nimport type { EChartsDataFormat, TimeChartSeriesMapping, DatapointInfo, FormatOptions } from '../model';\nimport { OPTIMIZED_MODE_SERIES_LIMIT, formatValue } from '../model';\nimport { batchDispatchNearbySeriesActions, getPointInGrid, getClosestTimestamp } from '../utils';\nimport type { CursorCoordinates, CursorData } from './tooltip-model';\nimport { EMPTY_TOOLTIP_DATA } from './tooltip-model';\nimport type { Candidate, GetYBufferParams, IsWithinPercentageRangeParams, NearbySeriesArray } from './types';\nimport {\n calculateBarBandwidth,\n calculateBarSegmentBounds,\n calculateBarYBounds,\n calculateVisualYForSeries,\n getPixelXFromGrid,\n} from './utils';\n\nexport type { NearbySeriesArray, NearbySeriesInfo } from './types';\n\n// increase multipliers to show more series in tooltip\nexport const INCREASE_NEARBY_SERIES_MULTIPLIER = 5.5; // adjusts how many series show in tooltip (higher == more series shown)\nexport const DYNAMIC_NEARBY_SERIES_MULTIPLIER = 30; // used for adjustment after series number divisor\nexport const SHOW_FEWER_SERIES_LIMIT = 5;\n\nfunction gatherCandidates(\n data: TimeSeries[],\n seriesMapping: TimeChartSeriesMapping,\n closestTimestamp: number,\n cursorX: number,\n cursorY: number,\n cursorXPixel: number | null,\n cursorPixelY: number | undefined,\n yBuffer: number,\n yBufferPixels: number | null,\n chart: EChartsInstance,\n): Candidate[] {\n const candidates: Candidate[] = [];\n const totalSeries = data.length;\n\n const stackTotals = new Map<string, number>();\n\n let sortedTimestamps: number[] = [];\n const firstValues = data[0]?.values;\n if (firstValues && firstValues.length > 0) {\n const seen = new Set<number>();\n for (const [ts] of firstValues) {\n if (!seen.has(ts)) {\n seen.add(ts);\n sortedTimestamps.push(ts);\n }\n }\n sortedTimestamps = sortedTimestamps.toSorted((a, b) => a - b);\n }\n\n // Bar-only indexes: ECharts groups bars independently of lines, so bar-relative index and count must exclude line series.\n const barSeriesIndexes: number[] = [];\n for (let i = 0; i < totalSeries; i++) {\n if ((seriesMapping[i]?.type ?? 'line') === 'bar') barSeriesIndexes.push(i);\n }\n\n // Computed once outside the loop — both depend only on the timestamp, not the series index.\n let barBandwidth: number | null = null;\n let barCenterPixelX: number | null = null;\n if (barSeriesIndexes.length > 0 && cursorXPixel !== null) {\n barBandwidth = calculateBarBandwidth(closestTimestamp, sortedTimestamps, chart);\n barCenterPixelX = getPixelXFromGrid(closestTimestamp, chart);\n }\n\n for (let seriesIdx = 0; seriesIdx < totalSeries; seriesIdx++) {\n const currentSeries = seriesMapping[seriesIdx];\n if (!currentSeries) continue;\n\n const currentDataset = data[seriesIdx];\n if (!currentDataset) continue;\n\n const currentDatasetValues: TimeSeriesValueTuple[] | undefined = currentDataset.values;\n if (!currentDatasetValues || !Array.isArray(currentDatasetValues)) continue;\n\n const seriesType = currentSeries.type ?? 'line';\n const currentSeriesName = currentSeries.name ? currentSeries.name.toString() : '';\n const seriesId = currentSeries.id ? currentSeries.id.toString() : '';\n const markerColor = (currentSeries.color ?? '#000').toString();\n\n let datumIdx = -1;\n let xValue = 0;\n let yValue: number | null | undefined;\n for (let i = 0; i < currentDatasetValues.length; i++) {\n const tuple = currentDatasetValues[i];\n if (!tuple) continue;\n if (tuple[0] === closestTimestamp) {\n datumIdx = i;\n xValue = tuple[0];\n yValue = tuple[1];\n break;\n }\n }\n if (datumIdx === -1) continue;\n\n if (yValue === null || yValue === undefined) continue;\n\n let isCandidate = false;\n let visualY = yValue;\n let distance = Infinity;\n\n if (seriesType === 'line') {\n visualY = calculateVisualYForSeries(seriesIdx, yValue, seriesMapping, stackTotals);\n\n if (cursorPixelY !== undefined && yBufferPixels !== null) {\n try {\n const dataPointPixel = chart.convertToPixel({ seriesIndex: seriesIdx }, [datumIdx, visualY]);\n if (dataPointPixel && dataPointPixel[1] !== undefined) {\n const pixelDistance = Math.abs(cursorPixelY - dataPointPixel[1]);\n isCandidate = pixelDistance <= yBufferPixels;\n distance = pixelDistance;\n } else {\n const verticalDistance = Math.abs(visualY - cursorY);\n isCandidate = verticalDistance <= yBuffer;\n distance = verticalDistance;\n }\n } catch {\n const verticalDistance = Math.abs(visualY - cursorY);\n isCandidate = verticalDistance <= yBuffer;\n distance = verticalDistance;\n }\n } else {\n const verticalDistance = Math.abs(visualY - cursorY);\n isCandidate = verticalDistance <= yBuffer;\n distance = verticalDistance;\n }\n } else if (seriesType === 'bar') {\n if (cursorXPixel === null || barBandwidth === null || barCenterPixelX === null) continue;\n\n const barRelativeIdx = barSeriesIndexes.indexOf(seriesIdx);\n if (barRelativeIdx === -1) continue;\n\n const segmentBounds = calculateBarSegmentBounds(\n barRelativeIdx,\n barBandwidth,\n barCenterPixelX,\n barSeriesIndexes.length,\n );\n\n const isWithinXBounds = cursorXPixel >= segmentBounds.left && cursorXPixel <= segmentBounds.right;\n if (!isWithinXBounds) continue;\n\n const stackId = (currentSeries as BarSeriesOption).stack;\n let isHoveringYBounds = true;\n\n if (stackId) {\n const stackIdStr = stackId.toString();\n const visualYBottom = stackTotals.get(stackIdStr) ?? 0;\n visualY = calculateVisualYForSeries(seriesIdx, yValue, seriesMapping, stackTotals);\n const yBounds = calculateBarYBounds(visualYBottom, visualY, chart);\n\n if (yBounds) {\n const cursorYPixel = chart.convertToPixel('grid', [0, cursorY]);\n if (cursorYPixel && cursorYPixel[1] !== undefined) {\n isHoveringYBounds = cursorYPixel[1] >= yBounds.top && cursorYPixel[1] <= yBounds.bottom;\n }\n }\n } else {\n visualY = yValue;\n }\n\n if (!isHoveringYBounds) continue;\n\n const segmentCenter = (segmentBounds.left + segmentBounds.right) / 2;\n distance = Math.abs(cursorXPixel - segmentCenter);\n isCandidate = true;\n }\n\n if (isCandidate) {\n candidates.push({\n seriesIdx,\n datumIdx,\n seriesId,\n seriesName: currentSeriesName,\n date: closestTimestamp,\n markerColor,\n x: xValue,\n y: yValue,\n visualY,\n distance,\n });\n }\n }\n\n return candidates;\n}\n\nfunction findClosestCandidate(candidates: Candidate[]): Candidate | null {\n if (candidates.length === 0) return null;\n let winner: Candidate | null = null;\n for (const candidate of candidates) {\n if (winner === null || candidate.distance < winner.distance) {\n winner = candidate;\n }\n }\n return winner;\n}\n\nfunction processCandidates(\n candidates: Candidate[],\n winner: Candidate | null,\n format: FormatOptions | undefined,\n seriesFormatMap: Map<string, FormatOptions> | undefined,\n chart: EChartsInstance,\n nonCandidateSeriesIndexes: number[],\n): NearbySeriesArray {\n const nearbySeriesIndexes: number[] = [];\n const emphasizedSeriesIndexes: number[] = [];\n const nonEmphasizedSeriesIndexes: number[] = [...nonCandidateSeriesIndexes];\n const emphasizedDatapoints: DatapointInfo[] = [];\n const duplicateDatapoints: DatapointInfo[] = [];\n const yValueCounts: Map<number, number> = new Map();\n\n const result: NearbySeriesArray = [];\n\n for (const candidate of candidates) {\n const seriesFormat = seriesFormatMap?.get(candidate.seriesId) ?? format;\n // Use raw y, not visualY — visualY is for proximity detection only.\n const displayY = candidate.y;\n const formattedY = formatValue(displayY, seriesFormat);\n const isClosestToCursor = winner !== null && candidate.seriesIdx === winner.seriesIdx;\n\n if (isClosestToCursor) {\n emphasizedSeriesIndexes.push(candidate.seriesIdx);\n\n const duplicateValuesCount = yValueCounts.get(displayY) ?? 0;\n yValueCounts.set(displayY, duplicateValuesCount + 1);\n if (duplicateValuesCount > 0) {\n duplicateDatapoints.push({\n seriesIndex: candidate.seriesIdx,\n dataIndex: candidate.datumIdx,\n seriesName: candidate.seriesName,\n yValue: displayY,\n });\n }\n\n emphasizedDatapoints.push({\n seriesIndex: candidate.seriesIdx,\n dataIndex: candidate.datumIdx,\n seriesName: candidate.seriesName,\n yValue: displayY,\n });\n } else {\n nonEmphasizedSeriesIndexes.push(candidate.seriesIdx);\n }\n\n result.push({\n seriesIdx: candidate.seriesIdx,\n datumIdx: candidate.datumIdx,\n seriesName: candidate.seriesName,\n date: candidate.date,\n x: candidate.x,\n y: displayY,\n formattedY,\n markerColor: candidate.markerColor,\n isClosestToCursor,\n });\n\n nearbySeriesIndexes.push(candidate.seriesIdx);\n }\n\n batchDispatchNearbySeriesActions(\n chart,\n nearbySeriesIndexes,\n emphasizedSeriesIndexes,\n nonEmphasizedSeriesIndexes,\n emphasizedDatapoints,\n duplicateDatapoints,\n );\n\n return result;\n}\n\n/**\n * Returns formatted series data for the points that are close to the user's cursor.\n * Adjust xBuffer and yBuffer to increase or decrease number of series shown.\n */\nexport function checkforNearbyTimeSeries(\n data: TimeSeries[],\n seriesMapping: TimeChartSeriesMapping,\n pointInGrid: number[],\n yBuffer: number,\n chart: EChartsInstance,\n format?: FormatOptions,\n seriesFormatMap?: Map<string, FormatOptions>,\n // in the case of multi-axis, we need the cursor Y position in pixel space\n cursorPixelY?: number,\n cursorXPixel?: number | null,\n): NearbySeriesArray {\n const cursorX: number | null = pointInGrid[0] ?? null;\n const cursorY: number | null = pointInGrid[1] ?? null;\n\n if (cursorX === null || cursorY === null) return EMPTY_TOOLTIP_DATA;\n if (chart.dispatchAction === undefined) return EMPTY_TOOLTIP_DATA;\n if (!Array.isArray(data)) return EMPTY_TOOLTIP_DATA;\n\n // All series share the same x-axis timestamps (enforced by getCommonTimeScale).\n const firstTimeSeriesValues = data[0]?.values;\n const closestTimestamp = getClosestTimestamp(firstTimeSeriesValues, cursorX);\n if (closestTimestamp === null) return EMPTY_TOOLTIP_DATA;\n\n let yBufferPixels: number | null = null;\n if (cursorPixelY !== undefined) {\n const cursorPoint = chart.convertToPixel('grid', [0, cursorY]);\n const bufferPoint = chart.convertToPixel('grid', [0, cursorY + yBuffer]);\n if (cursorPoint && bufferPoint && cursorPoint[1] !== undefined && bufferPoint[1] !== undefined) {\n yBufferPixels = Math.abs(bufferPoint[1] - cursorPoint[1]);\n }\n }\n\n const resolvedCursorXPixel = cursorXPixel ?? getPixelXFromGrid(closestTimestamp, chart);\n\n const candidates = gatherCandidates(\n data,\n seriesMapping,\n closestTimestamp,\n cursorX,\n cursorY,\n resolvedCursorXPixel,\n cursorPixelY,\n yBuffer,\n yBufferPixels,\n chart,\n );\n\n const winner = findClosestCandidate(candidates);\n\n const candidateIndexes = new Set<number>();\n for (const candidate of candidates) candidateIndexes.add(candidate.seriesIdx);\n const nonCandidateSeriesIndexes: number[] = [];\n for (let idx = 0; idx < data.length; idx++) {\n if (!candidateIndexes.has(idx)) nonCandidateSeriesIndexes.push(idx);\n }\n\n return processCandidates(candidates, winner, format, seriesFormatMap, chart, nonCandidateSeriesIndexes);\n}\n\n/**\n * [DEPRECATED] Returns formatted series data for the points that are close to the user's cursor\n * Adjust yBuffer to increase or decrease number of series shown\n */\nexport function legacyCheckforNearbySeries(\n data: EChartsDataFormat,\n pointInGrid: number[],\n yBuffer: number,\n chart?: EChartsInstance,\n format?: FormatOptions,\n): NearbySeriesArray {\n const currentNearbySeriesData: NearbySeriesArray = [];\n const cursorX: number | null = pointInGrid[0] ?? null;\n const cursorY: number | null = pointInGrid[1] ?? null;\n\n if (cursorX === null || cursorY === null) {\n return currentNearbySeriesData;\n }\n\n const nearbySeriesIndexes: number[] = [];\n const emphasizedSeriesIndexes: number[] = [];\n const nonEmphasizedSeriesIndexes: number[] = [];\n const totalSeries = data.timeSeries.length;\n if (Array.isArray(data.xAxis) && Array.isArray(data.timeSeries)) {\n for (let seriesIdx = 0; seriesIdx < totalSeries; seriesIdx++) {\n const currentSeries = data.timeSeries[seriesIdx];\n if (currentSeries === undefined) break;\n if (currentNearbySeriesData.length >= OPTIMIZED_MODE_SERIES_LIMIT) break;\n\n const currentSeriesName = currentSeries.name ? currentSeries.name.toString() : '';\n const markerColor = currentSeries.color ?? '#000';\n if (Array.isArray(currentSeries.data)) {\n for (let datumIdx = 0; datumIdx < currentSeries.data.length; datumIdx++) {\n const xValue = data.xAxis[datumIdx] ?? 0;\n const yValue = currentSeries.data[datumIdx];\n // ensure null values not displayed in tooltip\n if (yValue !== undefined && yValue !== null && cursorX === datumIdx) {\n if (yValue !== '-' && cursorY <= yValue + yBuffer && cursorY >= yValue - yBuffer) {\n // show fewer bold series in tooltip when many total series\n const minPercentRange = totalSeries > SHOW_FEWER_SERIES_LIMIT ? 2 : 5;\n const percentRangeToCheck = Math.max(minPercentRange, 100 / totalSeries);\n const isClosestToCursor = isWithinPercentageRange({\n valueToCheck: cursorY,\n baseValue: yValue,\n percentage: percentRangeToCheck,\n });\n if (isClosestToCursor) {\n emphasizedSeriesIndexes.push(seriesIdx);\n } else {\n nonEmphasizedSeriesIndexes.push(seriesIdx);\n // ensure series not close to cursor are not highlighted\n if (chart?.dispatchAction !== undefined) {\n chart.dispatchAction({\n type: 'downplay',\n seriesIndex: seriesIdx,\n });\n }\n }\n\n // determine whether to convert timestamp to ms, see: https://stackoverflow.com/a/23982005/17575201\n const xValueMilliSeconds = xValue > 99999999999 ? xValue : xValue * 1000;\n const formattedY = formatValue(yValue, format);\n currentNearbySeriesData.push({\n seriesIdx: seriesIdx,\n datumIdx: datumIdx,\n seriesName: currentSeriesName,\n date: xValueMilliSeconds,\n x: xValue,\n y: yValue,\n formattedY: formattedY,\n markerColor: markerColor.toString(),\n isClosestToCursor,\n });\n nearbySeriesIndexes.push(seriesIdx);\n }\n }\n }\n }\n }\n }\n if (chart?.dispatchAction !== undefined) {\n // Clears emphasis state of all lines that are not emphasized.\n // Emphasized is a subset of just the nearby series that are closest to cursor.\n chart.dispatchAction({\n type: 'downplay',\n seriesIndex: nonEmphasizedSeriesIndexes,\n });\n\n // https://echarts.apache.org/en/api.html#action.highlight\n if (emphasizedSeriesIndexes.length > 0) {\n // Fadeout opacity of all series not closest to cursor.\n chart.dispatchAction({\n type: 'highlight',\n seriesIndex: emphasizedSeriesIndexes,\n notBlur: false, // ensure blur IS triggered, this is default but setting so it is explicit\n escapeConnect: true, // shared crosshair should not emphasize series on adjacent charts\n });\n } else {\n // When no emphasized series with bold text, notBlur allows opacity fadeout to not trigger.\n chart.dispatchAction({\n type: 'highlight',\n seriesIndex: nearbySeriesIndexes,\n notBlur: true, // do not trigger blur state when cursor is not immediately close to any series\n escapeConnect: true, // shared crosshair should not emphasize series on adjacent charts\n });\n }\n }\n\n return currentNearbySeriesData;\n}\n\n/**\n * Uses mouse position to determine whether user is hovering over a chart canvas\n * If yes, convert from pixel values to logical cartesian coordinates and return all nearby series\n */\nexport function getNearbySeriesData({\n mousePos,\n pinnedPos,\n data,\n seriesMapping,\n chart,\n format,\n seriesFormatMap,\n showAllSeries = false,\n}: {\n mousePos: CursorData['coords'];\n pinnedPos: CursorCoordinates | null;\n data: TimeSeries[];\n seriesMapping: TimeChartSeriesMapping;\n chart?: EChartsInstance;\n format?: FormatOptions;\n seriesFormatMap?: Map<string, FormatOptions>;\n showAllSeries?: boolean;\n}): NearbySeriesArray {\n if (chart === undefined || mousePos === null) return EMPTY_TOOLTIP_DATA;\n\n // prevents multiple tooltips showing from adjacent charts unless tooltip is pinned\n let cursorTargetMatchesChart = false;\n if (mousePos.target !== null) {\n const currentParent = (<HTMLElement>mousePos.target).parentElement;\n if (currentParent !== null) {\n const currentGrandparent = currentParent.parentElement;\n if (currentGrandparent !== null) {\n const chartDom = chart.getDom();\n if (chartDom === currentGrandparent) {\n cursorTargetMatchesChart = true;\n }\n }\n }\n }\n\n // allows moving cursor inside tooltip without it fading away\n if (pinnedPos !== null) {\n mousePos = pinnedPos;\n cursorTargetMatchesChart = true;\n }\n\n if (cursorTargetMatchesChart === false || data === null || chart['_model'] === undefined) return EMPTY_TOOLTIP_DATA;\n\n if (mousePos.plotCanvas.x === undefined || mousePos.plotCanvas.y === undefined) return EMPTY_TOOLTIP_DATA;\n\n const cursorPixelY = mousePos.plotCanvas.y;\n const cursorXPixel = mousePos.plotCanvas.x;\n const pointInGrid = getPointInGrid(cursorXPixel, cursorPixelY, chart);\n if (pointInGrid !== null) {\n const chartModel = chart['_model'];\n const yAxisScale = chartModel.getComponent('yAxis').axis.scale;\n const isLogScale = yAxisScale.type === 'log';\n let yInterval = yAxisScale._interval;\n // For log scales, convert from log-space extent to actual data range and use 1% as the interval.\n if (isLogScale && yAxisScale.base) {\n const logBase = yAxisScale.base;\n const extent = yAxisScale._extent;\n // e.g. extent [0, 2] → 10^0..10^2\n const actualMin = logBase ** extent[0];\n const actualMax = logBase ** extent[1];\n yInterval = (actualMax - actualMin) / 100;\n }\n const totalSeries = data.length;\n const yBuffer = getYBuffer({ yInterval, totalSeries, showAllSeries });\n\n const hasMultipleYAxes = seriesMapping.some((series) => series.yAxisIndex !== undefined && series.yAxisIndex > 0);\n\n return checkforNearbyTimeSeries(\n data,\n seriesMapping,\n pointInGrid,\n yBuffer,\n chart,\n format,\n seriesFormatMap,\n hasMultipleYAxes ? cursorPixelY : undefined,\n cursorXPixel,\n );\n }\n\n // no nearby series found\n return EMPTY_TOOLTIP_DATA;\n}\n\n/*\n * Check if two numbers are within a specified percentage range\n */\nexport function isWithinPercentageRange({\n valueToCheck,\n baseValue,\n percentage,\n}: IsWithinPercentageRangeParams): boolean {\n const range = (percentage / 100) * baseValue;\n const lowerBound = baseValue - range;\n const upperBound = baseValue + range;\n return valueToCheck >= lowerBound && valueToCheck <= upperBound;\n}\n\n/*\n * Get range to check within for nearby series to show in tooltip.\n */\nexport function getYBuffer({ yInterval, totalSeries, showAllSeries = false }: GetYBufferParams): number {\n if (showAllSeries) {\n return yInterval * 10; // roughly correlates with grid so entire canvas is searched\n }\n // never let nearby series range be less than roughly the size of a single tick\n const yBufferMin = yInterval * 0.3;\n\n // tooltip trigger area gets smaller with more series\n if (totalSeries > SHOW_FEWER_SERIES_LIMIT) {\n const adjustedBuffer = (yInterval * DYNAMIC_NEARBY_SERIES_MULTIPLIER) / totalSeries;\n return Math.max(yBufferMin, adjustedBuffer);\n }\n // increase multiplier to expand nearby series range\n return Math.max(yBufferMin, yInterval * INCREASE_NEARBY_SERIES_MULTIPLIER);\n}\n"],"names":["OPTIMIZED_MODE_SERIES_LIMIT","formatValue","batchDispatchNearbySeriesActions","getPointInGrid","getClosestTimestamp","EMPTY_TOOLTIP_DATA","calculateBarBandwidth","calculateBarSegmentBounds","calculateBarYBounds","calculateVisualYForSeries","getPixelXFromGrid","INCREASE_NEARBY_SERIES_MULTIPLIER","DYNAMIC_NEARBY_SERIES_MULTIPLIER","SHOW_FEWER_SERIES_LIMIT","gatherCandidates","data","seriesMapping","closestTimestamp","cursorX","cursorY","cursorXPixel","cursorPixelY","yBuffer","yBufferPixels","chart","candidates","totalSeries","length","stackTotals","Map","sortedTimestamps","firstValues","values","seen","Set","ts","has","add","push","toSorted","a","b","barSeriesIndexes","i","type","barBandwidth","barCenterPixelX","seriesIdx","currentSeries","currentDataset","currentDatasetValues","Array","isArray","seriesType","currentSeriesName","name","toString","seriesId","id","markerColor","color","datumIdx","xValue","yValue","tuple","undefined","isCandidate","visualY","distance","Infinity","dataPointPixel","convertToPixel","seriesIndex","pixelDistance","Math","abs","verticalDistance","barRelativeIdx","indexOf","segmentBounds","isWithinXBounds","left","right","stackId","stack","isHoveringYBounds","stackIdStr","visualYBottom","get","yBounds","cursorYPixel","top","bottom","segmentCenter","seriesName","date","x","y","findClosestCandidate","winner","candidate","processCandidates","format","seriesFormatMap","nonCandidateSeriesIndexes","nearbySeriesIndexes","emphasizedSeriesIndexes","nonEmphasizedSeriesIndexes","emphasizedDatapoints","duplicateDatapoints","yValueCounts","result","seriesFormat","displayY","formattedY","isClosestToCursor","duplicateValuesCount","set","dataIndex","checkforNearbyTimeSeries","pointInGrid","dispatchAction","firstTimeSeriesValues","cursorPoint","bufferPoint","resolvedCursorXPixel","candidateIndexes","idx","legacyCheckforNearbySeries","currentNearbySeriesData","timeSeries","xAxis","minPercentRange","percentRangeToCheck","max","isWithinPercentageRange","valueToCheck","baseValue","percentage","xValueMilliSeconds","notBlur","escapeConnect","getNearbySeriesData","mousePos","pinnedPos","showAllSeries","cursorTargetMatchesChart","target","currentParent","parentElement","currentGrandparent","chartDom","getDom","plotCanvas","chartModel","yAxisScale","getComponent","axis","scale","isLogScale","yInterval","_interval","base","logBase","extent","_extent","actualMin","actualMax","getYBuffer","hasMultipleYAxes","some","series","yAxisIndex","range","lowerBound","upperBound","yBufferMin","adjustedBuffer"],"mappings":"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"}
@@ -35,7 +35,9 @@
35
35
  try {
36
36
  return new RegExp(pattern, flags);
37
37
  } catch (error) {
38
- throw new Error(`Failed to create RegExp ${error}`);
38
+ throw new Error(`Failed to create RegExp ${error}`, {
39
+ cause: error
40
+ });
39
41
  }
40
42
  }
41
43
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/regexp.ts"],"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\n/**\n * Checks if a string is a regex pattern.\n */\nexport function isRegexPattern(input: string | null | undefined): boolean {\n return Boolean(input?.startsWith('/'));\n}\n\n/**\n * Converts a string to RegExp. Handles both regular strings and regex patterns.\n * For regular strings, creates exact match regex.\n * For patterns like \"/pattern/flags\", creates corresponding RegExp.\n */\nexport function createRegexFromString(input: string): RegExp {\n if (!input) {\n throw new Error('Input string cannot be empty');\n }\n\n if (!isRegexPattern(input)) {\n return new RegExp(`^${input}$`);\n }\n\n const regexPattern = /^\\/(.+)\\/([gimy]*)$/;\n const matches = input.match(regexPattern);\n\n if (!matches) {\n throw new Error(`Invalid regular expression format: ${input}`);\n }\n\n const [, pattern = '', flags = ''] = matches;\n\n try {\n return new RegExp(pattern, flags);\n } catch (error) {\n throw new Error(`Failed to create RegExp ${error}`);\n }\n}\n"],"names":["isRegexPattern","input","Boolean","startsWith","createRegexFromString","Error","RegExp","regexPattern","matches","match","pattern","flags","error"],"mappings":"AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC;;CAEC,GACD,OAAO,SAASA,eAAeC,KAAgC;IAC7D,OAAOC,QAAQD,OAAOE,WAAW;AACnC;AAEA;;;;CAIC,GACD,OAAO,SAASC,sBAAsBH,KAAa;IACjD,IAAI,CAACA,OAAO;QACV,MAAM,IAAII,MAAM;IAClB;IAEA,IAAI,CAACL,eAAeC,QAAQ;QAC1B,OAAO,IAAIK,OAAO,CAAC,CAAC,EAAEL,MAAM,CAAC,CAAC;IAChC;IAEA,MAAMM,eAAe;IACrB,MAAMC,UAAUP,MAAMQ,KAAK,CAACF;IAE5B,IAAI,CAACC,SAAS;QACZ,MAAM,IAAIH,MAAM,CAAC,mCAAmC,EAAEJ,OAAO;IAC/D;IAEA,MAAM,GAAGS,UAAU,EAAE,EAAEC,QAAQ,EAAE,CAAC,GAAGH;IAErC,IAAI;QACF,OAAO,IAAIF,OAAOI,SAASC;IAC7B,EAAE,OAAOC,OAAO;QACd,MAAM,IAAIP,MAAM,CAAC,wBAAwB,EAAEO,OAAO;IACpD;AACF"}
1
+ {"version":3,"sources":["../../src/utils/regexp.ts"],"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\n/**\n * Checks if a string is a regex pattern.\n */\nexport function isRegexPattern(input: string | null | undefined): boolean {\n return Boolean(input?.startsWith('/'));\n}\n\n/**\n * Converts a string to RegExp. Handles both regular strings and regex patterns.\n * For regular strings, creates exact match regex.\n * For patterns like \"/pattern/flags\", creates corresponding RegExp.\n */\nexport function createRegexFromString(input: string): RegExp {\n if (!input) {\n throw new Error('Input string cannot be empty');\n }\n\n if (!isRegexPattern(input)) {\n return new RegExp(`^${input}$`);\n }\n\n const regexPattern = /^\\/(.+)\\/([gimy]*)$/;\n const matches = input.match(regexPattern);\n\n if (!matches) {\n throw new Error(`Invalid regular expression format: ${input}`);\n }\n\n const [, pattern = '', flags = ''] = matches;\n\n try {\n return new RegExp(pattern, flags);\n } catch (error) {\n throw new Error(`Failed to create RegExp ${error}`, { cause: error });\n }\n}\n"],"names":["isRegexPattern","input","Boolean","startsWith","createRegexFromString","Error","RegExp","regexPattern","matches","match","pattern","flags","error","cause"],"mappings":"AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC;;CAEC,GACD,OAAO,SAASA,eAAeC,KAAgC;IAC7D,OAAOC,QAAQD,OAAOE,WAAW;AACnC;AAEA;;;;CAIC,GACD,OAAO,SAASC,sBAAsBH,KAAa;IACjD,IAAI,CAACA,OAAO;QACV,MAAM,IAAII,MAAM;IAClB;IAEA,IAAI,CAACL,eAAeC,QAAQ;QAC1B,OAAO,IAAIK,OAAO,CAAC,CAAC,EAAEL,MAAM,CAAC,CAAC;IAChC;IAEA,MAAMM,eAAe;IACrB,MAAMC,UAAUP,MAAMQ,KAAK,CAACF;IAE5B,IAAI,CAACC,SAAS;QACZ,MAAM,IAAIH,MAAM,CAAC,mCAAmC,EAAEJ,OAAO;IAC/D;IAEA,MAAM,GAAGS,UAAU,EAAE,EAAEC,QAAQ,EAAE,CAAC,GAAGH;IAErC,IAAI;QACF,OAAO,IAAIF,OAAOI,SAASC;IAC7B,EAAE,OAAOC,OAAO;QACd,MAAM,IAAIP,MAAM,CAAC,wBAAwB,EAAEO,OAAO,EAAE;YAAEC,OAAOD;QAAM;IACrE;AACF"}
@@ -203,7 +203,7 @@
203
203
  }
204
204
  // Ordering data column alphabetically
205
205
  result = result.map((row)=>{
206
- return Object.keys(row).sort().reduce((obj, key)=>{
206
+ return Object.keys(row).toSorted().reduce((obj, key)=>{
207
207
  obj[key] = row[key];
208
208
  return obj;
209
209
  }, {});
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/transform-data.ts"],"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 type { Transform } from '../model';\n\n/*\n * Join: Regroup rows with equal cell value in a column.\n * If there are multiple line with same value, next row values override the current one\n *\n * Example: Join on 'mount' column\n * INPUT:\n * | timestamp | value #1 | value #3 | mount |\n * |------------|----------|----------|-----------|\n * | 1630000000 | 1 | | / |\n * | 1630000000 | 2 | | /boot/efi |\n * | 1630000000 | | 3 | / |\n * | 1630000000 | | 4 | /boot/efi |\n *\n * OUTPUT:\n * | timestamp | value #1 | value #3 | mount |\n * |------------|----------|----------|-----------|\n * | 1630000000 | 1 | 3 | / |\n * | 1630000000 | 2 | 4 | /boot/efi |\n */\nexport function applyJoinTransform(\n data: Array<Record<string, unknown>>,\n columns: string[],\n): Array<Record<string, unknown>> {\n // If column is undefined or empty, return data as is\n if (columns.length === 0) {\n return data;\n }\n\n const rowHashed: { [key: string]: Record<string, unknown> } = {};\n\n for (const row of data) {\n const rowHash = Object.keys(row)\n .filter((k) => columns.includes(k))\n .map((k) => row[k])\n .join('|');\n\n const rowHashedValue = rowHashed[rowHash];\n if (rowHashedValue) {\n rowHashed[rowHash] = { ...rowHashedValue, ...row };\n } else {\n rowHashed[rowHash] = { ...row };\n }\n }\n return Object.values(rowHashed);\n}\n\n/*\n * Merges selected columns into a single column.\n *\n * Example: Merge columns 'value #1' and 'value #2' into a single column 'MERGED'\n * INPUT:\n * +------------+----------+----------+-----------+-----------+\n * | timestamp | value #1 | value #2 | mount #1 | mount #2 |\n * +------------+----------+----------+-----------+-----------+\n * | 1630000000 | 1 | | / | |\n * | 1630000000 | 2 | | /boot/efi | |\n * | 1630000000 | | 3 | | / |\n * | 1630000000 | | 4 | | /boot/efi |\n * +------------+----------+----------+-----------+-----------+\n *\n * OUTPUT:\n * +------------+--------+-----------+-----------+\n * | timestamp | MERGED | mount #1 | mount #2 |\n * +------------+--------+-----------+-----------+\n * | 1630000000 | 1 | / | |\n * | 1630000000 | 2 | /boot/efi | |\n * | 1630000000 | 2 | | / |\n * | 1630000000 | 3 | | /boot/efi |\n * +------------+--------+-----------+-----------+\n */\nexport function applyMergeColumnsTransform(\n data: Array<Record<string, unknown>>,\n selectedColumns: string[],\n outputName: string,\n): Array<Record<string, unknown>> {\n const result: Array<Record<string, unknown>> = [];\n\n for (const row of data) {\n const columns = Object.keys(row).filter((k) => selectedColumns.includes(k));\n\n const selectedColumnValues: Record<string, unknown> = {};\n\n for (const column of columns) {\n selectedColumnValues[column] = row[column];\n delete row[column];\n }\n\n for (const column of columns) {\n result.push({ ...row, [outputName]: selectedColumnValues[column] });\n }\n\n if (columns.length === 0) {\n result.push(row);\n }\n }\n\n return result;\n}\n\n/*\n * Merge Indexed Columns: All indexed columns are merged to one column\n *\n * Example: Join on 'value' column\n * INPUT:\n * | timestamp #1 | timestamp #2 | value #1 | value #2 | instance #1 | instance #2 |\n * |--------------|--------------|----------|----------|-------------|-------------|\n * | 1630000000 | | 55 | | toto | |\n * | 1630000000 | | 33 | | toto | |\n * | 1630000000 | | 45 | | toto | |\n * | | 1630000000 | | 112 | | titi |\n * | | 1630000000 | | 20 | | titi |\n * | | 1630000000 | | 10 | | titi |\n *\n * OUTPUT:\n * | timestamp #1 | timestamp #2 | value | instance #1 | instance #2 |\n * |--------------|--------------|-------|-------------|-------------|\n * | 1630000000 | | 55 | toto | |\n * | 1630000000 | | 33 | toto | |\n * | 1630000000 | | 45 | toto | |\n * | | 1630000000 | 112 | | titi |\n * | | 1630000000 | 20 | | titi |\n * | | 1630000000 | 10 | | titi |\n */\nexport function applyMergeIndexedColumnsTransform(\n data: Array<Record<string, unknown>>,\n column: string,\n): Array<Record<string, unknown>> {\n const result: Array<Record<string, unknown>> = [];\n\n for (const entry of data) {\n const indexedColumns = Object.keys(entry).filter((k) =>\n new RegExp('^((' + column + ' #\\\\d+)|(' + column + '))$').test(k),\n );\n const indexedColumnValues: Record<string, unknown> = {};\n\n for (const indexedColumn of indexedColumns) {\n indexedColumnValues[indexedColumn] = entry[indexedColumn];\n delete entry[indexedColumn];\n }\n\n for (const indexedColumn of indexedColumns) {\n result.push({ ...entry, [column]: indexedColumnValues[indexedColumn] });\n }\n\n if (indexedColumns.length === 0) {\n result.push(entry);\n }\n }\n\n return result;\n}\n\n/*\n * Merge Indexed Columns: All indexed columns are merged to one column\n *\n * INPUT:\n * | timestamp | value #1 | value #2 | mount #1 | mount #2 | instance #1 | instance #2 | env #1 | env #2 |\n * |------------|----------|----------|-----------|-----------|-------------|-------------|--------|--------|\n * | 1630000000 | 1 | | / | | test:44 | | prd | |\n * | 1630000000 | 2 | | /boot/efi | | test:44 | | prd | |\n * | 1630000000 | | 5 | | / | | test:44 | | prd |\n * | 1630000000 | | 6 | | /boot/efi | | test:44 | | prd |\n *\n * OUTPUT:\n * | timestamp | value #1 | value #2 | mount | instance | env |\n * |------------|----------|----------|-----------|----------|-----|\n * | 1630000000 | 1 | 5 | / | test:44 | prd |\n * | 1630000000 | 2 | 6 | /boot/efi | test:44 | prd |\n */\nexport function applyMergeSeriesTransform(data: Array<Record<string, unknown>>): Array<Record<string, unknown>> {\n let result: Array<Record<string, unknown>> = [...data];\n\n const labelColumns = Array.from(\n new Set(\n data\n .flatMap(Object.keys)\n .map((label) => label.replace(/ #\\d+/, ''))\n .filter((label) => label !== 'value'),\n ),\n );\n\n for (const label of labelColumns) {\n result = applyMergeIndexedColumnsTransform(result, label);\n }\n\n result = applyJoinTransform(result, labelColumns);\n\n return result;\n}\n\n/*\n * Transforms query data with the given transforms\n */\nexport function transformData(\n data: Array<Record<string, unknown>>,\n transforms: Transform[],\n): Array<Record<string, unknown>> {\n let result: Array<Record<string, unknown>> = data;\n\n // Apply transforms by their orders\n for (const transform of transforms ?? []) {\n if (transform.spec.disabled) continue;\n\n switch (transform.kind) {\n case 'JoinByColumnValue': {\n if (transform.spec.columns && transform.spec.columns.length > 0) {\n result = applyJoinTransform(result, transform.spec.columns);\n }\n break;\n }\n case 'MergeIndexedColumns': {\n if (transform.spec.column) {\n result = applyMergeIndexedColumnsTransform(result, transform.spec.column);\n }\n break;\n }\n case 'MergeColumns': {\n if (transform.spec.columns && transform.spec.columns.length > 0 && transform.spec.name) {\n result = applyMergeColumnsTransform(result, transform.spec.columns, transform.spec.name);\n }\n break;\n }\n case 'MergeSeries': {\n result = applyMergeSeriesTransform(result);\n break;\n }\n }\n }\n\n // Ordering data column alphabetically\n result = result.map((row) => {\n return Object.keys(row)\n .sort()\n .reduce((obj: Record<string, unknown>, key: string) => {\n obj[key] = row[key];\n return obj;\n }, {});\n });\n return result;\n}\n"],"names":["applyJoinTransform","data","columns","length","rowHashed","row","rowHash","Object","keys","filter","k","includes","map","join","rowHashedValue","values","applyMergeColumnsTransform","selectedColumns","outputName","result","selectedColumnValues","column","push","applyMergeIndexedColumnsTransform","entry","indexedColumns","RegExp","test","indexedColumnValues","indexedColumn","applyMergeSeriesTransform","labelColumns","Array","from","Set","flatMap","label","replace","transformData","transforms","transform","spec","disabled","kind","name","sort","reduce","obj","key"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/utils/transform-data.ts"],"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 type { Transform } from '../model';\n\n/*\n * Join: Regroup rows with equal cell value in a column.\n * If there are multiple line with same value, next row values override the current one\n *\n * Example: Join on 'mount' column\n * INPUT:\n * | timestamp | value #1 | value #3 | mount |\n * |------------|----------|----------|-----------|\n * | 1630000000 | 1 | | / |\n * | 1630000000 | 2 | | /boot/efi |\n * | 1630000000 | | 3 | / |\n * | 1630000000 | | 4 | /boot/efi |\n *\n * OUTPUT:\n * | timestamp | value #1 | value #3 | mount |\n * |------------|----------|----------|-----------|\n * | 1630000000 | 1 | 3 | / |\n * | 1630000000 | 2 | 4 | /boot/efi |\n */\nexport function applyJoinTransform(\n data: Array<Record<string, unknown>>,\n columns: string[],\n): Array<Record<string, unknown>> {\n // If column is undefined or empty, return data as is\n if (columns.length === 0) {\n return data;\n }\n\n const rowHashed: { [key: string]: Record<string, unknown> } = {};\n\n for (const row of data) {\n const rowHash = Object.keys(row)\n .filter((k) => columns.includes(k))\n .map((k) => row[k])\n .join('|');\n\n const rowHashedValue = rowHashed[rowHash];\n if (rowHashedValue) {\n rowHashed[rowHash] = { ...rowHashedValue, ...row };\n } else {\n rowHashed[rowHash] = { ...row };\n }\n }\n return Object.values(rowHashed);\n}\n\n/*\n * Merges selected columns into a single column.\n *\n * Example: Merge columns 'value #1' and 'value #2' into a single column 'MERGED'\n * INPUT:\n * +------------+----------+----------+-----------+-----------+\n * | timestamp | value #1 | value #2 | mount #1 | mount #2 |\n * +------------+----------+----------+-----------+-----------+\n * | 1630000000 | 1 | | / | |\n * | 1630000000 | 2 | | /boot/efi | |\n * | 1630000000 | | 3 | | / |\n * | 1630000000 | | 4 | | /boot/efi |\n * +------------+----------+----------+-----------+-----------+\n *\n * OUTPUT:\n * +------------+--------+-----------+-----------+\n * | timestamp | MERGED | mount #1 | mount #2 |\n * +------------+--------+-----------+-----------+\n * | 1630000000 | 1 | / | |\n * | 1630000000 | 2 | /boot/efi | |\n * | 1630000000 | 2 | | / |\n * | 1630000000 | 3 | | /boot/efi |\n * +------------+--------+-----------+-----------+\n */\nexport function applyMergeColumnsTransform(\n data: Array<Record<string, unknown>>,\n selectedColumns: string[],\n outputName: string,\n): Array<Record<string, unknown>> {\n const result: Array<Record<string, unknown>> = [];\n\n for (const row of data) {\n const columns = Object.keys(row).filter((k) => selectedColumns.includes(k));\n\n const selectedColumnValues: Record<string, unknown> = {};\n\n for (const column of columns) {\n selectedColumnValues[column] = row[column];\n delete row[column];\n }\n\n for (const column of columns) {\n result.push({ ...row, [outputName]: selectedColumnValues[column] });\n }\n\n if (columns.length === 0) {\n result.push(row);\n }\n }\n\n return result;\n}\n\n/*\n * Merge Indexed Columns: All indexed columns are merged to one column\n *\n * Example: Join on 'value' column\n * INPUT:\n * | timestamp #1 | timestamp #2 | value #1 | value #2 | instance #1 | instance #2 |\n * |--------------|--------------|----------|----------|-------------|-------------|\n * | 1630000000 | | 55 | | toto | |\n * | 1630000000 | | 33 | | toto | |\n * | 1630000000 | | 45 | | toto | |\n * | | 1630000000 | | 112 | | titi |\n * | | 1630000000 | | 20 | | titi |\n * | | 1630000000 | | 10 | | titi |\n *\n * OUTPUT:\n * | timestamp #1 | timestamp #2 | value | instance #1 | instance #2 |\n * |--------------|--------------|-------|-------------|-------------|\n * | 1630000000 | | 55 | toto | |\n * | 1630000000 | | 33 | toto | |\n * | 1630000000 | | 45 | toto | |\n * | | 1630000000 | 112 | | titi |\n * | | 1630000000 | 20 | | titi |\n * | | 1630000000 | 10 | | titi |\n */\nexport function applyMergeIndexedColumnsTransform(\n data: Array<Record<string, unknown>>,\n column: string,\n): Array<Record<string, unknown>> {\n const result: Array<Record<string, unknown>> = [];\n\n for (const entry of data) {\n const indexedColumns = Object.keys(entry).filter((k) =>\n new RegExp('^((' + column + ' #\\\\d+)|(' + column + '))$').test(k),\n );\n const indexedColumnValues: Record<string, unknown> = {};\n\n for (const indexedColumn of indexedColumns) {\n indexedColumnValues[indexedColumn] = entry[indexedColumn];\n delete entry[indexedColumn];\n }\n\n for (const indexedColumn of indexedColumns) {\n result.push({ ...entry, [column]: indexedColumnValues[indexedColumn] });\n }\n\n if (indexedColumns.length === 0) {\n result.push(entry);\n }\n }\n\n return result;\n}\n\n/*\n * Merge Indexed Columns: All indexed columns are merged to one column\n *\n * INPUT:\n * | timestamp | value #1 | value #2 | mount #1 | mount #2 | instance #1 | instance #2 | env #1 | env #2 |\n * |------------|----------|----------|-----------|-----------|-------------|-------------|--------|--------|\n * | 1630000000 | 1 | | / | | test:44 | | prd | |\n * | 1630000000 | 2 | | /boot/efi | | test:44 | | prd | |\n * | 1630000000 | | 5 | | / | | test:44 | | prd |\n * | 1630000000 | | 6 | | /boot/efi | | test:44 | | prd |\n *\n * OUTPUT:\n * | timestamp | value #1 | value #2 | mount | instance | env |\n * |------------|----------|----------|-----------|----------|-----|\n * | 1630000000 | 1 | 5 | / | test:44 | prd |\n * | 1630000000 | 2 | 6 | /boot/efi | test:44 | prd |\n */\nexport function applyMergeSeriesTransform(data: Array<Record<string, unknown>>): Array<Record<string, unknown>> {\n let result: Array<Record<string, unknown>> = [...data];\n\n const labelColumns = Array.from(\n new Set(\n data\n .flatMap(Object.keys)\n .map((label) => label.replace(/ #\\d+/, ''))\n .filter((label) => label !== 'value'),\n ),\n );\n\n for (const label of labelColumns) {\n result = applyMergeIndexedColumnsTransform(result, label);\n }\n\n result = applyJoinTransform(result, labelColumns);\n\n return result;\n}\n\n/*\n * Transforms query data with the given transforms\n */\nexport function transformData(\n data: Array<Record<string, unknown>>,\n transforms: Transform[],\n): Array<Record<string, unknown>> {\n let result: Array<Record<string, unknown>> = data;\n\n // Apply transforms by their orders\n for (const transform of transforms ?? []) {\n if (transform.spec.disabled) continue;\n\n switch (transform.kind) {\n case 'JoinByColumnValue': {\n if (transform.spec.columns && transform.spec.columns.length > 0) {\n result = applyJoinTransform(result, transform.spec.columns);\n }\n break;\n }\n case 'MergeIndexedColumns': {\n if (transform.spec.column) {\n result = applyMergeIndexedColumnsTransform(result, transform.spec.column);\n }\n break;\n }\n case 'MergeColumns': {\n if (transform.spec.columns && transform.spec.columns.length > 0 && transform.spec.name) {\n result = applyMergeColumnsTransform(result, transform.spec.columns, transform.spec.name);\n }\n break;\n }\n case 'MergeSeries': {\n result = applyMergeSeriesTransform(result);\n break;\n }\n }\n }\n\n // Ordering data column alphabetically\n result = result.map((row) => {\n return Object.keys(row)\n .toSorted()\n .reduce((obj: Record<string, unknown>, key: string) => {\n obj[key] = row[key];\n return obj;\n }, {});\n });\n return result;\n}\n"],"names":["applyJoinTransform","data","columns","length","rowHashed","row","rowHash","Object","keys","filter","k","includes","map","join","rowHashedValue","values","applyMergeColumnsTransform","selectedColumns","outputName","result","selectedColumnValues","column","push","applyMergeIndexedColumnsTransform","entry","indexedColumns","RegExp","test","indexedColumnValues","indexedColumn","applyMergeSeriesTransform","labelColumns","Array","from","Set","flatMap","label","replace","transformData","transforms","transform","spec","disabled","kind","name","toSorted","reduce","obj","key"],"mappings":"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"}
@@ -170,7 +170,7 @@ const VARIABLE_REGEX = /\$(\w+)|\${(\w+)(?:\.([^:^}]+))?(?::([^}]+))?}/gm;
170
170
  variables// Sorting variables by their length.
171
171
  // In order to not have a variable name have contained in another variable name.
172
172
  // i.e.: $__range replacing $__range_ms => '3600_ms' instead of '3600000'
173
- .sort((a, b)=>b.length - a.length).forEach((v)=>{
173
+ .toSorted((a, b)=>b.length - a.length).forEach((v)=>{
174
174
  const variable = variableState[v];
175
175
  if (variable && variable.value !== undefined) {
176
176
  finalText = replaceVariable(finalText, v, variable?.value, variablesMap.get(v));
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/variable-interpolation.ts"],"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 type { VariableValue } from '@perses-dev/spec';\n\n/**\n * Option for a variable with label and value\n */\nexport type VariableOption = { label: string; value: string };\n\n/**\n * State of a variable including its current value, options, and loading state\n */\nexport type VariableState = {\n value: VariableValue;\n /**\n * Optional compact value for human-readable text. Query interpolation continues to use `value`.\n */\n displayValue?: VariableValue;\n options?: VariableOption[];\n loading: boolean;\n error?: Error;\n /**\n * If a local variable is overriding an external variable, local var will have the flag ``overriding=true``.\n */\n overriding?: boolean;\n /**\n * If a local variable is overriding an external variable, external var will have the flag ``overridden=true``.\n */\n overridden?: boolean;\n defaultValue?: VariableValue;\n customAllValue?: string;\n};\n\n/**\n * Map of variable names to their states\n */\nexport type VariableStateMap = Record<string, VariableState>;\n\n/**\n * Supported interpolation formats for variable values\n */\nexport enum InterpolationFormat {\n CSV = 'csv',\n DISTRIBUTED = 'distributed',\n DOUBLEQUOTE = 'doublequote',\n GLOB = 'glob',\n JSON = 'json',\n LUCENE = 'lucene',\n PERCENTENCODE = 'percentencode',\n PIPE = 'pipe',\n PROMETHEUS = 'prometheus',\n RAW = 'raw',\n REGEX = 'regex',\n SINGLEQUOTE = 'singlequote',\n SQLSTRING = 'sqlstring',\n TEXT = 'text',\n QUERYPARAM = 'queryparam',\n REGEX_LITERAL = 'regexliteral',\n}\n\nfunction stringToFormat(val: string | undefined): InterpolationFormat | undefined {\n if (!val) return undefined;\n\n const lowerVal = val.toLowerCase();\n return Object.values(InterpolationFormat).find((format) => format === lowerVal) || undefined;\n}\n\n/**\n * Interpolate an array of values with a specific format\n */\nexport function interpolate(values: string[], name: string, format: InterpolationFormat): string {\n switch (format) {\n case InterpolationFormat.CSV:\n case InterpolationFormat.RAW:\n return values.join(',');\n case InterpolationFormat.DISTRIBUTED: {\n const [first, ...rest] = values;\n return `${[first, ...rest.map((v) => `${name}=${v}`)].join(',')}`;\n }\n case InterpolationFormat.DOUBLEQUOTE:\n return values.map((v) => `\"${v}\"`).join(',');\n case InterpolationFormat.GLOB:\n return `{${values.join(',')}}`;\n case InterpolationFormat.JSON: {\n // values might contain stringified JSON objects so we need to parse them first\n // and then return a JSON stringified array to return valid JSON\n const parsedValues = values.map((v) => {\n try {\n return JSON.parse(v);\n } catch {\n return v;\n }\n });\n\n return JSON.stringify(parsedValues);\n }\n case InterpolationFormat.LUCENE:\n return `(${values.map((v) => `\"${v}\"`).join(' OR ')})`;\n case InterpolationFormat.PERCENTENCODE:\n return encodeURIComponent(values.join(','));\n case InterpolationFormat.PIPE:\n return values.join('|');\n case InterpolationFormat.REGEX: {\n const escapedRegex = values.map((v) => v.replace(/[-/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&'));\n return `(${escapedRegex.join('|')})`;\n }\n case InterpolationFormat.REGEX_LITERAL: {\n const escapedRegex = values.map((v) => v.replace(/[-/\\\\^$*+?.()|[\\]{}]/g, '\\\\\\\\$&'));\n return `(${escapedRegex.join('|')})`;\n }\n case InterpolationFormat.SINGLEQUOTE:\n return values.map((v) => `'${v}'`).join(',');\n case InterpolationFormat.SQLSTRING:\n return values.map((v) => `'${v.replace(/'/g, \"''\")}'`).join(',');\n case InterpolationFormat.TEXT:\n return values.join(' + ');\n case InterpolationFormat.QUERYPARAM:\n return values.map((v) => `${name}=${encodeURIComponent(v)}`).join('&');\n case InterpolationFormat.PROMETHEUS:\n default:\n return `(${values.join('|')})`;\n }\n}\n\n/**\n * Replace a single variable in text with its value\n */\nexport function replaceVariable(\n text: string,\n varName: string,\n variableValue: VariableValue,\n varFormat?: InterpolationFormat,\n): string {\n const variableSyntax = '$' + varName;\n const alternativeVariableSyntax = '${' + varName + (varFormat ? ':' + varFormat : '') + '}';\n\n let replaceString = '';\n if (Array.isArray(variableValue)) {\n replaceString = interpolate(variableValue, varName, varFormat || InterpolationFormat.PROMETHEUS);\n }\n if (typeof variableValue === 'string') {\n replaceString = interpolate([variableValue], varName, varFormat || InterpolationFormat.RAW);\n }\n text = text.replaceAll(variableSyntax, replaceString);\n return text.replaceAll(alternativeVariableSyntax, replaceString);\n}\n\n// This regular expression is designed to identify variable references in a string.\n// It supports two formats for referencing variables:\n// 1. $variableName - This is a simpler format, and the regular expression captures the variable name (\\w+ matches one or more word characters).\n// 2. ${variableName} - This is a more complex format and the regular expression captures the variable name (\\w+ matches one or more word characters) in the curly braces.\n// 3. ${variableName:format} - This is a more complex format that allows specifying a format interpolation.\n\nconst VARIABLE_REGEX = /\\$(\\w+)|\\${(\\w+)(?:\\.([^:^}]+))?(?::([^}]+))?}/gm;\n\n/**\n * Returns a list of variables\n */\nexport function parseVariables(text: string): string[] {\n const matches = new Set<string>();\n let match;\n\n while ((match = VARIABLE_REGEX.exec(text)) !== null) {\n if (match) {\n if (match[1]) {\n // \\$(\\w+)\\\n matches.add(match[1]);\n } else if (match[2]) {\n // \\${(\\w+)}\\\n matches.add(match[2]);\n }\n }\n }\n // return unique matches\n return Array.from(matches.values());\n}\n\n/**\n * Returns a map of variable names and its format. If no format is specified, it will be undefined.\n */\nexport function parseVariablesAndFormat(text: string): Map<string, InterpolationFormat | undefined> {\n const matches = new Map<string, InterpolationFormat | undefined>();\n let match;\n\n while ((match = VARIABLE_REGEX.exec(text)) !== null) {\n if (match) {\n let format = undefined;\n if (match[4]) {\n format = match[4];\n }\n if (match[1]) {\n // \\$(\\w+)\\\n matches.set(match[1], stringToFormat(format));\n } else if (match[2]) {\n // \\${(\\w+)}\\\n matches.set(match[2], stringToFormat(format));\n }\n }\n }\n return matches;\n}\n\n/**\n * Replace all variables in text with their values from the variable state map\n */\nexport function replaceVariables(text: string, variableState: VariableStateMap): string {\n const variablesMap = parseVariablesAndFormat(text);\n const variables = Array.from(variablesMap.keys());\n let finalText = text;\n variables\n // Sorting variables by their length.\n // In order to not have a variable name have contained in another variable name.\n // i.e.: $__range replacing $__range_ms => '3600_ms' instead of '3600000'\n .sort((a, b) => b.length - a.length)\n .forEach((v) => {\n const variable = variableState[v];\n if (variable && variable.value !== undefined) {\n finalText = replaceVariable(finalText, v, variable?.value, variablesMap.get(v));\n }\n });\n\n return finalText;\n}\n\n/**\n * Replace variables using their compact display values when available.\n */\nexport function replaceVariablesForDisplay(text: string, variableState: VariableStateMap): string {\n const displayState: VariableStateMap = {};\n for (const [name, state] of Object.entries(variableState)) {\n displayState[name] = state.displayValue === undefined ? state : { ...state, value: state.displayValue };\n }\n return replaceVariables(text, displayState);\n}\n"],"names":["InterpolationFormat","stringToFormat","val","undefined","lowerVal","toLowerCase","Object","values","find","format","interpolate","name","join","first","rest","map","v","parsedValues","JSON","parse","stringify","encodeURIComponent","escapedRegex","replace","replaceVariable","text","varName","variableValue","varFormat","variableSyntax","alternativeVariableSyntax","replaceString","Array","isArray","replaceAll","VARIABLE_REGEX","parseVariables","matches","Set","match","exec","add","from","parseVariablesAndFormat","Map","set","replaceVariables","variableState","variablesMap","variables","keys","finalText","sort","a","b","length","forEach","variable","value","get","replaceVariablesForDisplay","displayState","state","entries","displayValue"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/utils/variable-interpolation.ts"],"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 type { VariableValue } from '@perses-dev/spec';\n\n/**\n * Option for a variable with label and value\n */\nexport type VariableOption = { label: string; value: string };\n\n/**\n * State of a variable including its current value, options, and loading state\n */\nexport type VariableState = {\n value: VariableValue;\n /**\n * Optional compact value for human-readable text. Query interpolation continues to use `value`.\n */\n displayValue?: VariableValue;\n options?: VariableOption[];\n loading: boolean;\n error?: Error;\n /**\n * If a local variable is overriding an external variable, local var will have the flag ``overriding=true``.\n */\n overriding?: boolean;\n /**\n * If a local variable is overriding an external variable, external var will have the flag ``overridden=true``.\n */\n overridden?: boolean;\n defaultValue?: VariableValue;\n customAllValue?: string;\n};\n\n/**\n * Map of variable names to their states\n */\nexport type VariableStateMap = Record<string, VariableState>;\n\n/**\n * Supported interpolation formats for variable values\n */\nexport enum InterpolationFormat {\n CSV = 'csv',\n DISTRIBUTED = 'distributed',\n DOUBLEQUOTE = 'doublequote',\n GLOB = 'glob',\n JSON = 'json',\n LUCENE = 'lucene',\n PERCENTENCODE = 'percentencode',\n PIPE = 'pipe',\n PROMETHEUS = 'prometheus',\n RAW = 'raw',\n REGEX = 'regex',\n SINGLEQUOTE = 'singlequote',\n SQLSTRING = 'sqlstring',\n TEXT = 'text',\n QUERYPARAM = 'queryparam',\n REGEX_LITERAL = 'regexliteral',\n}\n\nfunction stringToFormat(val: string | undefined): InterpolationFormat | undefined {\n if (!val) return undefined;\n\n const lowerVal = val.toLowerCase();\n return Object.values(InterpolationFormat).find((format) => format === lowerVal) || undefined;\n}\n\n/**\n * Interpolate an array of values with a specific format\n */\nexport function interpolate(values: string[], name: string, format: InterpolationFormat): string {\n switch (format) {\n case InterpolationFormat.CSV:\n case InterpolationFormat.RAW:\n return values.join(',');\n case InterpolationFormat.DISTRIBUTED: {\n const [first, ...rest] = values;\n return `${[first, ...rest.map((v) => `${name}=${v}`)].join(',')}`;\n }\n case InterpolationFormat.DOUBLEQUOTE:\n return values.map((v) => `\"${v}\"`).join(',');\n case InterpolationFormat.GLOB:\n return `{${values.join(',')}}`;\n case InterpolationFormat.JSON: {\n // values might contain stringified JSON objects so we need to parse them first\n // and then return a JSON stringified array to return valid JSON\n const parsedValues = values.map((v) => {\n try {\n return JSON.parse(v);\n } catch {\n return v;\n }\n });\n\n return JSON.stringify(parsedValues);\n }\n case InterpolationFormat.LUCENE:\n return `(${values.map((v) => `\"${v}\"`).join(' OR ')})`;\n case InterpolationFormat.PERCENTENCODE:\n return encodeURIComponent(values.join(','));\n case InterpolationFormat.PIPE:\n return values.join('|');\n case InterpolationFormat.REGEX: {\n const escapedRegex = values.map((v) => v.replace(/[-/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&'));\n return `(${escapedRegex.join('|')})`;\n }\n case InterpolationFormat.REGEX_LITERAL: {\n const escapedRegex = values.map((v) => v.replace(/[-/\\\\^$*+?.()|[\\]{}]/g, '\\\\\\\\$&'));\n return `(${escapedRegex.join('|')})`;\n }\n case InterpolationFormat.SINGLEQUOTE:\n return values.map((v) => `'${v}'`).join(',');\n case InterpolationFormat.SQLSTRING:\n return values.map((v) => `'${v.replace(/'/g, \"''\")}'`).join(',');\n case InterpolationFormat.TEXT:\n return values.join(' + ');\n case InterpolationFormat.QUERYPARAM:\n return values.map((v) => `${name}=${encodeURIComponent(v)}`).join('&');\n case InterpolationFormat.PROMETHEUS:\n default:\n return `(${values.join('|')})`;\n }\n}\n\n/**\n * Replace a single variable in text with its value\n */\nexport function replaceVariable(\n text: string,\n varName: string,\n variableValue: VariableValue,\n varFormat?: InterpolationFormat,\n): string {\n const variableSyntax = '$' + varName;\n const alternativeVariableSyntax = '${' + varName + (varFormat ? ':' + varFormat : '') + '}';\n\n let replaceString = '';\n if (Array.isArray(variableValue)) {\n replaceString = interpolate(variableValue, varName, varFormat || InterpolationFormat.PROMETHEUS);\n }\n if (typeof variableValue === 'string') {\n replaceString = interpolate([variableValue], varName, varFormat || InterpolationFormat.RAW);\n }\n text = text.replaceAll(variableSyntax, replaceString);\n return text.replaceAll(alternativeVariableSyntax, replaceString);\n}\n\n// This regular expression is designed to identify variable references in a string.\n// It supports two formats for referencing variables:\n// 1. $variableName - This is a simpler format, and the regular expression captures the variable name (\\w+ matches one or more word characters).\n// 2. ${variableName} - This is a more complex format and the regular expression captures the variable name (\\w+ matches one or more word characters) in the curly braces.\n// 3. ${variableName:format} - This is a more complex format that allows specifying a format interpolation.\n\nconst VARIABLE_REGEX = /\\$(\\w+)|\\${(\\w+)(?:\\.([^:^}]+))?(?::([^}]+))?}/gm;\n\n/**\n * Returns a list of variables\n */\nexport function parseVariables(text: string): string[] {\n const matches = new Set<string>();\n let match;\n\n while ((match = VARIABLE_REGEX.exec(text)) !== null) {\n if (match) {\n if (match[1]) {\n // \\$(\\w+)\\\n matches.add(match[1]);\n } else if (match[2]) {\n // \\${(\\w+)}\\\n matches.add(match[2]);\n }\n }\n }\n // return unique matches\n return Array.from(matches.values());\n}\n\n/**\n * Returns a map of variable names and its format. If no format is specified, it will be undefined.\n */\nexport function parseVariablesAndFormat(text: string): Map<string, InterpolationFormat | undefined> {\n const matches = new Map<string, InterpolationFormat | undefined>();\n let match;\n\n while ((match = VARIABLE_REGEX.exec(text)) !== null) {\n if (match) {\n let format = undefined;\n if (match[4]) {\n format = match[4];\n }\n if (match[1]) {\n // \\$(\\w+)\\\n matches.set(match[1], stringToFormat(format));\n } else if (match[2]) {\n // \\${(\\w+)}\\\n matches.set(match[2], stringToFormat(format));\n }\n }\n }\n return matches;\n}\n\n/**\n * Replace all variables in text with their values from the variable state map\n */\nexport function replaceVariables(text: string, variableState: VariableStateMap): string {\n const variablesMap = parseVariablesAndFormat(text);\n const variables = Array.from(variablesMap.keys());\n let finalText = text;\n variables\n // Sorting variables by their length.\n // In order to not have a variable name have contained in another variable name.\n // i.e.: $__range replacing $__range_ms => '3600_ms' instead of '3600000'\n .toSorted((a, b) => b.length - a.length)\n .forEach((v) => {\n const variable = variableState[v];\n if (variable && variable.value !== undefined) {\n finalText = replaceVariable(finalText, v, variable?.value, variablesMap.get(v));\n }\n });\n\n return finalText;\n}\n\n/**\n * Replace variables using their compact display values when available.\n */\nexport function replaceVariablesForDisplay(text: string, variableState: VariableStateMap): string {\n const displayState: VariableStateMap = {};\n for (const [name, state] of Object.entries(variableState)) {\n displayState[name] = state.displayValue === undefined ? state : { ...state, value: state.displayValue };\n }\n return replaceVariables(text, displayState);\n}\n"],"names":["InterpolationFormat","stringToFormat","val","undefined","lowerVal","toLowerCase","Object","values","find","format","interpolate","name","join","first","rest","map","v","parsedValues","JSON","parse","stringify","encodeURIComponent","escapedRegex","replace","replaceVariable","text","varName","variableValue","varFormat","variableSyntax","alternativeVariableSyntax","replaceString","Array","isArray","replaceAll","VARIABLE_REGEX","parseVariables","matches","Set","match","exec","add","from","parseVariablesAndFormat","Map","set","replaceVariables","variableState","variablesMap","variables","keys","finalText","toSorted","a","b","length","forEach","variable","value","get","replaceVariablesForDisplay","displayState","state","entries","displayValue"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@perses-dev/components",
3
- "version": "0.55.0-beta.6",
3
+ "version": "0.55.0-beta.7",
4
4
  "description": "Common UI components used across Perses features",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/perses/perses/blob/main/README.md",
@@ -35,7 +35,7 @@
35
35
  "@fontsource/inter": "^5.0.0",
36
36
  "@mui/x-date-pickers": "^7.23.1",
37
37
  "@perses-dev/spec": "0.3.0-beta.5",
38
- "@perses-dev/client": "0.55.0-beta.6",
38
+ "@perses-dev/client": "0.55.0-beta.7",
39
39
  "numbro": "^2.3.6",
40
40
  "@tanstack/match-sorter-utils": "^8.19.4",
41
41
  "@tanstack/react-table": "^8.20.5",
@@ -59,8 +59,8 @@
59
59
  "@emotion/styled": "^11.14.1",
60
60
  "@mui/material": "^6.1.10",
61
61
  "lodash": "^4.17.21",
62
- "react": "^17.0.2 || ^18.0.0",
63
- "react-dom": "^17.0.2 || ^18.0.0"
62
+ "react": "^18.3.0",
63
+ "react-dom": "^18.3.0"
64
64
  },
65
65
  "files": [
66
66
  "dist"