@perses-dev/plugin-system 0.52.0-rc.1 → 0.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/DatasourceSelect.js +2 -1
- package/dist/cjs/components/LegendOptionsEditor/LegendOptionsEditor.js +73 -73
- package/dist/cjs/components/PluginEditor/PluginEditor.js +9 -10
- package/dist/cjs/components/PluginKindSelect/PluginKindSelect.js +6 -3
- package/dist/cjs/context/query-params.js +5 -5
- package/dist/cjs/runtime/TimeRangeProvider/query-params.js +27 -27
- package/dist/components/DatasourceSelect.d.ts.map +1 -1
- package/dist/components/DatasourceSelect.js +2 -1
- package/dist/components/DatasourceSelect.js.map +1 -1
- package/dist/components/LegendOptionsEditor/LegendOptionsEditor.d.ts.map +1 -1
- package/dist/components/LegendOptionsEditor/LegendOptionsEditor.js +75 -75
- package/dist/components/LegendOptionsEditor/LegendOptionsEditor.js.map +1 -1
- package/dist/components/PluginEditor/PluginEditor.d.ts.map +1 -1
- package/dist/components/PluginEditor/PluginEditor.js +9 -10
- package/dist/components/PluginEditor/PluginEditor.js.map +1 -1
- package/dist/components/PluginKindSelect/PluginKindSelect.d.ts.map +1 -1
- package/dist/components/PluginKindSelect/PluginKindSelect.js +7 -4
- package/dist/components/PluginKindSelect/PluginKindSelect.js.map +1 -1
- package/dist/context/query-params.js +5 -5
- package/dist/context/query-params.js.map +1 -1
- package/dist/runtime/TimeRangeProvider/query-params.d.ts +12 -7
- package/dist/runtime/TimeRangeProvider/query-params.d.ts.map +1 -1
- package/dist/runtime/TimeRangeProvider/query-params.js +23 -20
- package/dist/runtime/TimeRangeProvider/query-params.js.map +1 -1
- package/package.json +5 -5
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
|
-
import { Switch } from '@mui/material';
|
|
13
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
14
|
+
import { Switch, ToggleButtonGroup, ToggleButton } from '@mui/material';
|
|
15
15
|
import { DEFAULT_LEGEND, getLegendMode, getLegendPosition, getLegendSize } from '@perses-dev/core';
|
|
16
16
|
import { ErrorAlert, OptionsEditorControl, OptionsEditorGroup, SettingsAutocomplete } from '@perses-dev/components';
|
|
17
17
|
import { useMemo } from 'react';
|
|
@@ -22,12 +22,6 @@ const POSITION_OPTIONS = Object.entries(LEGEND_POSITIONS_CONFIG).map(([id, confi
|
|
|
22
22
|
...config
|
|
23
23
|
};
|
|
24
24
|
});
|
|
25
|
-
const MODE_OPTIONS = Object.entries(LEGEND_MODE_CONFIG).map(([id, config])=>{
|
|
26
|
-
return {
|
|
27
|
-
id: id,
|
|
28
|
-
...config
|
|
29
|
-
};
|
|
30
|
-
});
|
|
31
25
|
const SIZE_OPTIONS = Object.entries(LEGEND_SIZE_CONFIG).map(([id, config])=>{
|
|
32
26
|
return {
|
|
33
27
|
id: id,
|
|
@@ -48,13 +42,6 @@ export function LegendOptionsEditor({ value, onChange, showValuesEditor = true,
|
|
|
48
42
|
position: newValue.id
|
|
49
43
|
});
|
|
50
44
|
};
|
|
51
|
-
const handleLegendModeChange = (_, newValue)=>{
|
|
52
|
-
onChange({
|
|
53
|
-
...value,
|
|
54
|
-
position: currentPosition,
|
|
55
|
-
mode: newValue.id
|
|
56
|
-
});
|
|
57
|
-
};
|
|
58
45
|
const handleLegendSizeChange = (_, newValue)=>{
|
|
59
46
|
onChange({
|
|
60
47
|
...value,
|
|
@@ -75,7 +62,6 @@ export function LegendOptionsEditor({ value, onChange, showValuesEditor = true,
|
|
|
75
62
|
const currentPosition = getLegendPosition(value?.position);
|
|
76
63
|
const legendPositionConfig = LEGEND_POSITIONS_CONFIG[currentPosition];
|
|
77
64
|
const currentMode = getLegendMode(value?.mode);
|
|
78
|
-
const legendModeConfig = LEGEND_MODE_CONFIG[currentMode];
|
|
79
65
|
const currentSize = getLegendSize(value?.size);
|
|
80
66
|
const legendSizeConfig = LEGEND_SIZE_CONFIG[currentSize];
|
|
81
67
|
const legendValuesConfig = useMemo(()=>{
|
|
@@ -137,65 +123,79 @@ export function LegendOptionsEditor({ value, onChange, showValuesEditor = true,
|
|
|
137
123
|
onChange: handleLegendShowChange
|
|
138
124
|
})
|
|
139
125
|
}),
|
|
140
|
-
/*#__PURE__*/
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
126
|
+
value && /*#__PURE__*/ _jsxs(_Fragment, {
|
|
127
|
+
children: [
|
|
128
|
+
/*#__PURE__*/ _jsx(OptionsEditorControl, {
|
|
129
|
+
label: "Position",
|
|
130
|
+
control: /*#__PURE__*/ _jsx(SettingsAutocomplete, {
|
|
131
|
+
value: {
|
|
132
|
+
...legendPositionConfig,
|
|
133
|
+
id: currentPosition
|
|
134
|
+
},
|
|
135
|
+
options: POSITION_OPTIONS,
|
|
136
|
+
onChange: handleLegendPositionChange,
|
|
137
|
+
disableClearable: true
|
|
138
|
+
})
|
|
139
|
+
}),
|
|
140
|
+
/*#__PURE__*/ _jsx(OptionsEditorControl, {
|
|
141
|
+
label: "Mode",
|
|
142
|
+
control: /*#__PURE__*/ _jsx(ToggleButtonGroup, {
|
|
143
|
+
color: "primary",
|
|
144
|
+
exclusive: true,
|
|
145
|
+
value: currentMode,
|
|
146
|
+
"aria-label": "Mode",
|
|
147
|
+
onChange: (__, newValue)=>{
|
|
148
|
+
onChange({
|
|
149
|
+
...value,
|
|
150
|
+
position: currentPosition,
|
|
151
|
+
mode: newValue
|
|
152
|
+
});
|
|
153
|
+
},
|
|
154
|
+
children: Object.entries(LEGEND_MODE_CONFIG).map(([modeId, config])=>/*#__PURE__*/ _jsx(ToggleButton, {
|
|
155
|
+
value: modeId,
|
|
156
|
+
selected: currentMode === modeId,
|
|
157
|
+
"aria-label": `display ${modeId} mode`,
|
|
158
|
+
children: config.label
|
|
159
|
+
}, modeId))
|
|
160
|
+
})
|
|
161
|
+
}),
|
|
162
|
+
currentMode === 'table' && /*#__PURE__*/ _jsxs(_Fragment, {
|
|
163
|
+
children: [
|
|
164
|
+
/*#__PURE__*/ _jsx(OptionsEditorControl, {
|
|
165
|
+
label: "Size",
|
|
166
|
+
control: /*#__PURE__*/ _jsx(SettingsAutocomplete, {
|
|
167
|
+
value: {
|
|
168
|
+
...legendSizeConfig,
|
|
169
|
+
id: currentSize
|
|
170
|
+
},
|
|
171
|
+
options: SIZE_OPTIONS,
|
|
172
|
+
onChange: handleLegendSizeChange,
|
|
173
|
+
// TODO: enable sizes for list mode when we normalize the layout of
|
|
174
|
+
// lists to more closely match tables.
|
|
175
|
+
disableClearable: true
|
|
176
|
+
})
|
|
177
|
+
}),
|
|
178
|
+
showValuesEditor && /*#__PURE__*/ _jsx(OptionsEditorControl, {
|
|
179
|
+
label: "Values",
|
|
180
|
+
control: // For some reason, the inferred option type doesn't always seem to work
|
|
181
|
+
// quite right when `multiple` is true. Explicitly setting the generics
|
|
182
|
+
// to work around this.
|
|
183
|
+
/*#__PURE__*/ _jsx(SettingsAutocomplete, {
|
|
184
|
+
multiple: true,
|
|
185
|
+
disableCloseOnSelect: true,
|
|
186
|
+
disableClearable: true,
|
|
187
|
+
value: legendValuesConfig,
|
|
188
|
+
options: valueOptions,
|
|
189
|
+
onChange: handleLegendValueChange,
|
|
190
|
+
limitTags: 1,
|
|
191
|
+
ChipProps: {
|
|
192
|
+
size: 'small'
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
})
|
|
196
|
+
]
|
|
197
|
+
})
|
|
198
|
+
]
|
|
199
199
|
})
|
|
200
200
|
]
|
|
201
201
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/LegendOptionsEditor/LegendOptionsEditor.tsx"],"sourcesContent":["// Copyright 2023 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 { Switch, SwitchProps } from '@mui/material';\nimport { DEFAULT_LEGEND, getLegendMode, getLegendPosition, getLegendSize } from '@perses-dev/core';\nimport { ErrorAlert, OptionsEditorControl, OptionsEditorGroup, SettingsAutocomplete } from '@perses-dev/components';\nimport { ReactElement, useMemo } from 'react';\nimport {\n LEGEND_MODE_CONFIG,\n LEGEND_POSITIONS_CONFIG,\n LegendSpecOptions,\n LegendSingleSelectConfig,\n validateLegendSpec,\n LEGEND_VALUE_CONFIG,\n LegendValue,\n LEGEND_SIZE_CONFIG,\n comparisonLegends,\n ComparisonValues,\n} from '../../model';\n\ntype LegendPositionOption = LegendSingleSelectConfig & { id: LegendSpecOptions['position'] };\n\nconst POSITION_OPTIONS: LegendPositionOption[] = Object.entries(LEGEND_POSITIONS_CONFIG).map(([id, config]) => {\n return {\n id: id as LegendSpecOptions['position'],\n ...config,\n };\n});\n\ntype LegendModeOption = LegendSingleSelectConfig & { id: Required<LegendSpecOptions>['mode'] };\n\nconst MODE_OPTIONS: LegendModeOption[] = Object.entries(LEGEND_MODE_CONFIG).map(([id, config]) => {\n return {\n id: id as Required<LegendSpecOptions>['mode'],\n ...config,\n };\n});\n\ntype LegendSizeOption = LegendSingleSelectConfig & { id: Required<LegendSpecOptions>['size'] };\n\nconst SIZE_OPTIONS: LegendSizeOption[] = Object.entries(LEGEND_SIZE_CONFIG).map(([id, config]) => {\n return {\n id: id as Required<LegendSpecOptions>['size'],\n ...config,\n };\n});\n\ntype LegendValueOption = LegendSingleSelectConfig & { id: LegendValue | ComparisonValues };\n\nexport interface LegendOptionsEditorProps {\n value?: LegendSpecOptions;\n onChange: (legend?: LegendSpecOptions) => void;\n showValuesEditor?: boolean;\n calculation?: 'aggregation' | 'comparison';\n}\n\nexport function LegendOptionsEditor({\n value,\n onChange,\n showValuesEditor = true,\n calculation = 'aggregation',\n}: LegendOptionsEditorProps): ReactElement {\n const handleLegendShowChange: SwitchProps['onChange'] = (_: unknown, checked: boolean) => {\n // legend is hidden when legend obj is undefined\n const legendValue = checked === true ? { position: DEFAULT_LEGEND.position } : undefined;\n onChange(legendValue);\n };\n\n const handleLegendPositionChange = (_: unknown, newValue: LegendPositionOption): void => {\n onChange({\n ...value,\n position: newValue.id,\n });\n };\n\n const handleLegendModeChange = (_: unknown, newValue: LegendModeOption): void => {\n onChange({\n ...value,\n position: currentPosition,\n mode: newValue.id,\n });\n };\n\n const handleLegendSizeChange = (_: unknown, newValue: LegendSizeOption): void => {\n onChange({\n ...value,\n position: currentPosition,\n size: newValue.id,\n });\n };\n\n const handleLegendValueChange = (_: unknown, newValue: LegendValueOption[]): void => {\n onChange({\n ...value,\n position: currentPosition,\n values: newValue.map((value) => {\n return value.id;\n }),\n });\n };\n\n const isValidLegend = validateLegendSpec(value);\n const currentPosition = getLegendPosition(value?.position);\n const legendPositionConfig = LEGEND_POSITIONS_CONFIG[currentPosition];\n\n const currentMode = getLegendMode(value?.mode);\n const legendModeConfig = LEGEND_MODE_CONFIG[currentMode];\n\n const currentSize = getLegendSize(value?.size);\n const legendSizeConfig = LEGEND_SIZE_CONFIG[currentSize];\n\n const legendValuesConfig = useMemo(() => {\n const currentValues = value?.values;\n if (!currentValues?.length) return [];\n\n if (calculation === 'aggregation') {\n return currentValues.reduce((result, item) => {\n const config = LEGEND_VALUE_CONFIG[item as LegendValue];\n if (config) {\n result.push({ ...config, id: item });\n }\n return result;\n }, [] as LegendValueOption[]);\n }\n\n return currentValues.map((id) => {\n const { label, description } = comparisonLegends[id as ComparisonValues];\n return {\n id,\n label,\n description,\n };\n });\n }, [calculation, value?.values]);\n\n const valueOptions = useMemo(() => {\n if (calculation === 'aggregation') {\n return Object.entries(LEGEND_VALUE_CONFIG || {}).map(([id, config]) => {\n return {\n id: id as LegendValue,\n ...config,\n };\n });\n }\n\n return Object.entries(comparisonLegends).map(([id, config]) => ({\n id: id as ComparisonValues,\n ...config,\n }));\n }, [calculation]);\n\n return (\n <OptionsEditorGroup title=\"Legend\">\n {!isValidLegend && <ErrorAlert error={{ name: 'invalid-legend', message: 'Invalid legend spec' }} />}\n <OptionsEditorControl label=\"Show\" control={<Switch checked={!!value} onChange={handleLegendShowChange} />} />\n <OptionsEditorControl\n label=\"Position\"\n control={\n <SettingsAutocomplete\n value={{\n ...legendPositionConfig,\n id: currentPosition,\n }}\n options={POSITION_OPTIONS}\n onChange={handleLegendPositionChange}\n disabled={value === undefined}\n disableClearable\n ></SettingsAutocomplete>\n }\n />\n <OptionsEditorControl\n label=\"Mode\"\n control={\n <SettingsAutocomplete\n value={{\n ...legendModeConfig,\n id: currentMode,\n }}\n options={MODE_OPTIONS}\n onChange={handleLegendModeChange}\n disabled={!value}\n disableClearable\n ></SettingsAutocomplete>\n }\n />\n <OptionsEditorControl\n label=\"Size\"\n control={\n <SettingsAutocomplete\n value={{\n ...legendSizeConfig,\n id: currentSize,\n }}\n options={SIZE_OPTIONS}\n onChange={handleLegendSizeChange}\n // TODO: enable sizes for list mode when we normalize the layout of\n // lists to more closely match tables.\n disabled={!value || currentMode !== 'table'}\n disableClearable\n ></SettingsAutocomplete>\n }\n />\n {showValuesEditor && (\n <OptionsEditorControl\n label=\"Values\"\n control={\n // For some reason, the inferred option type doesn't always seem to work\n // quite right when `multiple` is true. Explicitly setting the generics\n // to work around this.\n <SettingsAutocomplete<LegendValueOption, true, true>\n multiple={true}\n disableCloseOnSelect\n disableClearable\n value={legendValuesConfig}\n options={valueOptions}\n onChange={handleLegendValueChange}\n disabled={!value || currentMode !== 'table'}\n limitTags={1}\n ChipProps={{\n size: 'small',\n }}\n />\n }\n />\n )}\n </OptionsEditorGroup>\n );\n}\n"],"names":["Switch","DEFAULT_LEGEND","getLegendMode","getLegendPosition","getLegendSize","ErrorAlert","OptionsEditorControl","OptionsEditorGroup","SettingsAutocomplete","useMemo","LEGEND_MODE_CONFIG","LEGEND_POSITIONS_CONFIG","validateLegendSpec","LEGEND_VALUE_CONFIG","LEGEND_SIZE_CONFIG","comparisonLegends","POSITION_OPTIONS","Object","entries","map","id","config","MODE_OPTIONS","SIZE_OPTIONS","LegendOptionsEditor","value","onChange","showValuesEditor","calculation","handleLegendShowChange","_","checked","legendValue","position","undefined","handleLegendPositionChange","newValue","handleLegendModeChange","currentPosition","mode","handleLegendSizeChange","size","handleLegendValueChange","values","isValidLegend","legendPositionConfig","currentMode","legendModeConfig","currentSize","legendSizeConfig","legendValuesConfig","currentValues","length","reduce","result","item","push","label","description","valueOptions","title","error","name","message","control","options","disabled","disableClearable","multiple","disableCloseOnSelect","limitTags","ChipProps"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/LegendOptionsEditor/LegendOptionsEditor.tsx"],"sourcesContent":["// Copyright 2023 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 { Switch, SwitchProps, ToggleButtonGroup, ToggleButton } from '@mui/material';\nimport { DEFAULT_LEGEND, getLegendMode, getLegendPosition, getLegendSize } from '@perses-dev/core';\nimport { ErrorAlert, OptionsEditorControl, OptionsEditorGroup, SettingsAutocomplete } from '@perses-dev/components';\nimport { ReactElement, useMemo } from 'react';\nimport {\n LEGEND_MODE_CONFIG,\n LEGEND_POSITIONS_CONFIG,\n LegendSpecOptions,\n LegendSingleSelectConfig,\n validateLegendSpec,\n LEGEND_VALUE_CONFIG,\n LegendValue,\n LEGEND_SIZE_CONFIG,\n comparisonLegends,\n ComparisonValues,\n} from '../../model';\n\ntype LegendPositionOption = LegendSingleSelectConfig & { id: LegendSpecOptions['position'] };\n\nconst POSITION_OPTIONS: LegendPositionOption[] = Object.entries(LEGEND_POSITIONS_CONFIG).map(([id, config]) => {\n return {\n id: id as LegendSpecOptions['position'],\n ...config,\n };\n});\n\ntype LegendSizeOption = LegendSingleSelectConfig & { id: Required<LegendSpecOptions>['size'] };\n\nconst SIZE_OPTIONS: LegendSizeOption[] = Object.entries(LEGEND_SIZE_CONFIG).map(([id, config]) => {\n return {\n id: id as Required<LegendSpecOptions>['size'],\n ...config,\n };\n});\n\ntype LegendValueOption = LegendSingleSelectConfig & { id: LegendValue | ComparisonValues };\n\nexport interface LegendOptionsEditorProps {\n value?: LegendSpecOptions;\n onChange: (legend?: LegendSpecOptions) => void;\n showValuesEditor?: boolean;\n calculation?: 'aggregation' | 'comparison';\n}\n\nexport function LegendOptionsEditor({\n value,\n onChange,\n showValuesEditor = true,\n calculation = 'aggregation',\n}: LegendOptionsEditorProps): ReactElement {\n const handleLegendShowChange: SwitchProps['onChange'] = (_: unknown, checked: boolean) => {\n // legend is hidden when legend obj is undefined\n const legendValue = checked === true ? { position: DEFAULT_LEGEND.position } : undefined;\n onChange(legendValue);\n };\n\n const handleLegendPositionChange = (_: unknown, newValue: LegendPositionOption): void => {\n onChange({\n ...value,\n position: newValue.id,\n });\n };\n\n const handleLegendSizeChange = (_: unknown, newValue: LegendSizeOption): void => {\n onChange({\n ...value,\n position: currentPosition,\n size: newValue.id,\n });\n };\n\n const handleLegendValueChange = (_: unknown, newValue: LegendValueOption[]): void => {\n onChange({\n ...value,\n position: currentPosition,\n values: newValue.map((value) => {\n return value.id;\n }),\n });\n };\n\n const isValidLegend = validateLegendSpec(value);\n const currentPosition = getLegendPosition(value?.position);\n const legendPositionConfig = LEGEND_POSITIONS_CONFIG[currentPosition];\n\n const currentMode = getLegendMode(value?.mode);\n\n const currentSize = getLegendSize(value?.size);\n const legendSizeConfig = LEGEND_SIZE_CONFIG[currentSize];\n\n const legendValuesConfig = useMemo(() => {\n const currentValues = value?.values;\n if (!currentValues?.length) return [];\n\n if (calculation === 'aggregation') {\n return currentValues.reduce((result, item) => {\n const config = LEGEND_VALUE_CONFIG[item as LegendValue];\n if (config) {\n result.push({ ...config, id: item });\n }\n return result;\n }, [] as LegendValueOption[]);\n }\n\n return currentValues.map((id) => {\n const { label, description } = comparisonLegends[id as ComparisonValues];\n return {\n id,\n label,\n description,\n };\n });\n }, [calculation, value?.values]);\n\n const valueOptions = useMemo(() => {\n if (calculation === 'aggregation') {\n return Object.entries(LEGEND_VALUE_CONFIG || {}).map(([id, config]) => {\n return {\n id: id as LegendValue,\n ...config,\n };\n });\n }\n\n return Object.entries(comparisonLegends).map(([id, config]) => ({\n id: id as ComparisonValues,\n ...config,\n }));\n }, [calculation]);\n\n return (\n <OptionsEditorGroup title=\"Legend\">\n {!isValidLegend && <ErrorAlert error={{ name: 'invalid-legend', message: 'Invalid legend spec' }} />}\n <OptionsEditorControl label=\"Show\" control={<Switch checked={!!value} onChange={handleLegendShowChange} />} />\n {value && (\n <>\n <OptionsEditorControl\n label=\"Position\"\n control={\n <SettingsAutocomplete\n value={{\n ...legendPositionConfig,\n id: currentPosition,\n }}\n options={POSITION_OPTIONS}\n onChange={handleLegendPositionChange}\n disableClearable\n />\n }\n />\n <OptionsEditorControl\n label=\"Mode\"\n control={\n <ToggleButtonGroup\n color=\"primary\"\n exclusive\n value={currentMode}\n aria-label=\"Mode\"\n onChange={(__, newValue) => {\n onChange({\n ...value,\n position: currentPosition,\n mode: newValue,\n });\n }}\n >\n {Object.entries(LEGEND_MODE_CONFIG).map(([modeId, config]) => (\n <ToggleButton\n key={modeId}\n value={modeId}\n selected={currentMode === modeId}\n aria-label={`display ${modeId} mode`}\n >\n {config.label}\n </ToggleButton>\n ))}\n </ToggleButtonGroup>\n }\n />\n {currentMode === 'table' && (\n <>\n <OptionsEditorControl\n label=\"Size\"\n control={\n <SettingsAutocomplete\n value={{\n ...legendSizeConfig,\n id: currentSize,\n }}\n options={SIZE_OPTIONS}\n onChange={handleLegendSizeChange}\n // TODO: enable sizes for list mode when we normalize the layout of\n // lists to more closely match tables.\n disableClearable\n />\n }\n />\n {showValuesEditor && (\n <OptionsEditorControl\n label=\"Values\"\n control={\n // For some reason, the inferred option type doesn't always seem to work\n // quite right when `multiple` is true. Explicitly setting the generics\n // to work around this.\n <SettingsAutocomplete<LegendValueOption, true, true>\n multiple={true}\n disableCloseOnSelect\n disableClearable\n value={legendValuesConfig}\n options={valueOptions}\n onChange={handleLegendValueChange}\n limitTags={1}\n ChipProps={{\n size: 'small',\n }}\n />\n }\n />\n )}\n </>\n )}\n </>\n )}\n </OptionsEditorGroup>\n );\n}\n"],"names":["Switch","ToggleButtonGroup","ToggleButton","DEFAULT_LEGEND","getLegendMode","getLegendPosition","getLegendSize","ErrorAlert","OptionsEditorControl","OptionsEditorGroup","SettingsAutocomplete","useMemo","LEGEND_MODE_CONFIG","LEGEND_POSITIONS_CONFIG","validateLegendSpec","LEGEND_VALUE_CONFIG","LEGEND_SIZE_CONFIG","comparisonLegends","POSITION_OPTIONS","Object","entries","map","id","config","SIZE_OPTIONS","LegendOptionsEditor","value","onChange","showValuesEditor","calculation","handleLegendShowChange","_","checked","legendValue","position","undefined","handleLegendPositionChange","newValue","handleLegendSizeChange","currentPosition","size","handleLegendValueChange","values","isValidLegend","legendPositionConfig","currentMode","mode","currentSize","legendSizeConfig","legendValuesConfig","currentValues","length","reduce","result","item","push","label","description","valueOptions","title","error","name","message","control","options","disableClearable","color","exclusive","aria-label","__","modeId","selected","multiple","disableCloseOnSelect","limitTags","ChipProps"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PluginEditor.d.ts","sourceRoot":"","sources":["../../../src/components/PluginEditor/PluginEditor.tsx"],"names":[],"mappings":";AAoBA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAmB,MAAM,qBAAqB,CAAC;AAE1F;;;;;;;GAOG;AAEH,eAAO,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"PluginEditor.d.ts","sourceRoot":"","sources":["../../../src/components/PluginEditor/PluginEditor.tsx"],"names":[],"mappings":";AAoBA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAmB,MAAM,qBAAqB,CAAC;AAE1F;;;;;;;GAOG;AAEH,eAAO,MAAM,YAAY,4HAwFvB,CAAC"}
|
|
@@ -72,13 +72,16 @@ import { usePluginEditor } from './plugin-editor-api';
|
|
|
72
72
|
/*#__PURE__*/ _jsxs(Box, {
|
|
73
73
|
sx: {
|
|
74
74
|
display: 'flex',
|
|
75
|
-
flexDirection: 'row'
|
|
75
|
+
flexDirection: 'row',
|
|
76
|
+
alignItems: 'center',
|
|
77
|
+
justifyContent: 'space-between',
|
|
78
|
+
gap: 1,
|
|
79
|
+
mb: 1
|
|
76
80
|
},
|
|
77
81
|
children: [
|
|
78
82
|
/*#__PURE__*/ _jsx(PluginKindSelect, {
|
|
79
83
|
fullWidth: false,
|
|
80
84
|
sx: {
|
|
81
|
-
mb: 2,
|
|
82
85
|
minWidth: 120
|
|
83
86
|
},
|
|
84
87
|
margin: "dense",
|
|
@@ -86,8 +89,10 @@ import { usePluginEditor } from './plugin-editor-api';
|
|
|
86
89
|
pluginTypes: pluginTypes,
|
|
87
90
|
disabled: isLoading,
|
|
88
91
|
value: pendingSelection ? pendingSelection : value.selection,
|
|
89
|
-
|
|
90
|
-
|
|
92
|
+
slotProps: {
|
|
93
|
+
input: {
|
|
94
|
+
readOnly: isReadonly
|
|
95
|
+
}
|
|
91
96
|
},
|
|
92
97
|
error: !!error,
|
|
93
98
|
helperText: error?.message,
|
|
@@ -96,12 +101,6 @@ import { usePluginEditor } from './plugin-editor-api';
|
|
|
96
101
|
withRunQueryButton && !isLoading && /*#__PURE__*/ _jsx(Button, {
|
|
97
102
|
"data-testid": "run_query_button",
|
|
98
103
|
variant: "contained",
|
|
99
|
-
sx: {
|
|
100
|
-
marginTop: 1.5,
|
|
101
|
-
marginBottom: 1.5,
|
|
102
|
-
paddingTop: 0.5,
|
|
103
|
-
marginLeft: 'auto'
|
|
104
|
-
},
|
|
105
104
|
startIcon: /*#__PURE__*/ _jsx(Reload, {}),
|
|
106
105
|
onClick: runQueryHandler,
|
|
107
106
|
children: "Run Query"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/PluginEditor/PluginEditor.tsx"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Box, Button } from '@mui/material';\nimport Reload from 'mdi-material-ui/Reload';\nimport { ErrorAlert, ErrorBoundary } from '@perses-dev/components';\nimport { forwardRef, ReactElement, useCallback, useImperativeHandle, useMemo, useState } from 'react';\nimport { UnknownSpec } from '@perses-dev/core';\nimport { PluginKindSelect } from '../PluginKindSelect';\nimport { PluginSpecEditor } from '../PluginSpecEditor';\nimport { PluginEditorProps, PluginEditorRef, usePluginEditor } from './plugin-editor-api';\n\n/**\n * A combination `PluginKindSelect` and `PluginSpecEditor` component. This is meant for editing the `plugin` property\n * that's common in our JSON specs where a user selects a plugin `kind` and then edits the `spec` via that plugin's\n * editor component. It takes care of transitioning from one plugin kind to another \"all at once\" so that when the\n * plugin's kind changes, the spec is also changed at the same time so those options editor components don't see a\n * previous plugin's spec state. If you just want this behavior, but in a different UI layout from this, try the\n * `usePluginEditor` hook that powers this component.\n */\n\nexport const PluginEditor = forwardRef<PluginEditorRef, PluginEditorProps>((props, ref): ReactElement => {\n const {\n value,\n withRunQueryButton = true,\n pluginTypes,\n pluginKindLabel,\n onChange: _,\n isReadonly,\n postExecuteRunQuery: refresh,\n ...others\n } = props;\n const { pendingSelection, isLoading, error, onSelectionChange, onSpecChange } = usePluginEditor(props);\n\n /* \n We could technically merge the watchedQuery, watchedOtherSpecs into a single watched-object,\n because at the end of the day, they are all specs.\n However, let's have them separated to keep the code simple and readable.\n Reason: Only Query string field is common between all of them. Other specs may be different\n Example: Legend, and MinSteps\n */\n const [watchedQuery, setWatchQuery] = useState<string>(value.spec['query'] as string);\n const [watchedOtherSpecs, setWatchOtherSpecs] = useState<UnknownSpec>(value.spec);\n\n const runQueryHandler = useCallback((): void => {\n onSpecChange({ ...value.spec, ...watchedOtherSpecs, query: watchedQuery });\n refresh?.();\n }, [value.spec, onSpecChange, watchedQuery, watchedOtherSpecs, refresh]);\n\n const queryHandlerSettings = useMemo(() => {\n return withRunQueryButton\n ? {\n runWithOnBlur: false,\n watchQueryChanges: (query: string): void => {\n setWatchQuery(query);\n },\n setWatchOtherSpecs: (otherSpecs: UnknownSpec): void => {\n setWatchOtherSpecs(otherSpecs);\n },\n }\n : undefined;\n }, [withRunQueryButton]);\n\n useImperativeHandle(ref, () => ({ flushChanges: runQueryHandler }));\n\n return (\n <Box {...others}>\n <Box
|
|
1
|
+
{"version":3,"sources":["../../../src/components/PluginEditor/PluginEditor.tsx"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Box, Button } from '@mui/material';\nimport Reload from 'mdi-material-ui/Reload';\nimport { ErrorAlert, ErrorBoundary } from '@perses-dev/components';\nimport { forwardRef, ReactElement, useCallback, useImperativeHandle, useMemo, useState } from 'react';\nimport { UnknownSpec } from '@perses-dev/core';\nimport { PluginKindSelect } from '../PluginKindSelect';\nimport { PluginSpecEditor } from '../PluginSpecEditor';\nimport { PluginEditorProps, PluginEditorRef, usePluginEditor } from './plugin-editor-api';\n\n/**\n * A combination `PluginKindSelect` and `PluginSpecEditor` component. This is meant for editing the `plugin` property\n * that's common in our JSON specs where a user selects a plugin `kind` and then edits the `spec` via that plugin's\n * editor component. It takes care of transitioning from one plugin kind to another \"all at once\" so that when the\n * plugin's kind changes, the spec is also changed at the same time so those options editor components don't see a\n * previous plugin's spec state. If you just want this behavior, but in a different UI layout from this, try the\n * `usePluginEditor` hook that powers this component.\n */\n\nexport const PluginEditor = forwardRef<PluginEditorRef, PluginEditorProps>((props, ref): ReactElement => {\n const {\n value,\n withRunQueryButton = true,\n pluginTypes,\n pluginKindLabel,\n onChange: _,\n isReadonly,\n postExecuteRunQuery: refresh,\n ...others\n } = props;\n const { pendingSelection, isLoading, error, onSelectionChange, onSpecChange } = usePluginEditor(props);\n\n /* \n We could technically merge the watchedQuery, watchedOtherSpecs into a single watched-object,\n because at the end of the day, they are all specs.\n However, let's have them separated to keep the code simple and readable.\n Reason: Only Query string field is common between all of them. Other specs may be different\n Example: Legend, and MinSteps\n */\n const [watchedQuery, setWatchQuery] = useState<string>(value.spec['query'] as string);\n const [watchedOtherSpecs, setWatchOtherSpecs] = useState<UnknownSpec>(value.spec);\n\n const runQueryHandler = useCallback((): void => {\n onSpecChange({ ...value.spec, ...watchedOtherSpecs, query: watchedQuery });\n refresh?.();\n }, [value.spec, onSpecChange, watchedQuery, watchedOtherSpecs, refresh]);\n\n const queryHandlerSettings = useMemo(() => {\n return withRunQueryButton\n ? {\n runWithOnBlur: false,\n watchQueryChanges: (query: string): void => {\n setWatchQuery(query);\n },\n setWatchOtherSpecs: (otherSpecs: UnknownSpec): void => {\n setWatchOtherSpecs(otherSpecs);\n },\n }\n : undefined;\n }, [withRunQueryButton]);\n\n useImperativeHandle(ref, () => ({ flushChanges: runQueryHandler }));\n\n return (\n <Box {...others}>\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 1,\n mb: 1,\n }}\n >\n <PluginKindSelect\n fullWidth={false}\n sx={{ minWidth: 120 }}\n margin=\"dense\"\n label={pluginKindLabel}\n pluginTypes={pluginTypes}\n disabled={isLoading}\n value={pendingSelection ? pendingSelection : value.selection}\n slotProps={{ input: { readOnly: isReadonly } }}\n error={!!error}\n helperText={error?.message}\n onChange={onSelectionChange}\n />\n\n {withRunQueryButton && !isLoading && (\n <Button data-testid=\"run_query_button\" variant=\"contained\" startIcon={<Reload />} onClick={runQueryHandler}>\n Run Query\n </Button>\n )}\n </Box>\n\n <ErrorBoundary FallbackComponent={ErrorAlert}>\n <PluginSpecEditor\n pluginSelection={value.selection}\n value={value.spec}\n onChange={onSpecChange}\n isReadonly={isReadonly}\n queryHandlerSettings={queryHandlerSettings}\n />\n </ErrorBoundary>\n </Box>\n );\n});\n\nPluginEditor.displayName = 'PluginEditor';\n"],"names":["Box","Button","Reload","ErrorAlert","ErrorBoundary","forwardRef","useCallback","useImperativeHandle","useMemo","useState","PluginKindSelect","PluginSpecEditor","usePluginEditor","PluginEditor","props","ref","value","withRunQueryButton","pluginTypes","pluginKindLabel","onChange","_","isReadonly","postExecuteRunQuery","refresh","others","pendingSelection","isLoading","error","onSelectionChange","onSpecChange","watchedQuery","setWatchQuery","spec","watchedOtherSpecs","setWatchOtherSpecs","runQueryHandler","query","queryHandlerSettings","runWithOnBlur","watchQueryChanges","otherSpecs","undefined","flushChanges","sx","display","flexDirection","alignItems","justifyContent","gap","mb","fullWidth","minWidth","margin","label","disabled","selection","slotProps","input","readOnly","helperText","message","data-testid","variant","startIcon","onClick","FallbackComponent","pluginSelection","displayName"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAASA,GAAG,EAAEC,MAAM,QAAQ,gBAAgB;AAC5C,OAAOC,YAAY,yBAAyB;AAC5C,SAASC,UAAU,EAAEC,aAAa,QAAQ,yBAAyB;AACnE,SAASC,UAAU,EAAgBC,WAAW,EAAEC,mBAAmB,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAQ;AAEtG,SAASC,gBAAgB,QAAQ,sBAAsB;AACvD,SAASC,gBAAgB,QAAQ,sBAAsB;AACvD,SAA6CC,eAAe,QAAQ,sBAAsB;AAE1F;;;;;;;CAOC,GAED,OAAO,MAAMC,6BAAeR,WAA+C,CAACS,OAAOC;IACjF,MAAM,EACJC,KAAK,EACLC,qBAAqB,IAAI,EACzBC,WAAW,EACXC,eAAe,EACfC,UAAUC,CAAC,EACXC,UAAU,EACVC,qBAAqBC,OAAO,EAC5B,GAAGC,QACJ,GAAGX;IACJ,MAAM,EAAEY,gBAAgB,EAAEC,SAAS,EAAEC,KAAK,EAAEC,iBAAiB,EAAEC,YAAY,EAAE,GAAGlB,gBAAgBE;IAEhG;;;;;;IAME,GACF,MAAM,CAACiB,cAAcC,cAAc,GAAGvB,SAAiBO,MAAMiB,IAAI,CAAC,QAAQ;IAC1E,MAAM,CAACC,mBAAmBC,mBAAmB,GAAG1B,SAAsBO,MAAMiB,IAAI;IAEhF,MAAMG,kBAAkB9B,YAAY;QAClCwB,aAAa;YAAE,GAAGd,MAAMiB,IAAI;YAAE,GAAGC,iBAAiB;YAAEG,OAAON;QAAa;QACxEP;IACF,GAAG;QAACR,MAAMiB,IAAI;QAAEH;QAAcC;QAAcG;QAAmBV;KAAQ;IAEvE,MAAMc,uBAAuB9B,QAAQ;QACnC,OAAOS,qBACH;YACEsB,eAAe;YACfC,mBAAmB,CAACH;gBAClBL,cAAcK;YAChB;YACAF,oBAAoB,CAACM;gBACnBN,mBAAmBM;YACrB;QACF,IACAC;IACN,GAAG;QAACzB;KAAmB;IAEvBV,oBAAoBQ,KAAK,IAAO,CAAA;YAAE4B,cAAcP;QAAgB,CAAA;IAEhE,qBACE,MAACpC;QAAK,GAAGyB,MAAM;;0BACb,MAACzB;gBACC4C,IAAI;oBACFC,SAAS;oBACTC,eAAe;oBACfC,YAAY;oBACZC,gBAAgB;oBAChBC,KAAK;oBACLC,IAAI;gBACN;;kCAEA,KAACxC;wBACCyC,WAAW;wBACXP,IAAI;4BAAEQ,UAAU;wBAAI;wBACpBC,QAAO;wBACPC,OAAOnC;wBACPD,aAAaA;wBACbqC,UAAU5B;wBACVX,OAAOU,mBAAmBA,mBAAmBV,MAAMwC,SAAS;wBAC5DC,WAAW;4BAAEC,OAAO;gCAAEC,UAAUrC;4BAAW;wBAAE;wBAC7CM,OAAO,CAAC,CAACA;wBACTgC,YAAYhC,OAAOiC;wBACnBzC,UAAUS;;oBAGXZ,sBAAsB,CAACU,2BACtB,KAAC1B;wBAAO6D,eAAY;wBAAmBC,SAAQ;wBAAYC,yBAAW,KAAC9D;wBAAW+D,SAAS7B;kCAAiB;;;;0BAMhH,KAAChC;gBAAc8D,mBAAmB/D;0BAChC,cAAA,KAACQ;oBACCwD,iBAAiBnD,MAAMwC,SAAS;oBAChCxC,OAAOA,MAAMiB,IAAI;oBACjBb,UAAUU;oBACVR,YAAYA;oBACZgB,sBAAsBA;;;;;AAKhC,GAAG;AAEHzB,aAAauD,WAAW,GAAG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PluginKindSelect.d.ts","sourceRoot":"","sources":["../../../src/components/PluginKindSelect/PluginKindSelect.tsx"],"names":[],"mappings":";AAaA,OAAO,EAAuB,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAExD,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,CAAC;IACpG,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,qBAAqB,CAAC;IAC9B,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAC/C;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,
|
|
1
|
+
{"version":3,"file":"PluginKindSelect.d.ts","sourceRoot":"","sources":["../../../src/components/PluginKindSelect/PluginKindSelect.tsx"],"names":[],"mappings":";AAaA,OAAO,EAAuB,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAExD,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,CAAC;IACpG,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,qBAAqB,CAAC;IAC9B,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAC/C;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,wHAoD3B,CAAC"}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
14
|
import { MenuItem, TextField } from '@mui/material';
|
|
15
|
-
import { forwardRef, useCallback } from 'react';
|
|
15
|
+
import { forwardRef, useCallback, useMemo } from 'react';
|
|
16
16
|
import { useListPluginMetadata } from '../../runtime';
|
|
17
17
|
/**
|
|
18
18
|
* Displays a MUI Select input for selecting a plugin's kind from a list of all the available plugins of some specific
|
|
@@ -23,6 +23,9 @@ import { useListPluginMetadata } from '../../runtime';
|
|
|
23
23
|
*/ export const PluginKindSelect = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
24
24
|
const { pluginTypes, value: propValue, onChange, ...others } = props;
|
|
25
25
|
const { data, isLoading } = useListPluginMetadata(pluginTypes);
|
|
26
|
+
const sortedData = useMemo(()=>data?.sort((a, b)=>a.spec.display.name.localeCompare(b.spec.display.name)), [
|
|
27
|
+
data
|
|
28
|
+
]);
|
|
26
29
|
// Pass an empty value while options are still loading so MUI doesn't complain about us using an "out of range" value
|
|
27
30
|
const value = !propValue || isLoading ? '' : selectionToOptionValue(propValue);
|
|
28
31
|
const handleChange = (event)=>{
|
|
@@ -33,9 +36,9 @@ import { useListPluginMetadata } from '../../runtime';
|
|
|
33
36
|
return '';
|
|
34
37
|
}
|
|
35
38
|
const selectedValue = optionValueToSelection(selected);
|
|
36
|
-
return
|
|
39
|
+
return sortedData?.find((v)=>v.kind === selectedValue.type && v.spec.name === selectedValue.kind)?.spec.display.name;
|
|
37
40
|
}, [
|
|
38
|
-
|
|
41
|
+
sortedData
|
|
39
42
|
]);
|
|
40
43
|
// TODO: Does this need a loading indicator of some kind?
|
|
41
44
|
return /*#__PURE__*/ _jsxs(TextField, {
|
|
@@ -54,7 +57,7 @@ import { useListPluginMetadata } from '../../runtime';
|
|
|
54
57
|
value: "",
|
|
55
58
|
children: "Loading..."
|
|
56
59
|
}),
|
|
57
|
-
|
|
60
|
+
sortedData?.map((metadata)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
58
61
|
"data-testid": "option",
|
|
59
62
|
value: selectionToOptionValue({
|
|
60
63
|
type: metadata.kind,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/PluginKindSelect/PluginKindSelect.tsx"],"sourcesContent":["// Copyright 2023 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 { MenuItem, TextField, TextFieldProps } from '@mui/material';\nimport { forwardRef, ReactElement, useCallback } from 'react';\nimport { PluginType } from '../../model';\nimport { useListPluginMetadata } from '../../runtime';\nimport { PluginEditorSelection } from '../PluginEditor';\n\nexport interface PluginKindSelectProps extends Omit<TextFieldProps, 'value' | 'onChange' | 'children'> {\n pluginTypes: PluginType[];\n value?: PluginEditorSelection;\n onChange?: (s: PluginEditorSelection) => void;\n}\n\n/**\n * Displays a MUI Select input for selecting a plugin's kind from a list of all the available plugins of some specific\n * plugin types. (e.g. \"Show a list of all the Panel plugins\", or \"Show a list of all the Variable plugins\", or \"Show\n * a list of all the TimeSeriesQuery, TraceQuery, ProfileQuery, and LogQuery plugins\").\n * The value of the select is the kind of the plugin, but you can also listen to the `onPluginTypeChange` event to know\n * when the user changes the plugin type (it fires at start for the default value.)\n */\nexport const PluginKindSelect = forwardRef((props: PluginKindSelectProps, ref): ReactElement => {\n const { pluginTypes, value: propValue, onChange, ...others } = props;\n const { data, isLoading } = useListPluginMetadata(pluginTypes);\n\n // Pass an empty value while options are still loading so MUI doesn't complain about us using an \"out of range\" value\n const value = !propValue || isLoading ? '' : selectionToOptionValue(propValue);\n\n const handleChange = (event: { target: { value: string } }): void => {\n onChange?.(optionValueToSelection(event.target.value));\n };\n\n const renderValue = useCallback(\n (selected: unknown) => {\n if (selected === '') {\n return '';\n }\n const selectedValue = optionValueToSelection(selected as string);\n return
|
|
1
|
+
{"version":3,"sources":["../../../src/components/PluginKindSelect/PluginKindSelect.tsx"],"sourcesContent":["// Copyright 2023 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 { MenuItem, TextField, TextFieldProps } from '@mui/material';\nimport { forwardRef, ReactElement, useCallback, useMemo } from 'react';\nimport { PluginType } from '../../model';\nimport { useListPluginMetadata } from '../../runtime';\nimport { PluginEditorSelection } from '../PluginEditor';\n\nexport interface PluginKindSelectProps extends Omit<TextFieldProps, 'value' | 'onChange' | 'children'> {\n pluginTypes: PluginType[];\n value?: PluginEditorSelection;\n onChange?: (s: PluginEditorSelection) => void;\n}\n\n/**\n * Displays a MUI Select input for selecting a plugin's kind from a list of all the available plugins of some specific\n * plugin types. (e.g. \"Show a list of all the Panel plugins\", or \"Show a list of all the Variable plugins\", or \"Show\n * a list of all the TimeSeriesQuery, TraceQuery, ProfileQuery, and LogQuery plugins\").\n * The value of the select is the kind of the plugin, but you can also listen to the `onPluginTypeChange` event to know\n * when the user changes the plugin type (it fires at start for the default value.)\n */\nexport const PluginKindSelect = forwardRef((props: PluginKindSelectProps, ref): ReactElement => {\n const { pluginTypes, value: propValue, onChange, ...others } = props;\n const { data, isLoading } = useListPluginMetadata(pluginTypes);\n\n const sortedData = useMemo(\n () => data?.sort((a, b) => a.spec.display.name.localeCompare(b.spec.display.name)),\n [data]\n );\n\n // Pass an empty value while options are still loading so MUI doesn't complain about us using an \"out of range\" value\n const value = !propValue || isLoading ? '' : selectionToOptionValue(propValue);\n\n const handleChange = (event: { target: { value: string } }): void => {\n onChange?.(optionValueToSelection(event.target.value));\n };\n\n const renderValue = useCallback(\n (selected: unknown) => {\n if (selected === '') {\n return '';\n }\n const selectedValue = optionValueToSelection(selected as string);\n return sortedData?.find((v) => v.kind === selectedValue.type && v.spec.name === selectedValue.kind)?.spec.display\n .name;\n },\n [sortedData]\n );\n\n // TODO: Does this need a loading indicator of some kind?\n return (\n <TextField\n select\n inputRef={ref}\n {...others}\n value={value}\n aria-label={value}\n onChange={handleChange}\n SelectProps={{ renderValue }}\n data-testid=\"plugin-kind-select\"\n >\n {isLoading && <MenuItem value=\"\">Loading...</MenuItem>}\n {sortedData?.map((metadata) => (\n <MenuItem\n data-testid=\"option\"\n key={metadata.kind + metadata.spec.name}\n value={selectionToOptionValue({ type: metadata.kind, kind: metadata.spec.name })}\n >\n {metadata.spec.display.name}\n </MenuItem>\n ))}\n </TextField>\n );\n});\nPluginKindSelect.displayName = 'PluginKindSelect';\n\n// Delimiter used to stringify/parse option values\nconst OPTION_VALUE_DELIMITER = '_____';\n\n/**\n * Given a PluginEditorSelection,\n * returns a string value like `{type}_____{kind}` that can be used as a Select input value.\n * @param selector\n */\nfunction selectionToOptionValue(selector: PluginEditorSelection): string {\n return [selector.type, selector.kind].join(OPTION_VALUE_DELIMITER);\n}\n\n/**\n * Given an option value name like `{type}_____{kind}`,\n * returns a PluginEditorSelection to be used by the query data model.\n * @param optionValue\n */\nfunction optionValueToSelection(optionValue: string): PluginEditorSelection {\n const words = optionValue.split(OPTION_VALUE_DELIMITER);\n const type = words[0] as PluginType | undefined;\n const kind = words[1];\n if (type === undefined || kind === undefined) {\n throw new Error('Invalid optionValue string');\n }\n return {\n type,\n kind,\n };\n}\n"],"names":["MenuItem","TextField","forwardRef","useCallback","useMemo","useListPluginMetadata","PluginKindSelect","props","ref","pluginTypes","value","propValue","onChange","others","data","isLoading","sortedData","sort","a","b","spec","display","name","localeCompare","selectionToOptionValue","handleChange","event","optionValueToSelection","target","renderValue","selected","selectedValue","find","v","kind","type","select","inputRef","aria-label","SelectProps","data-testid","map","metadata","displayName","OPTION_VALUE_DELIMITER","selector","join","optionValue","words","split","undefined","Error"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAASA,QAAQ,EAAEC,SAAS,QAAwB,gBAAgB;AACpE,SAASC,UAAU,EAAgBC,WAAW,EAAEC,OAAO,QAAQ,QAAQ;AAEvE,SAASC,qBAAqB,QAAQ,gBAAgB;AAStD;;;;;;CAMC,GACD,OAAO,MAAMC,iCAAmBJ,WAAW,CAACK,OAA8BC;IACxE,MAAM,EAAEC,WAAW,EAAEC,OAAOC,SAAS,EAAEC,QAAQ,EAAE,GAAGC,QAAQ,GAAGN;IAC/D,MAAM,EAAEO,IAAI,EAAEC,SAAS,EAAE,GAAGV,sBAAsBI;IAElD,MAAMO,aAAaZ,QACjB,IAAMU,MAAMG,KAAK,CAACC,GAAGC,IAAMD,EAAEE,IAAI,CAACC,OAAO,CAACC,IAAI,CAACC,aAAa,CAACJ,EAAEC,IAAI,CAACC,OAAO,CAACC,IAAI,IAChF;QAACR;KAAK;IAGR,qHAAqH;IACrH,MAAMJ,QAAQ,CAACC,aAAaI,YAAY,KAAKS,uBAAuBb;IAEpE,MAAMc,eAAe,CAACC;QACpBd,WAAWe,uBAAuBD,MAAME,MAAM,CAAClB,KAAK;IACtD;IAEA,MAAMmB,cAAc1B,YAClB,CAAC2B;QACC,IAAIA,aAAa,IAAI;YACnB,OAAO;QACT;QACA,MAAMC,gBAAgBJ,uBAAuBG;QAC7C,OAAOd,YAAYgB,KAAK,CAACC,IAAMA,EAAEC,IAAI,KAAKH,cAAcI,IAAI,IAAIF,EAAEb,IAAI,CAACE,IAAI,KAAKS,cAAcG,IAAI,GAAGd,KAAKC,QACvGC;IACL,GACA;QAACN;KAAW;IAGd,yDAAyD;IACzD,qBACE,MAACf;QACCmC,MAAM;QACNC,UAAU7B;QACT,GAAGK,MAAM;QACVH,OAAOA;QACP4B,cAAY5B;QACZE,UAAUa;QACVc,aAAa;YAAEV;QAAY;QAC3BW,eAAY;;YAEXzB,2BAAa,KAACf;gBAASU,OAAM;0BAAG;;YAChCM,YAAYyB,IAAI,CAACC,yBAChB,KAAC1C;oBACCwC,eAAY;oBAEZ9B,OAAOc,uBAAuB;wBAAEW,MAAMO,SAASR,IAAI;wBAAEA,MAAMQ,SAAStB,IAAI,CAACE,IAAI;oBAAC;8BAE7EoB,SAAStB,IAAI,CAACC,OAAO,CAACC,IAAI;mBAHtBoB,SAASR,IAAI,GAAGQ,SAAStB,IAAI,CAACE,IAAI;;;AAQjD,GAAG;AACHhB,iBAAiBqC,WAAW,GAAG;AAE/B,kDAAkD;AAClD,MAAMC,yBAAyB;AAE/B;;;;CAIC,GACD,SAASpB,uBAAuBqB,QAA+B;IAC7D,OAAO;QAACA,SAASV,IAAI;QAAEU,SAASX,IAAI;KAAC,CAACY,IAAI,CAACF;AAC7C;AAEA;;;;CAIC,GACD,SAASjB,uBAAuBoB,WAAmB;IACjD,MAAMC,QAAQD,YAAYE,KAAK,CAACL;IAChC,MAAMT,OAAOa,KAAK,CAAC,EAAE;IACrB,MAAMd,OAAOc,KAAK,CAAC,EAAE;IACrB,IAAIb,SAASe,aAAahB,SAASgB,WAAW;QAC5C,MAAM,IAAIC,MAAM;IAClB;IACA,OAAO;QACLhB;QACAD;IACF;AACF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Copyright
|
|
1
|
+
// Copyright 2025 The Perses Authors
|
|
2
2
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
// you may not use this file except in compliance with the License.
|
|
4
4
|
// You may obtain a copy of the License at
|
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
import { useCallback, useState } from 'react';
|
|
14
|
-
import {
|
|
14
|
+
import { useQueryParams } from 'use-query-params';
|
|
15
15
|
export function useSetProjectParams(enabledURLParams = true) {
|
|
16
|
-
const [query, setQuery] =
|
|
17
|
-
project:
|
|
16
|
+
const [query, setQuery] = useQueryParams({
|
|
17
|
+
project: ''
|
|
18
18
|
}, {
|
|
19
|
-
|
|
19
|
+
updateType: 'replaceIn'
|
|
20
20
|
});
|
|
21
21
|
const [projectState, setProjectState] = useState('none');
|
|
22
22
|
const setProject = useCallback((project)=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/context/query-params.ts"],"sourcesContent":["// Copyright
|
|
1
|
+
{"version":3,"sources":["../../src/context/query-params.ts"],"sourcesContent":["// Copyright 2025 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 { useCallback, useState } from 'react';\nimport { useQueryParams } from 'use-query-params';\n\nexport function useSetProjectParams(enabledURLParams = true): {\n project: string;\n setProject: (project: string) => void;\n} {\n const [query, setQuery] = useQueryParams({ project: '' }, { updateType: 'replaceIn' });\n\n const [projectState, setProjectState] = useState<string>('none');\n\n const setProject = useCallback(\n (project: string) => {\n return setQuery({ project });\n },\n [setQuery]\n );\n\n if (enabledURLParams) {\n return {\n project: query.project || 'none',\n setProject,\n };\n }\n\n return {\n project: projectState,\n setProject: setProjectState,\n };\n}\n"],"names":["useCallback","useState","useQueryParams","useSetProjectParams","enabledURLParams","query","setQuery","project","updateType","projectState","setProjectState","setProject"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAASA,WAAW,EAAEC,QAAQ,QAAQ,QAAQ;AAC9C,SAASC,cAAc,QAAQ,mBAAmB;AAElD,OAAO,SAASC,oBAAoBC,mBAAmB,IAAI;IAIzD,MAAM,CAACC,OAAOC,SAAS,GAAGJ,eAAe;QAAEK,SAAS;IAAG,GAAG;QAAEC,YAAY;IAAY;IAEpF,MAAM,CAACC,cAAcC,gBAAgB,GAAGT,SAAiB;IAEzD,MAAMU,aAAaX,YACjB,CAACO;QACC,OAAOD,SAAS;YAAEC;QAAQ;IAC5B,GACA;QAACD;KAAS;IAGZ,IAAIF,kBAAkB;QACpB,OAAO;YACLG,SAASF,MAAME,OAAO,IAAI;YAC1BI;QACF;IACF;IAEA,OAAO;QACLJ,SAASE;QACTE,YAAYD;IACd;AACF"}
|
|
@@ -1,15 +1,20 @@
|
|
|
1
|
+
import { QueryParamConfig } from 'use-query-params';
|
|
1
2
|
import { TimeRangeValue, DurationString } from '@perses-dev/core';
|
|
2
3
|
import { TimeRange } from './TimeRangeProvider';
|
|
3
4
|
export type TimeOptionValue = Date | DurationString | null | undefined;
|
|
4
|
-
export declare function encodeTimeRangeValue(timeOptionValue: TimeOptionValue): string;
|
|
5
|
+
export declare function encodeTimeRangeValue(timeOptionValue: TimeOptionValue): string | null | undefined;
|
|
5
6
|
export declare function decodeTimeRangeValue(input: string | Array<string | null> | null | undefined): Date | DurationString | null | undefined;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Custom TimeRangeValue param type
|
|
9
|
+
* See: https://github.com/pbeshai/use-query-params/tree/master/packages/serialize-query-params#param-types
|
|
10
|
+
*/
|
|
11
|
+
export declare const TimeRangeParam: QueryParamConfig<TimeOptionValue, TimeOptionValue>;
|
|
12
|
+
export declare const timeRangeQueryConfig: {
|
|
13
|
+
start: QueryParamConfig<TimeOptionValue, TimeOptionValue>;
|
|
14
|
+
end: QueryParamConfig<TimeOptionValue, TimeOptionValue>;
|
|
10
15
|
};
|
|
11
|
-
export declare const
|
|
12
|
-
refresh:
|
|
16
|
+
export declare const refreshIntervalQueryConfig: {
|
|
17
|
+
refresh: QueryParamConfig<TimeOptionValue, TimeOptionValue>;
|
|
13
18
|
};
|
|
14
19
|
/**
|
|
15
20
|
* Gets the initial time range taking into account URL params and dashboard JSON duration
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-params.d.ts","sourceRoot":"","sources":["../../../src/runtime/TimeRangeProvider/query-params.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"query-params.d.ts","sourceRoot":"","sources":["../../../src/runtime/TimeRangeProvider/query-params.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,gBAAgB,EAAkB,MAAM,kBAAkB,CAAC;AAEpE,OAAO,EACL,cAAc,EAGd,cAAc,EAEf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC;AAwBvE,wBAAgB,oBAAoB,CAAC,eAAe,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAWhG;AAGD,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,SAAS,GACtD,IAAI,GAAG,cAAc,GAAG,IAAI,GAAG,SAAS,CAI1C;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,gBAAgB,CAAC,eAAe,EAAE,eAAe,CAQ7E,CAAC;AAEF,eAAO,MAAM,oBAAoB;;;CAGhC,CAAC;AAEF,eAAO,MAAM,0BAA0B;;CAEtC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,iBAAiB,EAAE,cAAc,GAAG,cAAc,CAiBrF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,gBAAgB,EAAE,cAAc,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,GAAG,cAAc,CAAC,CA6BlH;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,iBAAiB,EAAE,cAAc,GAAG,cAAc,CAc3F;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,sBAAsB,CAAC,EAAE,cAAc,GACtC,IAAI,CAAC,SAAS,EAAE,iBAAiB,GAAG,oBAAoB,CAAC,CAyB3D"}
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
import { useMemo, useCallback, useEffect, useState } from 'react';
|
|
14
|
+
import { useQueryParams } from 'use-query-params';
|
|
14
15
|
import { getUnixTime, isDate } from 'date-fns';
|
|
15
16
|
import { isRelativeTimeRange, isDurationString } from '@perses-dev/core';
|
|
16
|
-
import { createParser, useQueryStates } from 'nuqs';
|
|
17
17
|
/* Interprets an encoded string and returns either the string or null/undefined if not available */ function getEncodedValue(input, allowEmptyString) {
|
|
18
18
|
// '' or []
|
|
19
19
|
if (!input || input.length === 0 && (!allowEmptyString || allowEmptyString && input !== '')) {
|
|
@@ -30,7 +30,7 @@ import { createParser, useQueryStates } from 'nuqs';
|
|
|
30
30
|
}
|
|
31
31
|
/* Encodes individual TimeRangeValue as a string, depends on whether start is relative or absolute */ export function encodeTimeRangeValue(timeOptionValue) {
|
|
32
32
|
if (!timeOptionValue) {
|
|
33
|
-
return
|
|
33
|
+
return timeOptionValue;
|
|
34
34
|
}
|
|
35
35
|
if (typeof timeOptionValue === 'string') {
|
|
36
36
|
if (isDurationString(timeOptionValue)) {
|
|
@@ -44,28 +44,31 @@ import { createParser, useQueryStates } from 'nuqs';
|
|
|
44
44
|
if (!paramString) return null;
|
|
45
45
|
return isDurationString(paramString) ? paramString : new Date(Number(paramString));
|
|
46
46
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Custom TimeRangeValue param type
|
|
49
|
+
* See: https://github.com/pbeshai/use-query-params/tree/master/packages/serialize-query-params#param-types
|
|
50
|
+
*/ export const TimeRangeParam = {
|
|
51
|
+
encode: encodeTimeRangeValue,
|
|
52
|
+
decode: decodeTimeRangeValue,
|
|
53
|
+
equals: (valueA, valueB)=>{
|
|
51
54
|
if (valueA === valueB) return true;
|
|
52
55
|
if (!valueA || !valueB) return valueA === valueB;
|
|
53
56
|
return valueA.valueOf() === valueB.valueOf();
|
|
54
57
|
}
|
|
55
|
-
});
|
|
56
|
-
export const parseAsTimeRange = {
|
|
57
|
-
start: parseAsTimeRangeValue,
|
|
58
|
-
end: parseAsTimeRangeValue
|
|
59
58
|
};
|
|
60
|
-
export const
|
|
61
|
-
|
|
59
|
+
export const timeRangeQueryConfig = {
|
|
60
|
+
start: TimeRangeParam,
|
|
61
|
+
end: TimeRangeParam
|
|
62
|
+
};
|
|
63
|
+
export const refreshIntervalQueryConfig = {
|
|
64
|
+
refresh: TimeRangeParam
|
|
62
65
|
};
|
|
63
66
|
/**
|
|
64
67
|
* Gets the initial time range taking into account URL params and dashboard JSON duration
|
|
65
68
|
* Sets start query param if it is empty on page load
|
|
66
69
|
*/ export function useInitialTimeRange(dashboardDuration) {
|
|
67
|
-
const [query] =
|
|
68
|
-
|
|
70
|
+
const [query] = useQueryParams(timeRangeQueryConfig, {
|
|
71
|
+
updateType: 'replaceIn'
|
|
69
72
|
});
|
|
70
73
|
const { start, end } = query;
|
|
71
74
|
return useMemo(()=>{
|
|
@@ -96,8 +99,8 @@ export const parseAsRefreshInterval = {
|
|
|
96
99
|
/**
|
|
97
100
|
* Returns time range getter and setter, taking the URL query params.
|
|
98
101
|
*/ export function useTimeRangeParams(initialTimeRange) {
|
|
99
|
-
const [query, setQuery] =
|
|
100
|
-
|
|
102
|
+
const [query, setQuery] = useQueryParams(timeRangeQueryConfig, {
|
|
103
|
+
updateType: 'replaceIn'
|
|
101
104
|
});
|
|
102
105
|
// determine whether initial param had previously been populated to fix back btn
|
|
103
106
|
const [paramsLoaded, setParamsLoaded] = useState(false);
|
|
@@ -140,8 +143,8 @@ export const parseAsRefreshInterval = {
|
|
|
140
143
|
* Gets the initial refresh interval taking into account URL params and dashboard JSON duration
|
|
141
144
|
* Sets refresh query param if it is empty on page load
|
|
142
145
|
*/ export function useInitialRefreshInterval(dashboardDuration) {
|
|
143
|
-
const [query] =
|
|
144
|
-
|
|
146
|
+
const [query] = useQueryParams(refreshIntervalQueryConfig, {
|
|
147
|
+
updateType: 'replaceIn'
|
|
145
148
|
});
|
|
146
149
|
const { refresh } = query;
|
|
147
150
|
return useMemo(()=>{
|
|
@@ -162,8 +165,8 @@ export const parseAsRefreshInterval = {
|
|
|
162
165
|
/**
|
|
163
166
|
* Returns refresh interval getter and setter, taking the URL query params.
|
|
164
167
|
*/ export function useSetRefreshIntervalParams(initialRefreshInterval) {
|
|
165
|
-
const [query, setQuery] =
|
|
166
|
-
|
|
168
|
+
const [query, setQuery] = useQueryParams(refreshIntervalQueryConfig, {
|
|
169
|
+
updateType: 'replaceIn'
|
|
167
170
|
});
|
|
168
171
|
// determine whether initial param had previously been populated to fix back btn
|
|
169
172
|
const [paramsLoaded, setParamsLoaded] = useState(false);
|