@perses-dev/components 0.55.0-beta.8 → 0.55.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/DragAndDrop/DragAndDropList.d.ts +10 -2
  2. package/dist/DragAndDrop/DragAndDropList.d.ts.map +1 -1
  3. package/dist/DragAndDrop/DragAndDropList.js +6 -4
  4. package/dist/DragAndDrop/DragAndDropList.js.map +1 -1
  5. package/dist/EChart/EChart.d.ts +1 -1
  6. package/dist/EChart/EChart.d.ts.map +1 -1
  7. package/dist/EChart/EChart.js +12 -25
  8. package/dist/EChart/EChart.js.map +1 -1
  9. package/dist/ExemplarMetadata/ExemplarMetadataTooltip.d.ts +27 -0
  10. package/dist/ExemplarMetadata/ExemplarMetadataTooltip.d.ts.map +1 -0
  11. package/dist/ExemplarMetadata/ExemplarMetadataTooltip.js +239 -0
  12. package/dist/ExemplarMetadata/ExemplarMetadataTooltip.js.map +1 -0
  13. package/dist/ExemplarMetadata/index.d.ts +2 -0
  14. package/dist/ExemplarMetadata/index.d.ts.map +1 -0
  15. package/dist/{utils/component-ids.js → ExemplarMetadata/index.js} +2 -15
  16. package/dist/ExemplarMetadata/index.js.map +1 -0
  17. package/dist/FormatControls/FormatControls.d.ts.map +1 -1
  18. package/dist/FormatControls/FormatControls.js +42 -4
  19. package/dist/FormatControls/FormatControls.js.map +1 -1
  20. package/dist/FormatControls/UnitSelector.js +4 -4
  21. package/dist/FormatControls/UnitSelector.js.map +1 -1
  22. package/dist/Legend/TableLegend.d.ts.map +1 -1
  23. package/dist/Legend/TableLegend.js +2 -1
  24. package/dist/Legend/TableLegend.js.map +1 -1
  25. package/dist/LinksEditor/LinkEditorForm.d.ts +1 -0
  26. package/dist/LinksEditor/LinkEditorForm.d.ts.map +1 -1
  27. package/dist/LinksEditor/LinkEditorForm.js +1 -0
  28. package/dist/LinksEditor/LinkEditorForm.js.map +1 -1
  29. package/dist/OptionsEditorLayout/OptionsEditorControl.d.ts.map +1 -1
  30. package/dist/OptionsEditorLayout/OptionsEditorControl.js +2 -3
  31. package/dist/OptionsEditorLayout/OptionsEditorControl.js.map +1 -1
  32. package/dist/SettingsAutocomplete/SettingsAutocomplete.d.ts.map +1 -1
  33. package/dist/SettingsAutocomplete/SettingsAutocomplete.js +6 -3
  34. package/dist/SettingsAutocomplete/SettingsAutocomplete.js.map +1 -1
  35. package/dist/Table/Table.d.ts.map +1 -1
  36. package/dist/Table/Table.js +3 -0
  37. package/dist/Table/Table.js.map +1 -1
  38. package/dist/Table/TableToolbar.d.ts.map +1 -1
  39. package/dist/Table/TableToolbar.js +1 -0
  40. package/dist/Table/TableToolbar.js.map +1 -1
  41. package/dist/Table/VirtualizedTable.d.ts +1 -1
  42. package/dist/Table/VirtualizedTable.d.ts.map +1 -1
  43. package/dist/Table/VirtualizedTable.js +10 -19
  44. package/dist/Table/VirtualizedTable.js.map +1 -1
  45. package/dist/Table/model/table-model.d.ts +6 -2
  46. package/dist/Table/model/table-model.d.ts.map +1 -1
  47. package/dist/Table/model/table-model.js.map +1 -1
  48. package/dist/ThresholdsEditor/ThresholdsEditor.js +1 -3
  49. package/dist/ThresholdsEditor/ThresholdsEditor.js.map +1 -1
  50. package/dist/TimeRangeSelector/DateTimeRangePicker.js +1 -1
  51. package/dist/TimeRangeSelector/DateTimeRangePicker.js.map +1 -1
  52. package/dist/TimeRangeSelector/TimeRangeSelector.js +4 -4
  53. package/dist/TimeRangeSelector/TimeRangeSelector.js.map +1 -1
  54. package/dist/TimeSeriesTooltip/TimeChartTooltip.d.ts.map +1 -1
  55. package/dist/TimeSeriesTooltip/TimeChartTooltip.js +27 -16
  56. package/dist/TimeSeriesTooltip/TimeChartTooltip.js.map +1 -1
  57. package/dist/TimeSeriesTooltip/utils.d.ts.map +1 -1
  58. package/dist/TimeSeriesTooltip/utils.js +6 -2
  59. package/dist/TimeSeriesTooltip/utils.js.map +1 -1
  60. package/dist/TransformsEditor/TransformEditor.d.ts.map +1 -1
  61. package/dist/TransformsEditor/TransformEditor.js +89 -0
  62. package/dist/TransformsEditor/TransformEditor.js.map +1 -1
  63. package/dist/controls/TextField.d.ts.map +1 -1
  64. package/dist/controls/TextField.js +15 -10
  65. package/dist/controls/TextField.js.map +1 -1
  66. package/dist/index.d.ts +1 -0
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js +1 -0
  69. package/dist/index.js.map +1 -1
  70. package/dist/model/custom.d.ts +22 -0
  71. package/dist/model/custom.d.ts.map +1 -0
  72. package/dist/model/custom.js +243 -0
  73. package/dist/model/custom.js.map +1 -0
  74. package/dist/model/index.d.ts +1 -0
  75. package/dist/model/index.d.ts.map +1 -1
  76. package/dist/model/index.js +1 -0
  77. package/dist/model/index.js.map +1 -1
  78. package/dist/model/transforms.d.ts +22 -1
  79. package/dist/model/transforms.d.ts.map +1 -1
  80. package/dist/model/transforms.js +2 -1
  81. package/dist/model/transforms.js.map +1 -1
  82. package/dist/model/units.d.ts +12 -10
  83. package/dist/model/units.d.ts.map +1 -1
  84. package/dist/model/units.js +33 -28
  85. package/dist/model/units.js.map +1 -1
  86. package/dist/utils/index.d.ts +0 -2
  87. package/dist/utils/index.d.ts.map +1 -1
  88. package/dist/utils/index.js +0 -2
  89. package/dist/utils/index.js.map +1 -1
  90. package/dist/utils/text.d.ts.map +1 -1
  91. package/dist/utils/text.js +14 -18
  92. package/dist/utils/text.js.map +1 -1
  93. package/dist/utils/transform-data.d.ts +5 -0
  94. package/dist/utils/transform-data.d.ts.map +1 -1
  95. package/dist/utils/transform-data.js +96 -0
  96. package/dist/utils/transform-data.js.map +1 -1
  97. package/dist/utils/variable-interpolation.d.ts +11 -0
  98. package/dist/utils/variable-interpolation.d.ts.map +1 -1
  99. package/dist/utils/variable-interpolation.js +64 -0
  100. package/dist/utils/variable-interpolation.js.map +1 -1
  101. package/package.json +3 -3
  102. package/dist/utils/component-ids.d.ts +0 -8
  103. package/dist/utils/component-ids.d.ts.map +0 -1
  104. package/dist/utils/component-ids.js.map +0 -1
  105. package/dist/utils/memo.d.ts +0 -13
  106. package/dist/utils/memo.d.ts.map +0 -1
  107. package/dist/utils/memo.js +0 -50
  108. package/dist/utils/memo.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/model/units.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 { BitsFormatOptions } from './bits';\nimport { formatBits, BITS_GROUP_CONFIG, BITS_UNIT_CONFIG } from './bits';\nimport type { BytesFormatOptions } from './bytes';\nimport { formatBytes, BYTES_GROUP_CONFIG, BYTES_UNIT_CONFIG } from './bytes';\nimport type { CurrencyFormatOptions } from './currency';\nimport { formatCurrency, CURRENCY_GROUP_CONFIG, CURRENCY_UNIT_CONFIG } from './currency';\nimport type { DateFormatOptions } from './date';\nimport { formatDate, DATE_GROUP_CONFIG, DATE_UNIT_CONFIG } from './date';\nimport type { DecimalFormatOptions } from './decimal';\nimport { formatDecimal, DECIMAL_GROUP_CONFIG, DECIMAL_UNIT_CONFIG } from './decimal';\nimport type { PercentFormatOptions } from './percent';\nimport { formatPercent, PERCENT_GROUP_CONFIG, PERCENT_UNIT_CONFIG } from './percent';\nimport type { TemperatureFormatOptions } from './temperature';\nimport { TEMPERATURE_GROUP_CONFIG, formatTemperature, TEMPERATURE_UNIT_CONFIG } from './temperature';\nimport type { ThroughputFormatOptions } from './throughput';\nimport { formatThroughput, THROUGHPUT_GROUP_CONFIG, THROUGHPUT_UNIT_CONFIG } from './throughput';\nimport type { TimeFormatOptions } from './time';\nimport { formatTime, TIME_GROUP_CONFIG, TIME_UNIT_CONFIG } from './time';\nimport type { UnitGroup, UnitGroupConfig, UnitConfig } from './types';\n\n/**\n * Most of the number formatting is based on Intl.NumberFormat, which is built into JavaScript.\n * Prefer Intl.NumbeFormat because it covers most use cases and will continue to be supported with time.\n *\n * To format bytes, we also make use of the `numbro` package,\n * because it can handle adding units like KB, MB, GB, etc. correctly.\n */\n\nexport const UNIT_GROUP_CONFIG: Readonly<Record<UnitGroup, UnitGroupConfig>> = {\n Time: TIME_GROUP_CONFIG,\n Percent: PERCENT_GROUP_CONFIG,\n Decimal: DECIMAL_GROUP_CONFIG,\n Bytes: BYTES_GROUP_CONFIG,\n Bits: BITS_GROUP_CONFIG,\n Throughput: THROUGHPUT_GROUP_CONFIG,\n Currency: CURRENCY_GROUP_CONFIG,\n Temperature: TEMPERATURE_GROUP_CONFIG,\n Date: DATE_GROUP_CONFIG,\n};\nexport const UNIT_CONFIG = {\n ...TIME_UNIT_CONFIG,\n ...PERCENT_UNIT_CONFIG,\n ...DECIMAL_UNIT_CONFIG,\n ...BYTES_UNIT_CONFIG,\n ...BITS_UNIT_CONFIG,\n ...THROUGHPUT_UNIT_CONFIG,\n ...CURRENCY_UNIT_CONFIG,\n ...TEMPERATURE_UNIT_CONFIG,\n ...DATE_UNIT_CONFIG,\n} as const;\n\nexport type FormatOptions =\n | TimeFormatOptions\n | PercentFormatOptions\n | DecimalFormatOptions\n | BytesFormatOptions\n | BitsFormatOptions\n | ThroughputFormatOptions\n | CurrencyFormatOptions\n | TemperatureFormatOptions\n | DateFormatOptions;\n\ntype HasDecimalPlaces<UnitOpt> = UnitOpt extends { decimalPlaces?: number } ? UnitOpt : never;\ntype HasShortValues<UnitOpt> = UnitOpt extends { shortValues?: boolean } ? UnitOpt : never;\n\nexport function formatValue(value: number, formatOptions?: FormatOptions): string {\n if (!formatOptions) {\n return value.toString();\n }\n\n if (isBytesUnit(formatOptions)) {\n return formatBytes(value, formatOptions);\n }\n\n if (isBitsUnit(formatOptions)) {\n return formatBits(value, formatOptions);\n }\n\n if (isDecimalUnit(formatOptions)) {\n return formatDecimal(value, formatOptions);\n }\n\n if (isPercentUnit(formatOptions)) {\n return formatPercent(value, formatOptions);\n }\n\n if (isTimeUnit(formatOptions)) {\n return formatTime(value, formatOptions);\n }\n\n if (isThroughputUnit(formatOptions)) {\n return formatThroughput(value, formatOptions);\n }\n\n if (isCurrencyUnit(formatOptions)) {\n return formatCurrency(value, formatOptions);\n }\n\n if (isDateUnit(formatOptions)) {\n return formatDate(value, formatOptions);\n }\n\n if (isTemperatureUnit(formatOptions)) {\n return formatTemperature(value, formatOptions);\n }\n\n const exhaustive: never = formatOptions;\n throw new Error(`Unknown unit options ${exhaustive}`);\n}\n\nexport function getUnitConfig(formatOptions: FormatOptions): UnitConfig {\n const unit = formatOptions.unit ?? 'decimal';\n return UNIT_CONFIG[unit];\n}\n\nexport function getUnitGroup(formatOptions: FormatOptions): UnitGroup {\n return getUnitConfig(formatOptions).group ?? 'Decimal';\n}\n\nexport function getUnitGroupConfig(formatOptions: FormatOptions): UnitGroupConfig {\n const unitConfig = getUnitConfig(formatOptions);\n return UNIT_GROUP_CONFIG[unitConfig.group ?? 'Decimal'];\n}\n\n// Type guards\nexport function isTimeUnit(formatOptions: FormatOptions): formatOptions is TimeFormatOptions {\n return getUnitGroup(formatOptions) === 'Time';\n}\n\nexport function isPercentUnit(formatOptions: FormatOptions): formatOptions is PercentFormatOptions {\n return getUnitGroup(formatOptions) === 'Percent';\n}\n\nexport function isDecimalUnit(formatOptions: FormatOptions): formatOptions is DecimalFormatOptions {\n return getUnitGroup(formatOptions) === 'Decimal';\n}\n\nexport function isBytesUnit(formatOptions: FormatOptions): formatOptions is BytesFormatOptions {\n return getUnitGroup(formatOptions) === 'Bytes';\n}\n\nexport function isBitsUnit(formatOptions: FormatOptions): formatOptions is BitsFormatOptions {\n return getUnitGroup(formatOptions) === 'Bits';\n}\n\nexport function isUnitWithDecimalPlaces(\n formatOptions: FormatOptions,\n): formatOptions is HasDecimalPlaces<FormatOptions> {\n const groupConfig = getUnitGroupConfig(formatOptions);\n\n return !!groupConfig.decimalPlaces;\n}\n\nexport function isUnitWithShortValues(formatOptions: FormatOptions): formatOptions is HasShortValues<FormatOptions> {\n const groupConfig = getUnitGroupConfig(formatOptions);\n\n return !!groupConfig.shortValues;\n}\n\nexport function isThroughputUnit(formatOptions: FormatOptions): formatOptions is ThroughputFormatOptions {\n return getUnitGroup(formatOptions) === 'Throughput';\n}\n\nexport function isCurrencyUnit(formatOptions: FormatOptions): formatOptions is CurrencyFormatOptions {\n return getUnitGroup(formatOptions) === 'Currency';\n}\n\nexport function isDateUnit(formatOptions: FormatOptions): formatOptions is DateFormatOptions {\n return getUnitGroup(formatOptions) === 'Date';\n}\n\nexport function isTemperatureUnit(formatOptions: FormatOptions): formatOptions is TemperatureFormatOptions {\n return getUnitGroup(formatOptions) === 'Temperature';\n}\n"],"names":["formatBits","BITS_GROUP_CONFIG","BITS_UNIT_CONFIG","formatBytes","BYTES_GROUP_CONFIG","BYTES_UNIT_CONFIG","formatCurrency","CURRENCY_GROUP_CONFIG","CURRENCY_UNIT_CONFIG","formatDate","DATE_GROUP_CONFIG","DATE_UNIT_CONFIG","formatDecimal","DECIMAL_GROUP_CONFIG","DECIMAL_UNIT_CONFIG","formatPercent","PERCENT_GROUP_CONFIG","PERCENT_UNIT_CONFIG","TEMPERATURE_GROUP_CONFIG","formatTemperature","TEMPERATURE_UNIT_CONFIG","formatThroughput","THROUGHPUT_GROUP_CONFIG","THROUGHPUT_UNIT_CONFIG","formatTime","TIME_GROUP_CONFIG","TIME_UNIT_CONFIG","UNIT_GROUP_CONFIG","Time","Percent","Decimal","Bytes","Bits","Throughput","Currency","Temperature","Date","UNIT_CONFIG","formatValue","value","formatOptions","toString","isBytesUnit","isBitsUnit","isDecimalUnit","isPercentUnit","isTimeUnit","isThroughputUnit","isCurrencyUnit","isDateUnit","isTemperatureUnit","exhaustive","Error","getUnitConfig","unit","getUnitGroup","group","getUnitGroupConfig","unitConfig","isUnitWithDecimalPlaces","groupConfig","decimalPlaces","isUnitWithShortValues","shortValues"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/model/units.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 { BitsFormatOptions } from './bits';\nimport { formatBits, BITS_GROUP_CONFIG, BITS_UNIT_CONFIG } from './bits';\nimport type { BytesFormatOptions } from './bytes';\nimport { formatBytes, BYTES_GROUP_CONFIG, BYTES_UNIT_CONFIG } from './bytes';\nimport type { CurrencyFormatOptions } from './currency';\nimport { formatCurrency, CURRENCY_GROUP_CONFIG, CURRENCY_UNIT_CONFIG } from './currency';\nimport type { WithCustomLabel } from './custom';\nimport { applyCustomLabel, supportsCustomLabel } from './custom';\nimport type { DateFormatOptions } from './date';\nimport { formatDate, DATE_GROUP_CONFIG, DATE_UNIT_CONFIG } from './date';\nimport type { DecimalFormatOptions } from './decimal';\nimport { formatDecimal, DECIMAL_GROUP_CONFIG, DECIMAL_UNIT_CONFIG } from './decimal';\nimport type { PercentFormatOptions } from './percent';\nimport { formatPercent, PERCENT_GROUP_CONFIG, PERCENT_UNIT_CONFIG } from './percent';\nimport type { TemperatureFormatOptions } from './temperature';\nimport { TEMPERATURE_GROUP_CONFIG, formatTemperature, TEMPERATURE_UNIT_CONFIG } from './temperature';\nimport type { ThroughputFormatOptions } from './throughput';\nimport { formatThroughput, THROUGHPUT_GROUP_CONFIG, THROUGHPUT_UNIT_CONFIG } from './throughput';\nimport type { TimeFormatOptions } from './time';\nimport { formatTime, TIME_GROUP_CONFIG, TIME_UNIT_CONFIG } from './time';\nimport type { UnitGroup, UnitGroupConfig, UnitConfig } from './types';\n\n/**\n * Most of the number formatting is based on Intl.NumberFormat, which is built into JavaScript.\n * Prefer Intl.NumbeFormat because it covers most use cases and will continue to be supported with time.\n *\n * To format bytes, we also make use of the `numbro` package,\n * because it can handle adding units like KB, MB, GB, etc. correctly.\n */\n\nexport const UNIT_GROUP_CONFIG: Readonly<Record<UnitGroup, UnitGroupConfig>> = {\n Time: TIME_GROUP_CONFIG,\n Percent: PERCENT_GROUP_CONFIG,\n Decimal: DECIMAL_GROUP_CONFIG,\n Bytes: BYTES_GROUP_CONFIG,\n Bits: BITS_GROUP_CONFIG,\n Throughput: THROUGHPUT_GROUP_CONFIG,\n Currency: CURRENCY_GROUP_CONFIG,\n Temperature: TEMPERATURE_GROUP_CONFIG,\n Date: DATE_GROUP_CONFIG,\n};\nexport const UNIT_CONFIG = {\n ...TIME_UNIT_CONFIG,\n ...PERCENT_UNIT_CONFIG,\n ...DECIMAL_UNIT_CONFIG,\n ...BYTES_UNIT_CONFIG,\n ...BITS_UNIT_CONFIG,\n ...THROUGHPUT_UNIT_CONFIG,\n ...CURRENCY_UNIT_CONFIG,\n ...TEMPERATURE_UNIT_CONFIG,\n ...DATE_UNIT_CONFIG,\n} as const;\n\n/** Standard unit options plus optional display override (customLabel). */\nexport type FormatOptions = (\n | TimeFormatOptions\n | PercentFormatOptions\n | DecimalFormatOptions\n | BytesFormatOptions\n | BitsFormatOptions\n | ThroughputFormatOptions\n | CurrencyFormatOptions\n | TemperatureFormatOptions\n | DateFormatOptions\n) &\n WithCustomLabel;\n\ntype HasDecimalPlaces<UnitOpt> = UnitOpt extends { decimalPlaces?: number } ? UnitOpt : never;\ntype HasShortValues<UnitOpt> = UnitOpt extends { shortValues?: boolean } ? UnitOpt : never;\n\nexport function formatValue(value: number, formatOptions?: FormatOptions): string {\n if (!formatOptions) {\n return value.toString();\n }\n\n let formatted: string;\n if (isBytesUnit(formatOptions)) {\n formatted = formatBytes(value, formatOptions);\n } else if (isBitsUnit(formatOptions)) {\n formatted = formatBits(value, formatOptions);\n } else if (isDecimalUnit(formatOptions)) {\n formatted = formatDecimal(value, formatOptions);\n } else if (isPercentUnit(formatOptions)) {\n formatted = formatPercent(value, formatOptions);\n } else if (isTimeUnit(formatOptions)) {\n formatted = formatTime(value, formatOptions);\n } else if (isThroughputUnit(formatOptions)) {\n formatted = formatThroughput(value, formatOptions);\n } else if (isCurrencyUnit(formatOptions)) {\n formatted = formatCurrency(value, formatOptions);\n } else if (isDateUnit(formatOptions)) {\n formatted = formatDate(value, formatOptions);\n } else if (isTemperatureUnit(formatOptions)) {\n formatted = formatTemperature(value, formatOptions);\n } else {\n const exhaustive: never = formatOptions;\n throw new Error(`Unknown unit options ${exhaustive}`);\n }\n\n return applyCustomLabel(formatted, formatOptions.customLabel, formatOptions.unit);\n}\n\nexport function getUnitConfig(formatOptions: FormatOptions): UnitConfig {\n const unit = formatOptions.unit ?? 'decimal';\n const config = UNIT_CONFIG[unit];\n const customLabel = formatOptions.customLabel?.trim();\n // Only override display name when customLabel is supported for this unit key.\n if (customLabel && supportsCustomLabel(unit)) {\n return { ...config, label: customLabel };\n }\n return config;\n}\n\nexport function getUnitGroup(formatOptions: FormatOptions): UnitGroup {\n return getUnitConfig(formatOptions).group ?? 'Decimal';\n}\n\nexport function getUnitGroupConfig(formatOptions: FormatOptions): UnitGroupConfig {\n const unitConfig = getUnitConfig(formatOptions);\n return UNIT_GROUP_CONFIG[unitConfig.group ?? 'Decimal'];\n}\n\n// Type guards\nexport function isTimeUnit(formatOptions: FormatOptions): formatOptions is TimeFormatOptions & WithCustomLabel {\n return getUnitGroup(formatOptions) === 'Time';\n}\n\nexport function isPercentUnit(formatOptions: FormatOptions): formatOptions is PercentFormatOptions & WithCustomLabel {\n return getUnitGroup(formatOptions) === 'Percent';\n}\n\nexport function isDecimalUnit(formatOptions: FormatOptions): formatOptions is DecimalFormatOptions & WithCustomLabel {\n return getUnitGroup(formatOptions) === 'Decimal';\n}\n\nexport function isBytesUnit(formatOptions: FormatOptions): formatOptions is BytesFormatOptions & WithCustomLabel {\n return getUnitGroup(formatOptions) === 'Bytes';\n}\n\nexport function isBitsUnit(formatOptions: FormatOptions): formatOptions is BitsFormatOptions & WithCustomLabel {\n return getUnitGroup(formatOptions) === 'Bits';\n}\n\nexport function isUnitWithDecimalPlaces(\n formatOptions: FormatOptions,\n): formatOptions is HasDecimalPlaces<FormatOptions> {\n const groupConfig = getUnitGroupConfig(formatOptions);\n\n return !!groupConfig.decimalPlaces;\n}\n\nexport function isUnitWithShortValues(formatOptions: FormatOptions): formatOptions is HasShortValues<FormatOptions> {\n const groupConfig = getUnitGroupConfig(formatOptions);\n\n return !!groupConfig.shortValues;\n}\n\nexport function isThroughputUnit(\n formatOptions: FormatOptions,\n): formatOptions is ThroughputFormatOptions & WithCustomLabel {\n return getUnitGroup(formatOptions) === 'Throughput';\n}\n\nexport function isCurrencyUnit(formatOptions: FormatOptions): formatOptions is CurrencyFormatOptions & WithCustomLabel {\n return getUnitGroup(formatOptions) === 'Currency';\n}\n\nexport function isDateUnit(formatOptions: FormatOptions): formatOptions is DateFormatOptions & WithCustomLabel {\n return getUnitGroup(formatOptions) === 'Date';\n}\n\nexport function isTemperatureUnit(\n formatOptions: FormatOptions,\n): formatOptions is TemperatureFormatOptions & WithCustomLabel {\n return getUnitGroup(formatOptions) === 'Temperature';\n}\n"],"names":["formatBits","BITS_GROUP_CONFIG","BITS_UNIT_CONFIG","formatBytes","BYTES_GROUP_CONFIG","BYTES_UNIT_CONFIG","formatCurrency","CURRENCY_GROUP_CONFIG","CURRENCY_UNIT_CONFIG","applyCustomLabel","supportsCustomLabel","formatDate","DATE_GROUP_CONFIG","DATE_UNIT_CONFIG","formatDecimal","DECIMAL_GROUP_CONFIG","DECIMAL_UNIT_CONFIG","formatPercent","PERCENT_GROUP_CONFIG","PERCENT_UNIT_CONFIG","TEMPERATURE_GROUP_CONFIG","formatTemperature","TEMPERATURE_UNIT_CONFIG","formatThroughput","THROUGHPUT_GROUP_CONFIG","THROUGHPUT_UNIT_CONFIG","formatTime","TIME_GROUP_CONFIG","TIME_UNIT_CONFIG","UNIT_GROUP_CONFIG","Time","Percent","Decimal","Bytes","Bits","Throughput","Currency","Temperature","Date","UNIT_CONFIG","formatValue","value","formatOptions","toString","formatted","isBytesUnit","isBitsUnit","isDecimalUnit","isPercentUnit","isTimeUnit","isThroughputUnit","isCurrencyUnit","isDateUnit","isTemperatureUnit","exhaustive","Error","customLabel","unit","getUnitConfig","config","trim","label","getUnitGroup","group","getUnitGroupConfig","unitConfig","isUnitWithDecimalPlaces","groupConfig","decimalPlaces","isUnitWithShortValues","shortValues"],"mappings":"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"}
@@ -2,10 +2,8 @@ export * from './axis';
2
2
  export * from './browser-storage';
3
3
  export * from './chart-actions';
4
4
  export * from './combine-sx';
5
- export * from './component-ids';
6
5
  export * from './data-field-interpolation';
7
6
  export * from './format';
8
- export * from './memo';
9
7
  export * from './request-interpolation';
10
8
  export * from './selection-interpolation';
11
9
  export * from './theme-gen';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAaA,cAAc,QAAQ,CAAC;AACvB,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAaA,cAAc,QAAQ,CAAC;AACvB,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,UAAU,CAAC;AACzB,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC"}
@@ -14,10 +14,8 @@ export * from "./axis.js";
14
14
  export * from "./browser-storage.js";
15
15
  export * from "./chart-actions.js";
16
16
  export * from "./combine-sx.js";
17
- export * from "./component-ids.js";
18
17
  export * from "./data-field-interpolation.js";
19
18
  export * from "./format.js";
20
- export * from "./memo.js";
21
19
  export * from "./request-interpolation.js";
22
20
  export * from "./selection-interpolation.js";
23
21
  export * from "./theme-gen.js";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/index.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\nexport * from './axis';\nexport * from './browser-storage';\nexport * from './chart-actions';\nexport * from './combine-sx';\nexport * from './component-ids';\nexport * from './data-field-interpolation';\nexport * from './format';\nexport * from './memo';\nexport * from './request-interpolation';\nexport * from './selection-interpolation';\nexport * from './theme-gen';\nexport * from './variable-interpolation';\nexport * from './value-mapping';\nexport * from './regexp';\nexport * from './transform-data';\nexport * from './time-series-data';\nexport * from './trace-data';\nexport * from './types';\nexport * from './text';\n"],"names":[],"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,cAAc,YAAS;AACvB,cAAc,uBAAoB;AAClC,cAAc,qBAAkB;AAChC,cAAc,kBAAe;AAC7B,cAAc,qBAAkB;AAChC,cAAc,gCAA6B;AAC3C,cAAc,cAAW;AACzB,cAAc,YAAS;AACvB,cAAc,6BAA0B;AACxC,cAAc,+BAA4B;AAC1C,cAAc,iBAAc;AAC5B,cAAc,8BAA2B;AACzC,cAAc,qBAAkB;AAChC,cAAc,cAAW;AACzB,cAAc,sBAAmB;AACjC,cAAc,wBAAqB;AACnC,cAAc,kBAAe;AAC7B,cAAc,aAAU;AACxB,cAAc,YAAS"}
1
+ {"version":3,"sources":["../../src/utils/index.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\nexport * from './axis';\nexport * from './browser-storage';\nexport * from './chart-actions';\nexport * from './combine-sx';\nexport * from './data-field-interpolation';\nexport * from './format';\nexport * from './request-interpolation';\nexport * from './selection-interpolation';\nexport * from './theme-gen';\nexport * from './variable-interpolation';\nexport * from './value-mapping';\nexport * from './regexp';\nexport * from './transform-data';\nexport * from './time-series-data';\nexport * from './trace-data';\nexport * from './types';\nexport * from './text';\n"],"names":[],"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,cAAc,YAAS;AACvB,cAAc,uBAAoB;AAClC,cAAc,qBAAkB;AAChC,cAAc,kBAAe;AAC7B,cAAc,gCAA6B;AAC3C,cAAc,cAAW;AACzB,cAAc,6BAA0B;AACxC,cAAc,+BAA4B;AAC1C,cAAc,iBAAc;AAC5B,cAAc,8BAA2B;AACzC,cAAc,qBAAkB;AAChC,cAAc,cAAW;AACzB,cAAc,sBAAmB;AACjC,cAAc,wBAAqB;AACnC,cAAc,kBAAe;AAC7B,cAAc,aAAU;AACxB,cAAc,YAAS"}
@@ -1 +1 @@
1
- {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/utils/text.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,QAAQ,EAAE,QAAQ,EAAE,CAAC,GAAG,MAAM,CAY9E;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,CAAC,SAAS,QAAQ,EAAE,QAAQ,EAAE,CAAC,GAAG,MAAM,CAYtF"}
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/utils/text.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAenD,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,QAAQ,EAAE,QAAQ,EAAE,CAAC,GAAG,MAAM,CAE9E;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,CAAC,SAAS,QAAQ,EAAE,QAAQ,EAAE,CAAC,GAAG,MAAM,CAGtF"}
@@ -10,30 +10,26 @@
10
10
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
+ function getDisplayName(spec) {
14
+ if (typeof spec !== 'object' || spec === null || !('display' in spec)) return undefined;
15
+ const { display } = spec;
16
+ if (typeof display !== 'object' || display === null || !('name' in display)) return undefined;
17
+ return typeof display.name === 'string' && display.name ? display.name : undefined;
18
+ }
19
+ function getSpecDisplayName(spec) {
20
+ // Variables wrap their display settings in a nested spec.
21
+ const nestedSpec = typeof spec === 'object' && spec !== null && 'spec' in spec ? spec.spec : undefined;
22
+ return getDisplayName(nestedSpec) ?? getDisplayName(spec);
23
+ }
13
24
  export function getResourceDisplayName(resource) {
14
- // Variables
15
- if (resource.spec?.spec?.display?.name) {
16
- return resource.spec.spec.display.name;
17
- }
18
- // Other resources with display
19
- if (resource.spec?.display?.name) {
20
- return resource.spec.display.name;
21
- }
22
- return resource.metadata.name;
25
+ return getSpecDisplayName(resource.spec) ?? resource.metadata.name;
23
26
  }
24
27
  /**
25
28
  * If the resource has a display name, return the resource display name with the resource name too
26
29
  * Else, only return the resource name
27
30
  */ export function getResourceExtendedDisplayName(resource) {
28
- // Variables
29
- if (resource.spec?.spec?.display?.name) {
30
- return `${resource.spec.spec.display.name} (ID: ${resource.metadata.name})`;
31
- }
32
- // Other resources with display
33
- if (resource.spec?.display?.name) {
34
- return `${resource.spec.display.name} (ID: ${resource.metadata.name})`;
35
- }
36
- return resource.metadata.name;
31
+ const displayName = getSpecDisplayName(resource.spec);
32
+ return displayName ? `${displayName} (ID: ${resource.metadata.name})` : resource.metadata.name;
37
33
  }
38
34
 
39
35
  //# sourceMappingURL=text.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/text.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 { Resource } from '@perses-dev/client';\n\nexport function getResourceDisplayName<T extends Resource>(resource: T): string {\n // Variables\n if (resource.spec?.spec?.display?.name) {\n return resource.spec.spec.display.name;\n }\n\n // Other resources with display\n if (resource.spec?.display?.name) {\n return resource.spec.display.name;\n }\n\n return resource.metadata.name;\n}\n\n/**\n * If the resource has a display name, return the resource display name with the resource name too\n * Else, only return the resource name\n */\nexport function getResourceExtendedDisplayName<T extends Resource>(resource: T): string {\n // Variables\n if (resource.spec?.spec?.display?.name) {\n return `${resource.spec.spec.display.name} (ID: ${resource.metadata.name})`;\n }\n\n // Other resources with display\n if (resource.spec?.display?.name) {\n return `${resource.spec.display.name} (ID: ${resource.metadata.name})`;\n }\n\n return resource.metadata.name;\n}\n"],"names":["getResourceDisplayName","resource","spec","display","name","metadata","getResourceExtendedDisplayName"],"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;AAIjC,OAAO,SAASA,uBAA2CC,QAAW;IACpE,YAAY;IACZ,IAAIA,SAASC,IAAI,EAAEA,MAAMC,SAASC,MAAM;QACtC,OAAOH,SAASC,IAAI,CAACA,IAAI,CAACC,OAAO,CAACC,IAAI;IACxC;IAEA,+BAA+B;IAC/B,IAAIH,SAASC,IAAI,EAAEC,SAASC,MAAM;QAChC,OAAOH,SAASC,IAAI,CAACC,OAAO,CAACC,IAAI;IACnC;IAEA,OAAOH,SAASI,QAAQ,CAACD,IAAI;AAC/B;AAEA;;;CAGC,GACD,OAAO,SAASE,+BAAmDL,QAAW;IAC5E,YAAY;IACZ,IAAIA,SAASC,IAAI,EAAEA,MAAMC,SAASC,MAAM;QACtC,OAAO,GAAGH,SAASC,IAAI,CAACA,IAAI,CAACC,OAAO,CAACC,IAAI,CAAC,MAAM,EAAEH,SAASI,QAAQ,CAACD,IAAI,CAAC,CAAC,CAAC;IAC7E;IAEA,+BAA+B;IAC/B,IAAIH,SAASC,IAAI,EAAEC,SAASC,MAAM;QAChC,OAAO,GAAGH,SAASC,IAAI,CAACC,OAAO,CAACC,IAAI,CAAC,MAAM,EAAEH,SAASI,QAAQ,CAACD,IAAI,CAAC,CAAC,CAAC;IACxE;IAEA,OAAOH,SAASI,QAAQ,CAACD,IAAI;AAC/B"}
1
+ {"version":3,"sources":["../../src/utils/text.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 { Resource } from '@perses-dev/client';\n\nfunction getDisplayName(spec: unknown): string | undefined {\n if (typeof spec !== 'object' || spec === null || !('display' in spec)) return undefined;\n const { display } = spec;\n if (typeof display !== 'object' || display === null || !('name' in display)) return undefined;\n return typeof display.name === 'string' && display.name ? display.name : undefined;\n}\n\nfunction getSpecDisplayName(spec: unknown): string | undefined {\n // Variables wrap their display settings in a nested spec.\n const nestedSpec = typeof spec === 'object' && spec !== null && 'spec' in spec ? spec.spec : undefined;\n return getDisplayName(nestedSpec) ?? getDisplayName(spec);\n}\n\nexport function getResourceDisplayName<T extends Resource>(resource: T): string {\n return getSpecDisplayName(resource.spec) ?? resource.metadata.name;\n}\n\n/**\n * If the resource has a display name, return the resource display name with the resource name too\n * Else, only return the resource name\n */\nexport function getResourceExtendedDisplayName<T extends Resource>(resource: T): string {\n const displayName = getSpecDisplayName(resource.spec);\n return displayName ? `${displayName} (ID: ${resource.metadata.name})` : resource.metadata.name;\n}\n"],"names":["getDisplayName","spec","undefined","display","name","getSpecDisplayName","nestedSpec","getResourceDisplayName","resource","metadata","getResourceExtendedDisplayName","displayName"],"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;AAIjC,SAASA,eAAeC,IAAa;IACnC,IAAI,OAAOA,SAAS,YAAYA,SAAS,QAAQ,CAAE,CAAA,aAAaA,IAAG,GAAI,OAAOC;IAC9E,MAAM,EAAEC,OAAO,EAAE,GAAGF;IACpB,IAAI,OAAOE,YAAY,YAAYA,YAAY,QAAQ,CAAE,CAAA,UAAUA,OAAM,GAAI,OAAOD;IACpF,OAAO,OAAOC,QAAQC,IAAI,KAAK,YAAYD,QAAQC,IAAI,GAAGD,QAAQC,IAAI,GAAGF;AAC3E;AAEA,SAASG,mBAAmBJ,IAAa;IACvC,0DAA0D;IAC1D,MAAMK,aAAa,OAAOL,SAAS,YAAYA,SAAS,QAAQ,UAAUA,OAAOA,KAAKA,IAAI,GAAGC;IAC7F,OAAOF,eAAeM,eAAeN,eAAeC;AACtD;AAEA,OAAO,SAASM,uBAA2CC,QAAW;IACpE,OAAOH,mBAAmBG,SAASP,IAAI,KAAKO,SAASC,QAAQ,CAACL,IAAI;AACpE;AAEA;;;CAGC,GACD,OAAO,SAASM,+BAAmDF,QAAW;IAC5E,MAAMG,cAAcN,mBAAmBG,SAASP,IAAI;IACpD,OAAOU,cAAc,GAAGA,YAAY,MAAM,EAAEH,SAASC,QAAQ,CAACL,IAAI,CAAC,CAAC,CAAC,GAAGI,SAASC,QAAQ,CAACL,IAAI;AAChG"}
@@ -3,5 +3,10 @@ export declare function applyJoinTransform(data: Array<Record<string, unknown>>,
3
3
  export declare function applyMergeColumnsTransform(data: Array<Record<string, unknown>>, selectedColumns: string[], outputName: string): Array<Record<string, unknown>>;
4
4
  export declare function applyMergeIndexedColumnsTransform(data: Array<Record<string, unknown>>, column: string): Array<Record<string, unknown>>;
5
5
  export declare function applyMergeSeriesTransform(data: Array<Record<string, unknown>>): Array<Record<string, unknown>>;
6
+ /**
7
+ * Pivot: rows grouped by rowField, dynamic columns from columnLabel values.
8
+ * Last value wins on duplicate (time, label).
9
+ */
10
+ export declare function applyPivotByLabelTransform(data: Array<Record<string, unknown>>, columnLabel: string, rowField?: string, valueField?: string, rowColumnName?: string): Array<Record<string, unknown>>;
6
11
  export declare function transformData(data: Array<Record<string, unknown>>, transforms: Transform[]): Array<Record<string, unknown>>;
7
12
  //# sourceMappingURL=transform-data.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transform-data.d.ts","sourceRoot":"","sources":["../../src/utils/transform-data.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAqB1C,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACpC,OAAO,EAAE,MAAM,EAAE,GAChB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAsBhC;AA0BD,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACpC,eAAe,EAAE,MAAM,EAAE,EACzB,UAAU,EAAE,MAAM,GACjB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAuBhC;AA0BD,wBAAgB,iCAAiC,CAC/C,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACpC,MAAM,EAAE,MAAM,GACb,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAwBhC;AAmBD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAmB9G;AAKD,wBAAgB,aAAa,CAC3B,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACpC,UAAU,EAAE,SAAS,EAAE,GACtB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA2ChC"}
1
+ {"version":3,"file":"transform-data.d.ts","sourceRoot":"","sources":["../../src/utils/transform-data.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAqB1C,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACpC,OAAO,EAAE,MAAM,EAAE,GAChB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAsBhC;AA0BD,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACpC,eAAe,EAAE,MAAM,EAAE,EACzB,UAAU,EAAE,MAAM,GACjB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAuBhC;AA0BD,wBAAgB,iCAAiC,CAC/C,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACpC,MAAM,EAAE,MAAM,GACb,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAwBhC;AAmBD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAmB9G;AAaD;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACpC,WAAW,EAAE,MAAM,EACnB,QAAQ,SAAc,EACtB,UAAU,SAAU,EACpB,aAAa,CAAC,EAAE,MAAM,GACrB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAqEhC;AAKD,wBAAgB,aAAa,CAC3B,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACpC,UAAU,EAAE,SAAS,EAAE,GACtB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAgEhC"}
@@ -165,13 +165,99 @@
165
165
  result = applyJoinTransform(result, labelColumns);
166
166
  return result;
167
167
  }
168
+ /** Treat empty string like omitted (editor / CUE can emit ""). */ function nonEmpty(s, fallback) {
169
+ return s?.trim() || fallback;
170
+ }
171
+ /** Resolve column key including MergeSeries suffixes ("value #2"). */ function resolvePivotKey(row, base) {
172
+ if (Object.hasOwn(row, base)) return base;
173
+ return Object.keys(row).find((k)=>k === base || k.startsWith(base + ' #') || k.startsWith(base + '#'));
174
+ }
175
+ /**
176
+ * Pivot: rows grouped by rowField, dynamic columns from columnLabel values.
177
+ * Last value wins on duplicate (time, label).
178
+ */ export function applyPivotByLabelTransform(data, columnLabel, rowField = 'timestamp', valueField = 'value', rowColumnName) {
179
+ if (!columnLabel || data.length === 0) {
180
+ return data;
181
+ }
182
+ const rowFieldName = nonEmpty(rowField, 'timestamp');
183
+ const valueFieldName = nonEmpty(valueField, 'value');
184
+ const rowCol = nonEmpty(rowColumnName, rowFieldName);
185
+ const labelSet = new Set();
186
+ const groups = new Map();
187
+ for (const row of data){
188
+ const rowKeyName = resolvePivotKey(row, rowFieldName);
189
+ const labelKeyName = resolvePivotKey(row, columnLabel);
190
+ const valueKeyName = resolvePivotKey(row, valueFieldName);
191
+ if (rowKeyName === undefined || labelKeyName === undefined) {
192
+ continue;
193
+ }
194
+ const rowKey = row[rowKeyName];
195
+ const label = row[labelKeyName];
196
+ if (rowKey === undefined || rowKey === null || label === undefined || label === null) {
197
+ continue;
198
+ }
199
+ // Avoid clobbering the row identity column when a series label equals rowCol.
200
+ // Skip blank labels (empty string / whitespace-only) — not meaningful column headers.
201
+ let labelStr = String(label).trim();
202
+ if (!labelStr) {
203
+ continue;
204
+ }
205
+ if (labelStr === rowCol) {
206
+ labelStr = `${labelStr} (value)`;
207
+ }
208
+ labelSet.add(labelStr);
209
+ const groupId = String(rowKey);
210
+ let out = groups.get(groupId);
211
+ if (!out) {
212
+ out = {
213
+ [rowCol]: rowKey
214
+ };
215
+ groups.set(groupId, out);
216
+ }
217
+ if (valueKeyName !== undefined) {
218
+ out[labelStr] = row[valueKeyName];
219
+ }
220
+ }
221
+ // Fresh copy from Set — mutate with sort() (no need for toSorted extra copy).
222
+ const labels = [
223
+ ...labelSet
224
+ ];
225
+ labels.sort((a, b)=>a.localeCompare(b));
226
+ const entries = [
227
+ ...groups.entries()
228
+ ];
229
+ entries.sort((a, b)=>{
230
+ const va = a[1][rowCol];
231
+ const vb = b[1][rowCol];
232
+ if (typeof va === 'number' && typeof vb === 'number') {
233
+ return vb - va;
234
+ }
235
+ return String(vb).localeCompare(String(va));
236
+ });
237
+ return entries.map(([, row])=>{
238
+ const ordered = {
239
+ [rowCol]: row[rowCol]
240
+ };
241
+ for (const lab of labels){
242
+ if (Object.hasOwn(row, lab)) {
243
+ ordered[lab] = row[lab];
244
+ }
245
+ }
246
+ return ordered;
247
+ });
248
+ }
168
249
  /*
169
250
  * Transforms query data with the given transforms
170
251
  */ export function transformData(data, transforms) {
171
252
  let result = data;
253
+ // Only skip final alpha sort when the last *enabled* transform is PivotByLabel
254
+ // (pivot already orders: row column first, then labels). Intermediate pivots must
255
+ // not leave skipAlphaSort stuck true for later transforms.
256
+ let lastEnabledKind;
172
257
  // Apply transforms by their orders
173
258
  for (const transform of transforms ?? []){
174
259
  if (transform.spec.disabled) continue;
260
+ lastEnabledKind = transform.kind;
175
261
  switch(transform.kind){
176
262
  case 'JoinByColumnValue':
177
263
  {
@@ -199,8 +285,18 @@
199
285
  result = applyMergeSeriesTransform(result);
200
286
  break;
201
287
  }
288
+ case 'PivotByLabel':
289
+ {
290
+ if (transform.spec.columnLabel) {
291
+ result = applyPivotByLabelTransform(result, transform.spec.columnLabel, nonEmpty(transform.spec.rowField, 'timestamp'), nonEmpty(transform.spec.valueField, 'value'), transform.spec.rowColumnName);
292
+ }
293
+ break;
294
+ }
202
295
  }
203
296
  }
297
+ if (lastEnabledKind === 'PivotByLabel') {
298
+ return result;
299
+ }
204
300
  // Ordering data column alphabetically
205
301
  result = result.map((row)=>{
206
302
  return Object.keys(row).toSorted().reduce((obj, key)=>{
@@ -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 .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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"}
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/** Treat empty string like omitted (editor / CUE can emit \"\"). */\nfunction nonEmpty(s: string | undefined, fallback: string): string {\n return s?.trim() || fallback;\n}\n\n/** Resolve column key including MergeSeries suffixes (\"value #2\"). */\nfunction resolvePivotKey(row: Record<string, unknown>, base: string): string | undefined {\n if (Object.hasOwn(row, base)) return base;\n return Object.keys(row).find((k) => k === base || k.startsWith(base + ' #') || k.startsWith(base + '#'));\n}\n\n/**\n * Pivot: rows grouped by rowField, dynamic columns from columnLabel values.\n * Last value wins on duplicate (time, label).\n */\nexport function applyPivotByLabelTransform(\n data: Array<Record<string, unknown>>,\n columnLabel: string,\n rowField = 'timestamp',\n valueField = 'value',\n rowColumnName?: string,\n): Array<Record<string, unknown>> {\n if (!columnLabel || data.length === 0) {\n return data;\n }\n\n const rowFieldName = nonEmpty(rowField, 'timestamp');\n const valueFieldName = nonEmpty(valueField, 'value');\n const rowCol = nonEmpty(rowColumnName, rowFieldName);\n\n const labelSet = new Set<string>();\n const groups = new Map<string, Record<string, unknown>>();\n\n for (const row of data) {\n const rowKeyName = resolvePivotKey(row, rowFieldName);\n const labelKeyName = resolvePivotKey(row, columnLabel);\n const valueKeyName = resolvePivotKey(row, valueFieldName);\n if (rowKeyName === undefined || labelKeyName === undefined) {\n continue;\n }\n\n const rowKey = row[rowKeyName];\n const label = row[labelKeyName];\n if (rowKey === undefined || rowKey === null || label === undefined || label === null) {\n continue;\n }\n\n // Avoid clobbering the row identity column when a series label equals rowCol.\n // Skip blank labels (empty string / whitespace-only) — not meaningful column headers.\n let labelStr = String(label).trim();\n if (!labelStr) {\n continue;\n }\n if (labelStr === rowCol) {\n labelStr = `${labelStr} (value)`;\n }\n labelSet.add(labelStr);\n const groupId = String(rowKey);\n\n let out = groups.get(groupId);\n if (!out) {\n out = { [rowCol]: rowKey };\n groups.set(groupId, out);\n }\n if (valueKeyName !== undefined) {\n out[labelStr] = row[valueKeyName];\n }\n }\n\n // Fresh copy from Set — mutate with sort() (no need for toSorted extra copy).\n const labels = [...labelSet];\n labels.sort((a, b) => a.localeCompare(b));\n const entries = [...groups.entries()];\n entries.sort((a, b) => {\n const va = a[1][rowCol];\n const vb = b[1][rowCol];\n if (typeof va === 'number' && typeof vb === 'number') {\n return vb - va;\n }\n return String(vb).localeCompare(String(va));\n });\n return entries.map(([, row]) => {\n const ordered: Record<string, unknown> = { [rowCol]: row[rowCol] };\n for (const lab of labels) {\n if (Object.hasOwn(row, lab)) {\n ordered[lab] = row[lab];\n }\n }\n return ordered;\n });\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 // Only skip final alpha sort when the last *enabled* transform is PivotByLabel\n // (pivot already orders: row column first, then labels). Intermediate pivots must\n // not leave skipAlphaSort stuck true for later transforms.\n let lastEnabledKind: Transform['kind'] | undefined;\n\n // Apply transforms by their orders\n for (const transform of transforms ?? []) {\n if (transform.spec.disabled) continue;\n lastEnabledKind = transform.kind;\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 case 'PivotByLabel': {\n if (transform.spec.columnLabel) {\n result = applyPivotByLabelTransform(\n result,\n transform.spec.columnLabel,\n nonEmpty(transform.spec.rowField, 'timestamp'),\n nonEmpty(transform.spec.valueField, 'value'),\n transform.spec.rowColumnName,\n );\n }\n break;\n }\n }\n }\n\n if (lastEnabledKind === 'PivotByLabel') {\n return result;\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","nonEmpty","s","fallback","trim","resolvePivotKey","base","hasOwn","find","startsWith","applyPivotByLabelTransform","columnLabel","rowField","valueField","rowColumnName","rowFieldName","valueFieldName","rowCol","labelSet","groups","Map","rowKeyName","labelKeyName","valueKeyName","undefined","rowKey","labelStr","String","add","groupId","out","get","set","labels","sort","a","b","localeCompare","entries","va","vb","ordered","lab","transformData","transforms","lastEnabledKind","transform","spec","disabled","kind","name","toSorted","reduce","obj","key"],"mappings":"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"}
@@ -78,4 +78,15 @@ export declare function replaceVariables(text: string, variableState: VariableSt
78
78
  * Replace variables using their compact display values when available.
79
79
  */
80
80
  export declare function replaceVariablesForDisplay(text: string, variableState: VariableStateMap): string;
81
+ /**
82
+ * Replace dashboard variables in a URL, including those nested inside
83
+ * percent-encoded query parameters (e.g. Explore `data=%24var`).
84
+ *
85
+ * 1. `replaceVariables` on the raw string (unencoded `$var` still works).
86
+ * 2. Parse query params (URLSearchParams decodes once), expand each value,
87
+ * rebuild with `append` so repeated keys are preserved.
88
+ * 3. Keep the original path/prefix before `?` so relative targets are unchanged
89
+ * (`?data=…`, `explore?…`, not forced `/…`).
90
+ */
91
+ export declare function replaceVariablesInUrl(url: string, variableState: VariableStateMap): string;
81
92
  //# sourceMappingURL=variable-interpolation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"variable-interpolation.d.ts","sourceRoot":"","sources":["../../src/utils/variable-interpolation.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9D;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,aAAa,CAAC;IACrB;;OAEG;IACH,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAE7D;;GAEG;AACH,oBAAY,mBAAmB;IAC7B,GAAG,QAAQ;IACX,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAC3B,IAAI,SAAS;IACb,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,aAAa,kBAAkB;IAC/B,IAAI,SAAS;IACb,UAAU,eAAe;IACzB,GAAG,QAAQ;IACX,KAAK,UAAU;IACf,WAAW,gBAAgB;IAC3B,SAAS,cAAc;IACvB,IAAI,SAAS;IACb,UAAU,eAAe;IACzB,aAAa,iBAAiB;CAC/B;AASD;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAoD/F;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,aAAa,EAC5B,SAAS,CAAC,EAAE,mBAAmB,GAC9B,MAAM,CAaR;AAUD;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBrD;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,mBAAmB,GAAG,SAAS,CAAC,CAoBlG;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,gBAAgB,GAAG,MAAM,CAiBtF;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,gBAAgB,GAAG,MAAM,CAMhG"}
1
+ {"version":3,"file":"variable-interpolation.d.ts","sourceRoot":"","sources":["../../src/utils/variable-interpolation.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9D;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,aAAa,CAAC;IACrB;;OAEG;IACH,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAE7D;;GAEG;AACH,oBAAY,mBAAmB;IAC7B,GAAG,QAAQ;IACX,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAC3B,IAAI,SAAS;IACb,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,aAAa,kBAAkB;IAC/B,IAAI,SAAS;IACb,UAAU,eAAe;IACzB,GAAG,QAAQ;IACX,KAAK,UAAU;IACf,WAAW,gBAAgB;IAC3B,SAAS,cAAc;IACvB,IAAI,SAAS;IACb,UAAU,eAAe;IACzB,aAAa,iBAAiB;CAC/B;AASD;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAoD/F;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,aAAa,EAC5B,SAAS,CAAC,EAAE,mBAAmB,GAC9B,MAAM,CAaR;AAUD;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBrD;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,mBAAmB,GAAG,SAAS,CAAC,CAoBlG;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,gBAAgB,GAAG,MAAM,CAiBtF;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,gBAAgB,GAAG,MAAM,CAMhG;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,gBAAgB,GAAG,MAAM,CAwD1F"}
@@ -190,5 +190,69 @@ const VARIABLE_REGEX = /\$(\w+)|\${(\w+)(?:\.([^:^}]+))?(?::([^}]+))?}/gm;
190
190
  }
191
191
  return replaceVariables(text, displayState);
192
192
  }
193
+ /**
194
+ * Replace dashboard variables in a URL, including those nested inside
195
+ * percent-encoded query parameters (e.g. Explore `data=%24var`).
196
+ *
197
+ * 1. `replaceVariables` on the raw string (unencoded `$var` still works).
198
+ * 2. Parse query params (URLSearchParams decodes once), expand each value,
199
+ * rebuild with `append` so repeated keys are preserved.
200
+ * 3. Keep the original path/prefix before `?` so relative targets are unchanged
201
+ * (`?data=…`, `explore?…`, not forced `/…`).
202
+ */ export function replaceVariablesInUrl(url, variableState) {
203
+ let result = replaceVariables(url, variableState);
204
+ try {
205
+ const isAbsolute = /^https?:\/\//i.test(result);
206
+ const isProtocolRelative = result.startsWith('//');
207
+ // Skip non-http schemes (mailto:, etc.) — only expand via step 1.
208
+ const hasNonHttpScheme = /^[a-z][a-z0-9+.-]*:/i.test(result);
209
+ if (!isAbsolute && !isProtocolRelative && hasNonHttpScheme) {
210
+ return result;
211
+ }
212
+ const parseInput = isProtocolRelative ? `http:${result}` : result;
213
+ const parsedUrl = new URL(parseInput, isAbsolute || isProtocolRelative ? undefined : 'http://perses.local');
214
+ // Rebuild query in original pair order so searchParams key order is stable.
215
+ const originalEntries = Array.from(parsedUrl.searchParams.entries());
216
+ let changed = false;
217
+ const replacedEntries = originalEntries.map(([key, value])=>{
218
+ const replacedValue = replaceVariables(value, variableState);
219
+ if (replacedValue !== value) {
220
+ changed = true;
221
+ }
222
+ return [
223
+ key,
224
+ replacedValue
225
+ ];
226
+ });
227
+ if (!changed) {
228
+ return result;
229
+ }
230
+ const keysToClear = [
231
+ ...new Set(originalEntries.map(([key])=>key))
232
+ ];
233
+ for (const key of keysToClear){
234
+ parsedUrl.searchParams.delete(key);
235
+ }
236
+ for (const [key, value] of replacedEntries){
237
+ parsedUrl.searchParams.append(key, value);
238
+ }
239
+ if (isAbsolute) {
240
+ return parsedUrl.href;
241
+ }
242
+ if (isProtocolRelative) {
243
+ return `//${parsedUrl.host}${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}`;
244
+ }
245
+ // Relative: preserve original substring before ?/# (do not force leading /).
246
+ const q = result.indexOf('?');
247
+ const h = result.indexOf('#');
248
+ let baseEnd = result.length;
249
+ if (q >= 0) baseEnd = q;
250
+ else if (h >= 0) baseEnd = h;
251
+ const base = result.slice(0, baseEnd);
252
+ return `${base}${parsedUrl.search}${parsedUrl.hash}`;
253
+ } catch {
254
+ return result;
255
+ }
256
+ }
193
257
 
194
258
  //# sourceMappingURL=variable-interpolation.js.map
@@ -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 .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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"}
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\n/**\n * Replace dashboard variables in a URL, including those nested inside\n * percent-encoded query parameters (e.g. Explore `data=%24var`).\n *\n * 1. `replaceVariables` on the raw string (unencoded `$var` still works).\n * 2. Parse query params (URLSearchParams decodes once), expand each value,\n * rebuild with `append` so repeated keys are preserved.\n * 3. Keep the original path/prefix before `?` so relative targets are unchanged\n * (`?data=…`, `explore?…`, not forced `/…`).\n */\nexport function replaceVariablesInUrl(url: string, variableState: VariableStateMap): string {\n let result = replaceVariables(url, variableState);\n\n try {\n const isAbsolute = /^https?:\\/\\//i.test(result);\n const isProtocolRelative = result.startsWith('//');\n // Skip non-http schemes (mailto:, etc.) — only expand via step 1.\n const hasNonHttpScheme = /^[a-z][a-z0-9+.-]*:/i.test(result);\n if (!isAbsolute && !isProtocolRelative && hasNonHttpScheme) {\n return result;\n }\n\n const parseInput = isProtocolRelative ? `http:${result}` : result;\n const parsedUrl = new URL(parseInput, isAbsolute || isProtocolRelative ? undefined : 'http://perses.local');\n\n // Rebuild query in original pair order so searchParams key order is stable.\n const originalEntries = Array.from(parsedUrl.searchParams.entries());\n let changed = false;\n const replacedEntries = originalEntries.map(([key, value]) => {\n const replacedValue = replaceVariables(value, variableState);\n if (replacedValue !== value) {\n changed = true;\n }\n return [key, replacedValue] as const;\n });\n\n if (!changed) {\n return result;\n }\n\n const keysToClear = [...new Set(originalEntries.map(([key]) => key))];\n for (const key of keysToClear) {\n parsedUrl.searchParams.delete(key);\n }\n for (const [key, value] of replacedEntries) {\n parsedUrl.searchParams.append(key, value);\n }\n\n if (isAbsolute) {\n return parsedUrl.href;\n }\n if (isProtocolRelative) {\n return `//${parsedUrl.host}${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}`;\n }\n\n // Relative: preserve original substring before ?/# (do not force leading /).\n const q = result.indexOf('?');\n const h = result.indexOf('#');\n let baseEnd = result.length;\n if (q >= 0) baseEnd = q;\n else if (h >= 0) baseEnd = h;\n const base = result.slice(0, baseEnd);\n return `${base}${parsedUrl.search}${parsedUrl.hash}`;\n } catch {\n return result;\n }\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","replaceVariablesInUrl","url","result","isAbsolute","test","isProtocolRelative","startsWith","hasNonHttpScheme","parseInput","parsedUrl","URL","originalEntries","searchParams","changed","replacedEntries","key","replacedValue","keysToClear","delete","append","href","host","pathname","search","hash","q","indexOf","h","baseEnd","base","slice"],"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.8",
3
+ "version": "0.55.0-rc.0",
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",
@@ -34,8 +34,8 @@
34
34
  "@date-fns/tz": "^1.4.1",
35
35
  "@fontsource/inter": "^5.0.0",
36
36
  "@mui/x-date-pickers": "^7.23.1",
37
- "@perses-dev/spec": "0.3.0-beta.7",
38
- "@perses-dev/client": "0.55.0-beta.8",
37
+ "@perses-dev/spec": "0.3.0-rc.0",
38
+ "@perses-dev/client": "0.55.0-rc.0",
39
39
  "numbro": "^2.3.6",
40
40
  "@tanstack/match-sorter-utils": "^8.19.4",
41
41
  "@tanstack/react-table": "^8.20.5",
@@ -1,8 +0,0 @@
1
- declare global {
2
- var useIdValue: number;
3
- }
4
- /**
5
- * Generates a unique (stable) ID for a component. Should be replaced with React.useId once we support only React 18.
6
- */
7
- export declare function useId(prefix: string): string;
8
- //# sourceMappingURL=component-ids.d.ts.map