@perses-dev/components 0.55.0-beta.10 → 0.55.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/TransformsEditor/TransformEditor.d.ts.map +1 -1
- package/dist/TransformsEditor/TransformEditor.js +89 -0
- package/dist/TransformsEditor/TransformEditor.js.map +1 -1
- package/dist/model/transforms.d.ts +22 -1
- package/dist/model/transforms.d.ts.map +1 -1
- package/dist/model/transforms.js +2 -1
- package/dist/model/transforms.js.map +1 -1
- package/dist/utils/transform-data.d.ts +5 -0
- package/dist/utils/transform-data.d.ts.map +1 -1
- package/dist/utils/transform-data.js +96 -0
- package/dist/utils/transform-data.js.map +1 -1
- package/dist/utils/variable-interpolation.d.ts +11 -0
- package/dist/utils/variable-interpolation.d.ts.map +1 -1
- package/dist/utils/variable-interpolation.js +64 -0
- package/dist/utils/variable-interpolation.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransformEditor.d.ts","sourceRoot":"","sources":["../../src/TransformsEditor/TransformEditor.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAUhD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAG1C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"TransformEditor.d.ts","sourceRoot":"","sources":["../../src/TransformsEditor/TransformEditor.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAUhD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAG1C,OAAO,KAAK,EAMV,SAAS,EACV,MAAM,UAAU,CAAC;AAiLlB,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,GAAG,UAAU,CAAC;IAC/F,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;CAC1C;AAED,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,oBAAoB,GAAG,YAAY,CA+CjG"}
|
|
@@ -263,6 +263,20 @@ export function TransformEditor({ value, onChange, ...props }) {
|
|
|
263
263
|
})
|
|
264
264
|
]
|
|
265
265
|
})
|
|
266
|
+
}),
|
|
267
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
268
|
+
value: "PivotByLabel",
|
|
269
|
+
children: /*#__PURE__*/ _jsxs(Stack, {
|
|
270
|
+
children: [
|
|
271
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
272
|
+
children: "Pivot by label"
|
|
273
|
+
}),
|
|
274
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
275
|
+
variant: "caption",
|
|
276
|
+
children: "Time × label matrix (rows = time, columns = label values)"
|
|
277
|
+
})
|
|
278
|
+
]
|
|
279
|
+
})
|
|
266
280
|
})
|
|
267
281
|
]
|
|
268
282
|
}),
|
|
@@ -281,6 +295,81 @@ export function TransformEditor({ value, onChange, ...props }) {
|
|
|
281
295
|
value.kind === 'MergeSeries' && /*#__PURE__*/ _jsx(MergeSeriesTransformEditor, {
|
|
282
296
|
value: value,
|
|
283
297
|
onChange: onChange
|
|
298
|
+
}),
|
|
299
|
+
value.kind === 'PivotByLabel' && /*#__PURE__*/ _jsx(PivotByLabelTransformEditor, {
|
|
300
|
+
value: value,
|
|
301
|
+
onChange: onChange
|
|
302
|
+
})
|
|
303
|
+
]
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
function PivotByLabelTransformEditor({ value, onChange }) {
|
|
307
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
308
|
+
gap: 2,
|
|
309
|
+
children: [
|
|
310
|
+
/*#__PURE__*/ _jsx(MuiTextField, {
|
|
311
|
+
label: "Column label",
|
|
312
|
+
fullWidth: true,
|
|
313
|
+
value: value.spec.columnLabel ?? '',
|
|
314
|
+
onChange: (e)=>onChange({
|
|
315
|
+
...value,
|
|
316
|
+
spec: {
|
|
317
|
+
...value.spec,
|
|
318
|
+
columnLabel: e.target.value
|
|
319
|
+
}
|
|
320
|
+
}),
|
|
321
|
+
helperText: "Label that becomes dynamic column headers (e.g. farm_short)"
|
|
322
|
+
}),
|
|
323
|
+
/*#__PURE__*/ _jsx(MuiTextField, {
|
|
324
|
+
label: "Row field",
|
|
325
|
+
fullWidth: true,
|
|
326
|
+
value: value.spec.rowField ?? 'timestamp',
|
|
327
|
+
onChange: (e)=>onChange({
|
|
328
|
+
...value,
|
|
329
|
+
spec: {
|
|
330
|
+
...value.spec,
|
|
331
|
+
rowField: e.target.value
|
|
332
|
+
}
|
|
333
|
+
}),
|
|
334
|
+
helperText: "Field used for row identity (default: timestamp)"
|
|
335
|
+
}),
|
|
336
|
+
/*#__PURE__*/ _jsx(MuiTextField, {
|
|
337
|
+
label: "Value field",
|
|
338
|
+
fullWidth: true,
|
|
339
|
+
value: value.spec.valueField ?? 'value',
|
|
340
|
+
onChange: (e)=>onChange({
|
|
341
|
+
...value,
|
|
342
|
+
spec: {
|
|
343
|
+
...value.spec,
|
|
344
|
+
valueField: e.target.value
|
|
345
|
+
}
|
|
346
|
+
})
|
|
347
|
+
}),
|
|
348
|
+
/*#__PURE__*/ _jsx(MuiTextField, {
|
|
349
|
+
label: "Row column name",
|
|
350
|
+
fullWidth: true,
|
|
351
|
+
value: value.spec.rowColumnName ?? '',
|
|
352
|
+
onChange: (e)=>onChange({
|
|
353
|
+
...value,
|
|
354
|
+
spec: {
|
|
355
|
+
...value.spec,
|
|
356
|
+
rowColumnName: e.target.value || undefined
|
|
357
|
+
}
|
|
358
|
+
}),
|
|
359
|
+
helperText: "Optional display name for the row column (default: row field)"
|
|
360
|
+
}),
|
|
361
|
+
/*#__PURE__*/ _jsx(FormControlLabel, {
|
|
362
|
+
control: /*#__PURE__*/ _jsx(Switch, {
|
|
363
|
+
checked: !!value.spec.disabled,
|
|
364
|
+
onChange: (_, checked)=>onChange({
|
|
365
|
+
...value,
|
|
366
|
+
spec: {
|
|
367
|
+
...value.spec,
|
|
368
|
+
disabled: checked
|
|
369
|
+
}
|
|
370
|
+
})
|
|
371
|
+
}),
|
|
372
|
+
label: "Disabled"
|
|
284
373
|
})
|
|
285
374
|
]
|
|
286
375
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/TransformsEditor/TransformEditor.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport type { StackProps } from '@mui/material';\nimport {\n Autocomplete,\n FormControlLabel,\n MenuItem,\n Stack,\n Switch,\n Typography,\n TextField as MuiTextField,\n} from '@mui/material';\nimport type { ReactElement } from 'react';\n\nimport { TextField } from '../controls';\nimport type {\n JoinByColumnValueTransform,\n MergeColumnsTransform,\n MergeIndexedColumnsTransform,\n MergeSeriesTransform,\n Transform,\n} from '../model';\n\ninterface TransformSpecEditorProps<Spec> {\n value: Spec;\n onChange: (transform: Spec) => void;\n}\n\nfunction JoinByColumnValueTransformEditor({\n value,\n onChange,\n}: TransformSpecEditorProps<JoinByColumnValueTransform>): ReactElement {\n return (\n <Stack direction=\"row\">\n <Autocomplete\n freeSolo\n multiple\n id=\"join-columns\"\n sx={{ width: '100%' }}\n options={[]} // TODO: autofill columns name when query results is available to panel editors\n value={value.spec.columns ?? []}\n renderInput={(params) => <MuiTextField {...params} variant=\"outlined\" label=\"Columns\" required />}\n onChange={(_, columns) => {\n onChange({\n ...value,\n spec: {\n ...value.spec,\n columns: columns,\n },\n });\n }}\n />\n <FormControlLabel\n label=\"Enabled\"\n labelPlacement=\"start\"\n control={\n <Switch\n value={!value.spec.disabled}\n checked={!value.spec.disabled}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, disabled: !e.target.checked },\n })\n }\n />\n }\n />\n </Stack>\n );\n}\n\nfunction MergeColumnsTransformEditor({\n value,\n onChange,\n}: TransformSpecEditorProps<MergeColumnsTransform>): ReactElement {\n return (\n <Stack direction=\"row\" gap={1} alignItems=\"center\">\n <Autocomplete\n freeSolo\n multiple\n id=\"merge-columns-columns\"\n sx={{ width: '100%' }}\n options={[]}\n value={value.spec.columns ?? []}\n renderInput={(params) => <MuiTextField {...params} variant=\"outlined\" label=\"Columns\" required />}\n onChange={(_, columns) => {\n onChange({\n ...value,\n spec: {\n ...value.spec,\n columns: columns,\n },\n });\n }}\n />\n\n <TextField\n id=\"merge-columns-name\"\n variant=\"outlined\"\n label=\"Output Name\"\n value={value.spec.name ?? ''}\n sx={{ width: '100%' }}\n onChange={(name) => {\n onChange({\n ...value,\n spec: {\n ...value.spec,\n name: name,\n },\n });\n }}\n required\n />\n <FormControlLabel\n label=\"Enabled\"\n labelPlacement=\"start\"\n control={\n <Switch\n value={!value.spec.disabled}\n checked={!value.spec.disabled}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, disabled: !e.target.checked },\n })\n }\n />\n }\n />\n </Stack>\n );\n}\n\nfunction MergeIndexedColumnsTransformEditor({\n value,\n onChange,\n}: TransformSpecEditorProps<MergeIndexedColumnsTransform>): ReactElement {\n return (\n <Stack direction=\"row\">\n <TextField\n id=\"merge-indexed-columns\"\n variant=\"outlined\"\n label=\"Column\"\n placeholder=\"Example: 'value' for merging 'value #1', 'value #2' and 'value #...'\"\n value={value.spec.column ?? ''}\n sx={{ width: '100%' }}\n onChange={(column) => {\n onChange({\n ...value,\n spec: { ...value.spec, column: column },\n });\n }}\n required\n />\n <FormControlLabel\n label=\"Enabled\"\n labelPlacement=\"start\"\n control={\n <Switch\n value={!value.spec.disabled}\n checked={!value.spec.disabled}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, disabled: !e.target.checked },\n })\n }\n />\n }\n />\n </Stack>\n );\n}\n\nfunction MergeSeriesTransformEditor({ value, onChange }: TransformSpecEditorProps<MergeSeriesTransform>): ReactElement {\n return (\n <Stack direction=\"row\">\n <FormControlLabel\n label=\"Enabled\"\n labelPlacement=\"start\"\n control={\n <Switch\n value={!value.spec.disabled}\n checked={!value.spec.disabled}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, disabled: !e.target.checked },\n })\n }\n />\n }\n />\n </Stack>\n );\n}\n\nexport interface TransformEditorProps extends Omit<StackProps, 'children' | 'value' | 'onChange'> {\n value: Transform;\n onChange: (transform: Transform) => void;\n}\n\nexport function TransformEditor({ value, onChange, ...props }: TransformEditorProps): ReactElement {\n return (\n <Stack gap={2} sx={{ width: '100%' }} mt={1} {...props}>\n <TextField\n select\n label=\"Kind\"\n value={value.kind}\n onChange={(kind) => onChange({ ...value, kind: kind as unknown as Transform['kind'] } as Transform)}\n >\n <MenuItem value=\"JoinByColumnValue\">\n <Stack>\n <Typography>Join by column value</Typography>\n <Typography variant=\"caption\">Regroup rows with equal cell value in a column</Typography>\n </Stack>\n </MenuItem>\n <MenuItem value=\"MergeColumns\">\n <Stack>\n <Typography>Merge columns</Typography>\n <Typography variant=\"caption\">Multiple columns are merged to one column</Typography>\n </Stack>\n </MenuItem>\n <MenuItem value=\"MergeIndexedColumns\">\n <Stack>\n <Typography>Merge indexed columns</Typography>\n <Typography variant=\"caption\">Indexed columns are merged to one column</Typography>\n </Stack>\n </MenuItem>\n <MenuItem value=\"MergeSeries\">\n <Stack>\n <Typography>Merge series</Typography>\n <Typography variant=\"caption\">Series will be merged by their labels</Typography>\n </Stack>\n </MenuItem>\n </TextField>\n {value.kind === 'JoinByColumnValue' && <JoinByColumnValueTransformEditor value={value} onChange={onChange} />}\n {value.kind === 'MergeColumns' && <MergeColumnsTransformEditor value={value} onChange={onChange} />}\n {value.kind === 'MergeIndexedColumns' && <MergeIndexedColumnsTransformEditor value={value} onChange={onChange} />}\n {value.kind === 'MergeSeries' && <MergeSeriesTransformEditor value={value} onChange={onChange} />}\n </Stack>\n );\n}\n"],"names":["Autocomplete","FormControlLabel","MenuItem","Stack","Switch","Typography","TextField","MuiTextField","JoinByColumnValueTransformEditor","value","onChange","direction","freeSolo","multiple","id","sx","width","options","spec","columns","renderInput","params","variant","label","required","_","labelPlacement","control","disabled","checked","e","target","MergeColumnsTransformEditor","gap","alignItems","name","MergeIndexedColumnsTransformEditor","placeholder","column","MergeSeriesTransformEditor","TransformEditor","props","mt","select","kind"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/TransformsEditor/TransformEditor.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport type { StackProps } from '@mui/material';\nimport {\n Autocomplete,\n FormControlLabel,\n MenuItem,\n Stack,\n Switch,\n Typography,\n TextField as MuiTextField,\n} from '@mui/material';\nimport type { ReactElement } from 'react';\n\nimport { TextField } from '../controls';\nimport type {\n JoinByColumnValueTransform,\n MergeColumnsTransform,\n MergeIndexedColumnsTransform,\n MergeSeriesTransform,\n PivotByLabelTransform,\n Transform,\n} from '../model';\n\ninterface TransformSpecEditorProps<Spec> {\n value: Spec;\n onChange: (transform: Spec) => void;\n}\n\nfunction JoinByColumnValueTransformEditor({\n value,\n onChange,\n}: TransformSpecEditorProps<JoinByColumnValueTransform>): ReactElement {\n return (\n <Stack direction=\"row\">\n <Autocomplete\n freeSolo\n multiple\n id=\"join-columns\"\n sx={{ width: '100%' }}\n options={[]} // TODO: autofill columns name when query results is available to panel editors\n value={value.spec.columns ?? []}\n renderInput={(params) => <MuiTextField {...params} variant=\"outlined\" label=\"Columns\" required />}\n onChange={(_, columns) => {\n onChange({\n ...value,\n spec: {\n ...value.spec,\n columns: columns,\n },\n });\n }}\n />\n <FormControlLabel\n label=\"Enabled\"\n labelPlacement=\"start\"\n control={\n <Switch\n value={!value.spec.disabled}\n checked={!value.spec.disabled}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, disabled: !e.target.checked },\n })\n }\n />\n }\n />\n </Stack>\n );\n}\n\nfunction MergeColumnsTransformEditor({\n value,\n onChange,\n}: TransformSpecEditorProps<MergeColumnsTransform>): ReactElement {\n return (\n <Stack direction=\"row\" gap={1} alignItems=\"center\">\n <Autocomplete\n freeSolo\n multiple\n id=\"merge-columns-columns\"\n sx={{ width: '100%' }}\n options={[]}\n value={value.spec.columns ?? []}\n renderInput={(params) => <MuiTextField {...params} variant=\"outlined\" label=\"Columns\" required />}\n onChange={(_, columns) => {\n onChange({\n ...value,\n spec: {\n ...value.spec,\n columns: columns,\n },\n });\n }}\n />\n\n <TextField\n id=\"merge-columns-name\"\n variant=\"outlined\"\n label=\"Output Name\"\n value={value.spec.name ?? ''}\n sx={{ width: '100%' }}\n onChange={(name) => {\n onChange({\n ...value,\n spec: {\n ...value.spec,\n name: name,\n },\n });\n }}\n required\n />\n <FormControlLabel\n label=\"Enabled\"\n labelPlacement=\"start\"\n control={\n <Switch\n value={!value.spec.disabled}\n checked={!value.spec.disabled}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, disabled: !e.target.checked },\n })\n }\n />\n }\n />\n </Stack>\n );\n}\n\nfunction MergeIndexedColumnsTransformEditor({\n value,\n onChange,\n}: TransformSpecEditorProps<MergeIndexedColumnsTransform>): ReactElement {\n return (\n <Stack direction=\"row\">\n <TextField\n id=\"merge-indexed-columns\"\n variant=\"outlined\"\n label=\"Column\"\n placeholder=\"Example: 'value' for merging 'value #1', 'value #2' and 'value #...'\"\n value={value.spec.column ?? ''}\n sx={{ width: '100%' }}\n onChange={(column) => {\n onChange({\n ...value,\n spec: { ...value.spec, column: column },\n });\n }}\n required\n />\n <FormControlLabel\n label=\"Enabled\"\n labelPlacement=\"start\"\n control={\n <Switch\n value={!value.spec.disabled}\n checked={!value.spec.disabled}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, disabled: !e.target.checked },\n })\n }\n />\n }\n />\n </Stack>\n );\n}\n\nfunction MergeSeriesTransformEditor({ value, onChange }: TransformSpecEditorProps<MergeSeriesTransform>): ReactElement {\n return (\n <Stack direction=\"row\">\n <FormControlLabel\n label=\"Enabled\"\n labelPlacement=\"start\"\n control={\n <Switch\n value={!value.spec.disabled}\n checked={!value.spec.disabled}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, disabled: !e.target.checked },\n })\n }\n />\n }\n />\n </Stack>\n );\n}\n\nexport interface TransformEditorProps extends Omit<StackProps, 'children' | 'value' | 'onChange'> {\n value: Transform;\n onChange: (transform: Transform) => void;\n}\n\nexport function TransformEditor({ value, onChange, ...props }: TransformEditorProps): ReactElement {\n return (\n <Stack gap={2} sx={{ width: '100%' }} mt={1} {...props}>\n <TextField\n select\n label=\"Kind\"\n value={value.kind}\n onChange={(kind) => onChange({ ...value, kind: kind as unknown as Transform['kind'] } as Transform)}\n >\n <MenuItem value=\"JoinByColumnValue\">\n <Stack>\n <Typography>Join by column value</Typography>\n <Typography variant=\"caption\">Regroup rows with equal cell value in a column</Typography>\n </Stack>\n </MenuItem>\n <MenuItem value=\"MergeColumns\">\n <Stack>\n <Typography>Merge columns</Typography>\n <Typography variant=\"caption\">Multiple columns are merged to one column</Typography>\n </Stack>\n </MenuItem>\n <MenuItem value=\"MergeIndexedColumns\">\n <Stack>\n <Typography>Merge indexed columns</Typography>\n <Typography variant=\"caption\">Indexed columns are merged to one column</Typography>\n </Stack>\n </MenuItem>\n <MenuItem value=\"MergeSeries\">\n <Stack>\n <Typography>Merge series</Typography>\n <Typography variant=\"caption\">Series will be merged by their labels</Typography>\n </Stack>\n </MenuItem>\n <MenuItem value=\"PivotByLabel\">\n <Stack>\n <Typography>Pivot by label</Typography>\n <Typography variant=\"caption\">Time × label matrix (rows = time, columns = label values)</Typography>\n </Stack>\n </MenuItem>\n </TextField>\n {value.kind === 'JoinByColumnValue' && <JoinByColumnValueTransformEditor value={value} onChange={onChange} />}\n {value.kind === 'MergeColumns' && <MergeColumnsTransformEditor value={value} onChange={onChange} />}\n {value.kind === 'MergeIndexedColumns' && <MergeIndexedColumnsTransformEditor value={value} onChange={onChange} />}\n {value.kind === 'MergeSeries' && <MergeSeriesTransformEditor value={value} onChange={onChange} />}\n {value.kind === 'PivotByLabel' && <PivotByLabelTransformEditor value={value} onChange={onChange} />}\n </Stack>\n );\n}\n\nfunction PivotByLabelTransformEditor({\n value,\n onChange,\n}: TransformSpecEditorProps<PivotByLabelTransform>): ReactElement {\n return (\n <Stack gap={2}>\n <MuiTextField\n label=\"Column label\"\n fullWidth\n value={value.spec.columnLabel ?? ''}\n onChange={(e) => onChange({ ...value, spec: { ...value.spec, columnLabel: e.target.value } })}\n helperText=\"Label that becomes dynamic column headers (e.g. farm_short)\"\n />\n <MuiTextField\n label=\"Row field\"\n fullWidth\n value={value.spec.rowField ?? 'timestamp'}\n onChange={(e) => onChange({ ...value, spec: { ...value.spec, rowField: e.target.value } })}\n helperText=\"Field used for row identity (default: timestamp)\"\n />\n <MuiTextField\n label=\"Value field\"\n fullWidth\n value={value.spec.valueField ?? 'value'}\n onChange={(e) => onChange({ ...value, spec: { ...value.spec, valueField: e.target.value } })}\n />\n <MuiTextField\n label=\"Row column name\"\n fullWidth\n value={value.spec.rowColumnName ?? ''}\n onChange={(e) =>\n onChange({\n ...value,\n spec: { ...value.spec, rowColumnName: e.target.value || undefined },\n })\n }\n helperText=\"Optional display name for the row column (default: row field)\"\n />\n <FormControlLabel\n control={\n <Switch\n checked={!!value.spec.disabled}\n onChange={(_, checked) => onChange({ ...value, spec: { ...value.spec, disabled: checked } })}\n />\n }\n label=\"Disabled\"\n />\n </Stack>\n );\n}\n"],"names":["Autocomplete","FormControlLabel","MenuItem","Stack","Switch","Typography","TextField","MuiTextField","JoinByColumnValueTransformEditor","value","onChange","direction","freeSolo","multiple","id","sx","width","options","spec","columns","renderInput","params","variant","label","required","_","labelPlacement","control","disabled","checked","e","target","MergeColumnsTransformEditor","gap","alignItems","name","MergeIndexedColumnsTransformEditor","placeholder","column","MergeSeriesTransformEditor","TransformEditor","props","mt","select","kind","PivotByLabelTransformEditor","fullWidth","columnLabel","helperText","rowField","valueField","rowColumnName","undefined"],"mappings":"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"}
|
|
@@ -32,12 +32,33 @@ export interface MergeSeriesTransform {
|
|
|
32
32
|
kind: 'MergeSeries';
|
|
33
33
|
spec: TransformCommonSpec;
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Pivot multi-series table rows into a time × label matrix
|
|
37
|
+
* (Grafana groupingToMatrix parity).
|
|
38
|
+
*
|
|
39
|
+
* Example: columnLabel=farm_short, rowField=timestamp
|
|
40
|
+
* → one row per timestamp, one column per farm_short value.
|
|
41
|
+
*/
|
|
42
|
+
export interface PivotByLabelTransform {
|
|
43
|
+
kind: 'PivotByLabel';
|
|
44
|
+
spec: TransformCommonSpec & {
|
|
45
|
+
/** Label/column that becomes dynamic column headers (e.g. farm_short). */
|
|
46
|
+
columnLabel: string;
|
|
47
|
+
/** Field for row identity (default: timestamp). */
|
|
48
|
+
rowField?: string;
|
|
49
|
+
/** Value field name (default: value). */
|
|
50
|
+
valueField?: string;
|
|
51
|
+
/** Name of the row column after pivot (default: rowField). */
|
|
52
|
+
rowColumnName?: string;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export type Transform = JoinByColumnValueTransform | MergeColumnsTransform | MergeIndexedColumnsTransform | MergeSeriesTransform | ExtractColumnFieldsTransform | PivotByLabelTransform;
|
|
36
56
|
export declare const TRANSFORM_TEXT: {
|
|
37
57
|
JoinByColumnValue: string;
|
|
38
58
|
MergeColumns: string;
|
|
39
59
|
MergeIndexedColumns: string;
|
|
40
60
|
MergeSeries: string;
|
|
41
61
|
ExtractColumnFields: string;
|
|
62
|
+
PivotByLabel: string;
|
|
42
63
|
};
|
|
43
64
|
//# sourceMappingURL=transforms.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transforms.d.ts","sourceRoot":"","sources":["../../src/model/transforms.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,IAAI,EAAE,mBAAmB,GAAG;QAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,qBAAqB,CAAC;IAC5B,IAAI,EAAE,mBAAmB,GAAG;QAC1B,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,kBAAkB,GAAG,eAAe,CAAC;QAChE,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,mBAAmB,GAAG;QAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,qBAAqB,CAAC;IAC5B,IAAI,EAAE,mBAAmB,GAAG;QAC1B,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,mBAAmB,CAAC;CAC3B;AAED,MAAM,MAAM,SAAS,GACjB,0BAA0B,GAC1B,qBAAqB,GACrB,4BAA4B,GAC5B,oBAAoB,GACpB,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"transforms.d.ts","sourceRoot":"","sources":["../../src/model/transforms.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,IAAI,EAAE,mBAAmB,GAAG;QAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,qBAAqB,CAAC;IAC5B,IAAI,EAAE,mBAAmB,GAAG;QAC1B,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,kBAAkB,GAAG,eAAe,CAAC;QAChE,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,mBAAmB,GAAG;QAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,qBAAqB,CAAC;IAC5B,IAAI,EAAE,mBAAmB,GAAG;QAC1B,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,mBAAmB,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,mBAAmB,GAAG;QAC1B,0EAA0E;QAC1E,WAAW,EAAE,MAAM,CAAC;QACpB,mDAAmD;QACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,yCAAyC;QACzC,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,8DAA8D;QAC9D,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED,MAAM,MAAM,SAAS,GACjB,0BAA0B,GAC1B,qBAAqB,GACrB,4BAA4B,GAC5B,oBAAoB,GACpB,4BAA4B,GAC5B,qBAAqB,CAAC;AAG1B,eAAO,MAAM,cAAc;IACzB,iBAAiB;IACjB,YAAY;IACZ,mBAAmB;IACnB,WAAW;IACX,mBAAmB;IACnB,YAAY;CACb,CAAC"}
|
package/dist/model/transforms.js
CHANGED
|
@@ -16,7 +16,8 @@ export const TRANSFORM_TEXT = {
|
|
|
16
16
|
MergeColumns: 'Merge columns',
|
|
17
17
|
MergeIndexedColumns: 'Merge indexed columns',
|
|
18
18
|
MergeSeries: 'Merge series',
|
|
19
|
-
ExtractColumnFields: 'Extract column fields'
|
|
19
|
+
ExtractColumnFields: 'Extract column fields',
|
|
20
|
+
PivotByLabel: 'Pivot by label'
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
//# sourceMappingURL=transforms.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/model/transforms.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 interface TransformCommonSpec {\n disabled?: boolean;\n}\n\nexport interface JoinByColumnValueTransform {\n kind: 'JoinByColumnValue';\n spec: TransformCommonSpec & {\n columns: string[];\n };\n}\n\nexport interface ExtractColumnFieldsTransform {\n kind: 'ExtractColumnFields';\n spec: TransformCommonSpec & {\n column: string;\n format: 'JSON' | 'Regex' | 'SplitByDelimiter' | 'KeyValuePairs';\n matcher?: string;\n };\n}\n\nexport interface MergeColumnsTransform {\n kind: 'MergeColumns';\n spec: TransformCommonSpec & {\n columns: string[];\n name: string;\n };\n}\n\nexport interface MergeIndexedColumnsTransform {\n kind: 'MergeIndexedColumns';\n spec: TransformCommonSpec & {\n column: string;\n };\n}\n\nexport interface MergeSeriesTransform {\n kind: 'MergeSeries';\n spec: TransformCommonSpec;\n}\n\nexport type Transform =\n | JoinByColumnValueTransform\n | MergeColumnsTransform\n | MergeIndexedColumnsTransform\n | MergeSeriesTransform\n | ExtractColumnFieldsTransform;\n\n// Can be moved somewhere else\nexport const TRANSFORM_TEXT = {\n JoinByColumnValue: 'Join by column value',\n MergeColumns: 'Merge columns',\n MergeIndexedColumns: 'Merge indexed columns',\n MergeSeries: 'Merge series',\n ExtractColumnFields: 'Extract column fields',\n};\n"],"names":["TRANSFORM_TEXT","JoinByColumnValue","MergeColumns","MergeIndexedColumns","MergeSeries","ExtractColumnFields"],"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;
|
|
1
|
+
{"version":3,"sources":["../../src/model/transforms.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 interface TransformCommonSpec {\n disabled?: boolean;\n}\n\nexport interface JoinByColumnValueTransform {\n kind: 'JoinByColumnValue';\n spec: TransformCommonSpec & {\n columns: string[];\n };\n}\n\nexport interface ExtractColumnFieldsTransform {\n kind: 'ExtractColumnFields';\n spec: TransformCommonSpec & {\n column: string;\n format: 'JSON' | 'Regex' | 'SplitByDelimiter' | 'KeyValuePairs';\n matcher?: string;\n };\n}\n\nexport interface MergeColumnsTransform {\n kind: 'MergeColumns';\n spec: TransformCommonSpec & {\n columns: string[];\n name: string;\n };\n}\n\nexport interface MergeIndexedColumnsTransform {\n kind: 'MergeIndexedColumns';\n spec: TransformCommonSpec & {\n column: string;\n };\n}\n\nexport interface MergeSeriesTransform {\n kind: 'MergeSeries';\n spec: TransformCommonSpec;\n}\n\n/**\n * Pivot multi-series table rows into a time × label matrix\n * (Grafana groupingToMatrix parity).\n *\n * Example: columnLabel=farm_short, rowField=timestamp\n * → one row per timestamp, one column per farm_short value.\n */\nexport interface PivotByLabelTransform {\n kind: 'PivotByLabel';\n spec: TransformCommonSpec & {\n /** Label/column that becomes dynamic column headers (e.g. farm_short). */\n columnLabel: string;\n /** Field for row identity (default: timestamp). */\n rowField?: string;\n /** Value field name (default: value). */\n valueField?: string;\n /** Name of the row column after pivot (default: rowField). */\n rowColumnName?: string;\n };\n}\n\nexport type Transform =\n | JoinByColumnValueTransform\n | MergeColumnsTransform\n | MergeIndexedColumnsTransform\n | MergeSeriesTransform\n | ExtractColumnFieldsTransform\n | PivotByLabelTransform;\n\n// Can be moved somewhere else\nexport const TRANSFORM_TEXT = {\n JoinByColumnValue: 'Join by column value',\n MergeColumns: 'Merge columns',\n MergeIndexedColumns: 'Merge indexed columns',\n MergeSeries: 'Merge series',\n ExtractColumnFields: 'Extract column fields',\n PivotByLabel: 'Pivot by label',\n};\n"],"names":["TRANSFORM_TEXT","JoinByColumnValue","MergeColumns","MergeIndexedColumns","MergeSeries","ExtractColumnFields","PivotByLabel"],"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;AAuEjC,8BAA8B;AAC9B,OAAO,MAAMA,iBAAiB;IAC5BC,mBAAmB;IACnBC,cAAc;IACdC,qBAAqB;IACrBC,aAAa;IACbC,qBAAqB;IACrBC,cAAc;AAChB,EAAE"}
|
|
@@ -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,
|
|
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":"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;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,SAASA,mBACdC,IAAoC,EACpCC,OAAiB;IAEjB,qDAAqD;IACrD,IAAIA,QAAQC,MAAM,KAAK,GAAG;QACxB,OAAOF;IACT;IAEA,MAAMG,YAAwD,CAAC;IAE/D,KAAK,MAAMC,OAAOJ,KAAM;QACtB,MAAMK,UAAUC,OAAOC,IAAI,CAACH,KACzBI,MAAM,CAAC,CAACC,IAAMR,QAAQS,QAAQ,CAACD,IAC/BE,GAAG,CAAC,CAACF,IAAML,GAAG,CAACK,EAAE,EACjBG,IAAI,CAAC;QAER,MAAMC,iBAAiBV,SAAS,CAACE,QAAQ;QACzC,IAAIQ,gBAAgB;YAClBV,SAAS,CAACE,QAAQ,GAAG;gBAAE,GAAGQ,cAAc;gBAAE,GAAGT,GAAG;YAAC;QACnD,OAAO;YACLD,SAAS,CAACE,QAAQ,GAAG;gBAAE,GAAGD,GAAG;YAAC;QAChC;IACF;IACA,OAAOE,OAAOQ,MAAM,CAACX;AACvB;AAEA;;;;;;;;;;;;;;;;;;;;;;;CAuBC,GACD,OAAO,SAASY,2BACdf,IAAoC,EACpCgB,eAAyB,EACzBC,UAAkB;IAElB,MAAMC,SAAyC,EAAE;IAEjD,KAAK,MAAMd,OAAOJ,KAAM;QACtB,MAAMC,UAAUK,OAAOC,IAAI,CAACH,KAAKI,MAAM,CAAC,CAACC,IAAMO,gBAAgBN,QAAQ,CAACD;QAExE,MAAMU,uBAAgD,CAAC;QAEvD,KAAK,MAAMC,UAAUnB,QAAS;YAC5BkB,oBAAoB,CAACC,OAAO,GAAGhB,GAAG,CAACgB,OAAO;YAC1C,OAAOhB,GAAG,CAACgB,OAAO;QACpB;QAEA,KAAK,MAAMA,UAAUnB,QAAS;YAC5BiB,OAAOG,IAAI,CAAC;gBAAE,GAAGjB,GAAG;gBAAE,CAACa,WAAW,EAAEE,oBAAoB,CAACC,OAAO;YAAC;QACnE;QAEA,IAAInB,QAAQC,MAAM,KAAK,GAAG;YACxBgB,OAAOG,IAAI,CAACjB;QACd;IACF;IAEA,OAAOc;AACT;AAEA;;;;;;;;;;;;;;;;;;;;;;;CAuBC,GACD,OAAO,SAASI,kCACdtB,IAAoC,EACpCoB,MAAc;IAEd,MAAMF,SAAyC,EAAE;IAEjD,KAAK,MAAMK,SAASvB,KAAM;QACxB,MAAMwB,iBAAiBlB,OAAOC,IAAI,CAACgB,OAAOf,MAAM,CAAC,CAACC,IAChD,IAAIgB,OAAO,QAAQL,SAAS,cAAcA,SAAS,OAAOM,IAAI,CAACjB;QAEjE,MAAMkB,sBAA+C,CAAC;QAEtD,KAAK,MAAMC,iBAAiBJ,eAAgB;YAC1CG,mBAAmB,CAACC,cAAc,GAAGL,KAAK,CAACK,cAAc;YACzD,OAAOL,KAAK,CAACK,cAAc;QAC7B;QAEA,KAAK,MAAMA,iBAAiBJ,eAAgB;YAC1CN,OAAOG,IAAI,CAAC;gBAAE,GAAGE,KAAK;gBAAE,CAACH,OAAO,EAAEO,mBAAmB,CAACC,cAAc;YAAC;QACvE;QAEA,IAAIJ,eAAetB,MAAM,KAAK,GAAG;YAC/BgB,OAAOG,IAAI,CAACE;QACd;IACF;IAEA,OAAOL;AACT;AAEA;;;;;;;;;;;;;;;;CAgBC,GACD,OAAO,SAASW,0BAA0B7B,IAAoC;IAC5E,IAAIkB,SAAyC;WAAIlB;KAAK;IAEtD,MAAM8B,eAAeC,MAAMC,IAAI,CAC7B,IAAIC,IACFjC,KACGkC,OAAO,CAAC5B,OAAOC,IAAI,EACnBI,GAAG,CAAC,CAACwB,QAAUA,MAAMC,OAAO,CAAC,SAAS,KACtC5B,MAAM,CAAC,CAAC2B,QAAUA,UAAU;IAInC,KAAK,MAAMA,SAASL,aAAc;QAChCZ,SAASI,kCAAkCJ,QAAQiB;IACrD;IAEAjB,SAASnB,mBAAmBmB,QAAQY;IAEpC,OAAOZ;AACT;AAEA,gEAAgE,GAChE,SAASmB,SAASC,CAAqB,EAAEC,QAAgB;IACvD,OAAOD,GAAGE,UAAUD;AACtB;AAEA,oEAAoE,GACpE,SAASE,gBAAgBrC,GAA4B,EAAEsC,IAAY;IACjE,IAAIpC,OAAOqC,MAAM,CAACvC,KAAKsC,OAAO,OAAOA;IACrC,OAAOpC,OAAOC,IAAI,CAACH,KAAKwC,IAAI,CAAC,CAACnC,IAAMA,MAAMiC,QAAQjC,EAAEoC,UAAU,CAACH,OAAO,SAASjC,EAAEoC,UAAU,CAACH,OAAO;AACrG;AAEA;;;CAGC,GACD,OAAO,SAASI,2BACd9C,IAAoC,EACpC+C,WAAmB,EACnBC,WAAW,WAAW,EACtBC,aAAa,OAAO,EACpBC,aAAsB;IAEtB,IAAI,CAACH,eAAe/C,KAAKE,MAAM,KAAK,GAAG;QACrC,OAAOF;IACT;IAEA,MAAMmD,eAAed,SAASW,UAAU;IACxC,MAAMI,iBAAiBf,SAASY,YAAY;IAC5C,MAAMI,SAAShB,SAASa,eAAeC;IAEvC,MAAMG,WAAW,IAAIrB;IACrB,MAAMsB,SAAS,IAAIC;IAEnB,KAAK,MAAMpD,OAAOJ,KAAM;QACtB,MAAMyD,aAAahB,gBAAgBrC,KAAK+C;QACxC,MAAMO,eAAejB,gBAAgBrC,KAAK2C;QAC1C,MAAMY,eAAelB,gBAAgBrC,KAAKgD;QAC1C,IAAIK,eAAeG,aAAaF,iBAAiBE,WAAW;YAC1D;QACF;QAEA,MAAMC,SAASzD,GAAG,CAACqD,WAAW;QAC9B,MAAMtB,QAAQ/B,GAAG,CAACsD,aAAa;QAC/B,IAAIG,WAAWD,aAAaC,WAAW,QAAQ1B,UAAUyB,aAAazB,UAAU,MAAM;YACpF;QACF;QAEA,8EAA8E;QAC9E,sFAAsF;QACtF,IAAI2B,WAAWC,OAAO5B,OAAOK,IAAI;QACjC,IAAI,CAACsB,UAAU;YACb;QACF;QACA,IAAIA,aAAaT,QAAQ;YACvBS,WAAW,GAAGA,SAAS,QAAQ,CAAC;QAClC;QACAR,SAASU,GAAG,CAACF;QACb,MAAMG,UAAUF,OAAOF;QAEvB,IAAIK,MAAMX,OAAOY,GAAG,CAACF;QACrB,IAAI,CAACC,KAAK;YACRA,MAAM;gBAAE,CAACb,OAAO,EAAEQ;YAAO;YACzBN,OAAOa,GAAG,CAACH,SAASC;QACtB;QACA,IAAIP,iBAAiBC,WAAW;YAC9BM,GAAG,CAACJ,SAAS,GAAG1D,GAAG,CAACuD,aAAa;QACnC;IACF;IAEA,8EAA8E;IAC9E,MAAMU,SAAS;WAAIf;KAAS;IAC5Be,OAAOC,IAAI,CAAC,CAACC,GAAGC,IAAMD,EAAEE,aAAa,CAACD;IACtC,MAAME,UAAU;WAAInB,OAAOmB,OAAO;KAAG;IACrCA,QAAQJ,IAAI,CAAC,CAACC,GAAGC;QACf,MAAMG,KAAKJ,CAAC,CAAC,EAAE,CAAClB,OAAO;QACvB,MAAMuB,KAAKJ,CAAC,CAAC,EAAE,CAACnB,OAAO;QACvB,IAAI,OAAOsB,OAAO,YAAY,OAAOC,OAAO,UAAU;YACpD,OAAOA,KAAKD;QACd;QACA,OAAOZ,OAAOa,IAAIH,aAAa,CAACV,OAAOY;IACzC;IACA,OAAOD,QAAQ/D,GAAG,CAAC,CAAC,GAAGP,IAAI;QACzB,MAAMyE,UAAmC;YAAE,CAACxB,OAAO,EAAEjD,GAAG,CAACiD,OAAO;QAAC;QACjE,KAAK,MAAMyB,OAAOT,OAAQ;YACxB,IAAI/D,OAAOqC,MAAM,CAACvC,KAAK0E,MAAM;gBAC3BD,OAAO,CAACC,IAAI,GAAG1E,GAAG,CAAC0E,IAAI;YACzB;QACF;QACA,OAAOD;IACT;AACF;AAEA;;CAEC,GACD,OAAO,SAASE,cACd/E,IAAoC,EACpCgF,UAAuB;IAEvB,IAAI9D,SAAyClB;IAC7C,+EAA+E;IAC/E,kFAAkF;IAClF,2DAA2D;IAC3D,IAAIiF;IAEJ,mCAAmC;IACnC,KAAK,MAAMC,aAAaF,cAAc,EAAE,CAAE;QACxC,IAAIE,UAAUC,IAAI,CAACC,QAAQ,EAAE;QAC7BH,kBAAkBC,UAAUG,IAAI;QAEhC,OAAQH,UAAUG,IAAI;YACpB,KAAK;gBAAqB;oBACxB,IAAIH,UAAUC,IAAI,CAAClF,OAAO,IAAIiF,UAAUC,IAAI,CAAClF,OAAO,CAACC,MAAM,GAAG,GAAG;wBAC/DgB,SAASnB,mBAAmBmB,QAAQgE,UAAUC,IAAI,CAAClF,OAAO;oBAC5D;oBACA;gBACF;YACA,KAAK;gBAAuB;oBAC1B,IAAIiF,UAAUC,IAAI,CAAC/D,MAAM,EAAE;wBACzBF,SAASI,kCAAkCJ,QAAQgE,UAAUC,IAAI,CAAC/D,MAAM;oBAC1E;oBACA;gBACF;YACA,KAAK;gBAAgB;oBACnB,IAAI8D,UAAUC,IAAI,CAAClF,OAAO,IAAIiF,UAAUC,IAAI,CAAClF,OAAO,CAACC,MAAM,GAAG,KAAKgF,UAAUC,IAAI,CAACG,IAAI,EAAE;wBACtFpE,SAASH,2BAA2BG,QAAQgE,UAAUC,IAAI,CAAClF,OAAO,EAAEiF,UAAUC,IAAI,CAACG,IAAI;oBACzF;oBACA;gBACF;YACA,KAAK;gBAAe;oBAClBpE,SAASW,0BAA0BX;oBACnC;gBACF;YACA,KAAK;gBAAgB;oBACnB,IAAIgE,UAAUC,IAAI,CAACpC,WAAW,EAAE;wBAC9B7B,SAAS4B,2BACP5B,QACAgE,UAAUC,IAAI,CAACpC,WAAW,EAC1BV,SAAS6C,UAAUC,IAAI,CAACnC,QAAQ,EAAE,cAClCX,SAAS6C,UAAUC,IAAI,CAAClC,UAAU,EAAE,UACpCiC,UAAUC,IAAI,CAACjC,aAAa;oBAEhC;oBACA;gBACF;QACF;IACF;IAEA,IAAI+B,oBAAoB,gBAAgB;QACtC,OAAO/D;IACT;IAEA,sCAAsC;IACtCA,SAASA,OAAOP,GAAG,CAAC,CAACP;QACnB,OAAOE,OAAOC,IAAI,CAACH,KAChBmF,QAAQ,GACRC,MAAM,CAAC,CAACC,KAA8BC;YACrCD,GAAG,CAACC,IAAI,GAAGtF,GAAG,CAACsF,IAAI;YACnB,OAAOD;QACT,GAAG,CAAC;IACR;IACA,OAAOvE;AACT"}
|
|
@@ -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":"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;AAsCjC;;CAEC,GACD,OAAO,IAAA,AAAKA,6CAAAA;;;;;;;;;;;;;;;;;WAAAA;MAiBX;AAED,SAASC,eAAeC,GAAuB;IAC7C,IAAI,CAACA,KAAK,OAAOC;IAEjB,MAAMC,WAAWF,IAAIG,WAAW;IAChC,OAAOC,OAAOC,MAAM,CAACP,qBAAqBQ,IAAI,CAAC,CAACC,SAAWA,WAAWL,aAAaD;AACrF;AAEA;;CAEC,GACD,OAAO,SAASO,YAAYH,MAAgB,EAAEI,IAAY,EAAEF,MAA2B;IACrF,OAAQA;QACN;QACA;YACE,OAAOF,OAAOK,IAAI,CAAC;QACrB;YAAsC;gBACpC,MAAM,CAACC,OAAO,GAAGC,KAAK,GAAGP;gBACzB,OAAO,GAAG;oBAACM;uBAAUC,KAAKC,GAAG,CAAC,CAACC,IAAM,GAAGL,KAAK,CAAC,EAAEK,GAAG;iBAAE,CAACJ,IAAI,CAAC,MAAM;YACnE;QACA;YACE,OAAOL,OAAOQ,GAAG,CAAC,CAACC,IAAM,CAAC,CAAC,EAAEA,EAAE,CAAC,CAAC,EAAEJ,IAAI,CAAC;QAC1C;YACE,OAAO,CAAC,CAAC,EAAEL,OAAOK,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC;YAA+B;gBAC7B,+EAA+E;gBAC/E,gEAAgE;gBAChE,MAAMK,eAAeV,OAAOQ,GAAG,CAAC,CAACC;oBAC/B,IAAI;wBACF,OAAOE,KAAKC,KAAK,CAACH;oBACpB,EAAE,OAAM;wBACN,OAAOA;oBACT;gBACF;gBAEA,OAAOE,KAAKE,SAAS,CAACH;YACxB;QACA;YACE,OAAO,CAAC,CAAC,EAAEV,OAAOQ,GAAG,CAAC,CAACC,IAAM,CAAC,CAAC,EAAEA,EAAE,CAAC,CAAC,EAAEJ,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxD;YACE,OAAOS,mBAAmBd,OAAOK,IAAI,CAAC;QACxC;YACE,OAAOL,OAAOK,IAAI,CAAC;QACrB;YAAgC;gBAC9B,MAAMU,eAAef,OAAOQ,GAAG,CAAC,CAACC,IAAMA,EAAEO,OAAO,CAAC,yBAAyB;gBAC1E,OAAO,CAAC,CAAC,EAAED,aAAaV,IAAI,CAAC,KAAK,CAAC,CAAC;YACtC;QACA;YAAwC;gBACtC,MAAMU,eAAef,OAAOQ,GAAG,CAAC,CAACC,IAAMA,EAAEO,OAAO,CAAC,yBAAyB;gBAC1E,OAAO,CAAC,CAAC,EAAED,aAAaV,IAAI,CAAC,KAAK,CAAC,CAAC;YACtC;QACA;YACE,OAAOL,OAAOQ,GAAG,CAAC,CAACC,IAAM,CAAC,CAAC,EAAEA,EAAE,CAAC,CAAC,EAAEJ,IAAI,CAAC;QAC1C;YACE,OAAOL,OAAOQ,GAAG,CAAC,CAACC,IAAM,CAAC,CAAC,EAAEA,EAAEO,OAAO,CAAC,MAAM,MAAM,CAAC,CAAC,EAAEX,IAAI,CAAC;QAC9D;YACE,OAAOL,OAAOK,IAAI,CAAC;QACrB;YACE,OAAOL,OAAOQ,GAAG,CAAC,CAACC,IAAM,GAAGL,KAAK,CAAC,EAAEU,mBAAmBL,IAAI,EAAEJ,IAAI,CAAC;QACpE;QACA;YACE,OAAO,CAAC,CAAC,EAAEL,OAAOK,IAAI,CAAC,KAAK,CAAC,CAAC;IAClC;AACF;AAEA;;CAEC,GACD,OAAO,SAASY,gBACdC,IAAY,EACZC,OAAe,EACfC,aAA4B,EAC5BC,SAA+B;IAE/B,MAAMC,iBAAiB,MAAMH;IAC7B,MAAMI,4BAA4B,OAAOJ,UAAWE,CAAAA,YAAY,MAAMA,YAAY,EAAC,IAAK;IAExF,IAAIG,gBAAgB;IACpB,IAAIC,MAAMC,OAAO,CAACN,gBAAgB;QAChCI,gBAAgBrB,YAAYiB,eAAeD,SAASE;IACtD;IACA,IAAI,OAAOD,kBAAkB,UAAU;QACrCI,gBAAgBrB,YAAY;YAACiB;SAAc,EAAED,SAASE;IACxD;IACAH,OAAOA,KAAKS,UAAU,CAACL,gBAAgBE;IACvC,OAAON,KAAKS,UAAU,CAACJ,2BAA2BC;AACpD;AAEA,mFAAmF;AACnF,qDAAqD;AACrD,gJAAgJ;AAChJ,0KAA0K;AAC1K,2GAA2G;AAE3G,MAAMI,iBAAiB;AAEvB;;CAEC,GACD,OAAO,SAASC,eAAeX,IAAY;IACzC,MAAMY,UAAU,IAAIC;IACpB,IAAIC;IAEJ,MAAO,AAACA,CAAAA,QAAQJ,eAAeK,IAAI,CAACf,KAAI,MAAO,KAAM;QACnD,IAAIc,OAAO;YACT,IAAIA,KAAK,CAAC,EAAE,EAAE;gBACZ,WAAW;gBACXF,QAAQI,GAAG,CAACF,KAAK,CAAC,EAAE;YACtB,OAAO,IAAIA,KAAK,CAAC,EAAE,EAAE;gBACnB,aAAa;gBACbF,QAAQI,GAAG,CAACF,KAAK,CAAC,EAAE;YACtB;QACF;IACF;IACA,wBAAwB;IACxB,OAAOP,MAAMU,IAAI,CAACL,QAAQ9B,MAAM;AAClC;AAEA;;CAEC,GACD,OAAO,SAASoC,wBAAwBlB,IAAY;IAClD,MAAMY,UAAU,IAAIO;IACpB,IAAIL;IAEJ,MAAO,AAACA,CAAAA,QAAQJ,eAAeK,IAAI,CAACf,KAAI,MAAO,KAAM;QACnD,IAAIc,OAAO;YACT,IAAI9B,SAASN;YACb,IAAIoC,KAAK,CAAC,EAAE,EAAE;gBACZ9B,SAAS8B,KAAK,CAAC,EAAE;YACnB;YACA,IAAIA,KAAK,CAAC,EAAE,EAAE;gBACZ,WAAW;gBACXF,QAAQQ,GAAG,CAACN,KAAK,CAAC,EAAE,EAAEtC,eAAeQ;YACvC,OAAO,IAAI8B,KAAK,CAAC,EAAE,EAAE;gBACnB,aAAa;gBACbF,QAAQQ,GAAG,CAACN,KAAK,CAAC,EAAE,EAAEtC,eAAeQ;YACvC;QACF;IACF;IACA,OAAO4B;AACT;AAEA;;CAEC,GACD,OAAO,SAASS,iBAAiBrB,IAAY,EAAEsB,aAA+B;IAC5E,MAAMC,eAAeL,wBAAwBlB;IAC7C,MAAMwB,YAAYjB,MAAMU,IAAI,CAACM,aAAaE,IAAI;IAC9C,IAAIC,YAAY1B;IAChBwB,SACE,qCAAqC;IACrC,gFAAgF;IAChF,yEAAyE;KACxEG,QAAQ,CAAC,CAACC,GAAGC,IAAMA,EAAEC,MAAM,GAAGF,EAAEE,MAAM,EACtCC,OAAO,CAAC,CAACxC;QACR,MAAMyC,WAAWV,aAAa,CAAC/B,EAAE;QACjC,IAAIyC,YAAYA,SAASC,KAAK,KAAKvD,WAAW;YAC5CgD,YAAY3B,gBAAgB2B,WAAWnC,GAAGyC,UAAUC,OAAOV,aAAaW,GAAG,CAAC3C;QAC9E;IACF;IAEF,OAAOmC;AACT;AAEA;;CAEC,GACD,OAAO,SAASS,2BAA2BnC,IAAY,EAAEsB,aAA+B;IACtF,MAAMc,eAAiC,CAAC;IACxC,KAAK,MAAM,CAAClD,MAAMmD,MAAM,IAAIxD,OAAOyD,OAAO,CAAChB,eAAgB;QACzDc,YAAY,CAAClD,KAAK,GAAGmD,MAAME,YAAY,KAAK7D,YAAY2D,QAAQ;YAAE,GAAGA,KAAK;YAAEJ,OAAOI,MAAME,YAAY;QAAC;IACxG;IACA,OAAOlB,iBAAiBrB,MAAMoC;AAChC;AAEA;;;;;;;;;CASC,GACD,OAAO,SAASI,sBAAsBC,GAAW,EAAEnB,aAA+B;IAChF,IAAIoB,SAASrB,iBAAiBoB,KAAKnB;IAEnC,IAAI;QACF,MAAMqB,aAAa,gBAAgBC,IAAI,CAACF;QACxC,MAAMG,qBAAqBH,OAAOI,UAAU,CAAC;QAC7C,kEAAkE;QAClE,MAAMC,mBAAmB,uBAAuBH,IAAI,CAACF;QACrD,IAAI,CAACC,cAAc,CAACE,sBAAsBE,kBAAkB;YAC1D,OAAOL;QACT;QAEA,MAAMM,aAAaH,qBAAqB,CAAC,KAAK,EAAEH,QAAQ,GAAGA;QAC3D,MAAMO,YAAY,IAAIC,IAAIF,YAAYL,cAAcE,qBAAqBnE,YAAY;QAErF,4EAA4E;QAC5E,MAAMyE,kBAAkB5C,MAAMU,IAAI,CAACgC,UAAUG,YAAY,CAACd,OAAO;QACjE,IAAIe,UAAU;QACd,MAAMC,kBAAkBH,gBAAgB7D,GAAG,CAAC,CAAC,CAACiE,KAAKtB,MAAM;YACvD,MAAMuB,gBAAgBnC,iBAAiBY,OAAOX;YAC9C,IAAIkC,kBAAkBvB,OAAO;gBAC3BoB,UAAU;YACZ;YACA,OAAO;gBAACE;gBAAKC;aAAc;QAC7B;QAEA,IAAI,CAACH,SAAS;YACZ,OAAOX;QACT;QAEA,MAAMe,cAAc;eAAI,IAAI5C,IAAIsC,gBAAgB7D,GAAG,CAAC,CAAC,CAACiE,IAAI,GAAKA;SAAM;QACrE,KAAK,MAAMA,OAAOE,YAAa;YAC7BR,UAAUG,YAAY,CAACM,MAAM,CAACH;QAChC;QACA,KAAK,MAAM,CAACA,KAAKtB,MAAM,IAAIqB,gBAAiB;YAC1CL,UAAUG,YAAY,CAACO,MAAM,CAACJ,KAAKtB;QACrC;QAEA,IAAIU,YAAY;YACd,OAAOM,UAAUW,IAAI;QACvB;QACA,IAAIf,oBAAoB;YACtB,OAAO,CAAC,EAAE,EAAEI,UAAUY,IAAI,GAAGZ,UAAUa,QAAQ,GAAGb,UAAUc,MAAM,GAAGd,UAAUe,IAAI,EAAE;QACvF;QAEA,6EAA6E;QAC7E,MAAMC,IAAIvB,OAAOwB,OAAO,CAAC;QACzB,MAAMC,IAAIzB,OAAOwB,OAAO,CAAC;QACzB,IAAIE,UAAU1B,OAAOZ,MAAM;QAC3B,IAAImC,KAAK,GAAGG,UAAUH;aACjB,IAAIE,KAAK,GAAGC,UAAUD;QAC3B,MAAME,OAAO3B,OAAO4B,KAAK,CAAC,GAAGF;QAC7B,OAAO,GAAGC,OAAOpB,UAAUc,MAAM,GAAGd,UAAUe,IAAI,EAAE;IACtD,EAAE,OAAM;QACN,OAAOtB;IACT;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@perses-dev/components",
|
|
3
|
-
"version": "0.55.0-beta.
|
|
3
|
+
"version": "0.55.0-beta.11",
|
|
4
4
|
"description": "Common UI components used across Perses features",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/perses/perses/blob/main/README.md",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"@fontsource/inter": "^5.0.0",
|
|
36
36
|
"@mui/x-date-pickers": "^7.23.1",
|
|
37
37
|
"@perses-dev/spec": "0.3.0-beta.8",
|
|
38
|
-
"@perses-dev/client": "0.55.0-beta.
|
|
38
|
+
"@perses-dev/client": "0.55.0-beta.11",
|
|
39
39
|
"numbro": "^2.3.6",
|
|
40
40
|
"@tanstack/match-sorter-utils": "^8.19.4",
|
|
41
41
|
"@tanstack/react-table": "^8.20.5",
|