@grafana/scenes 5.13.0--canary.878.10702174754.0 β†’ 5.13.1--canary.889.10720020573.0

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,29 @@
1
+ # v5.13.0 (Wed Sep 04 2024)
2
+
3
+ ### Release Notes
4
+
5
+ #### UrlSync: Support browser history steps, remove singleton ([#878](https://github.com/grafana/scenes/pull/878))
6
+
7
+ getUrlSyncManager is no longer exported as UrlSyncManager is now no longer global singleton but local to the UrlSyncContextProvider.
8
+ If you called getUrlSyncManager().getUrlState that util function is available via the exported object sceneUtils.
9
+
10
+ ---
11
+
12
+ #### πŸš€ Enhancement
13
+
14
+ - UrlSync: Support browser history steps, remove singleton [#878](https://github.com/grafana/scenes/pull/878) ([@torkelo](https://github.com/torkelo))
15
+
16
+ #### πŸ› Bug Fix
17
+
18
+ - chore: export SceneDataTransformerState [#888](https://github.com/grafana/scenes/pull/888) ([@jewbetcha](https://github.com/jewbetcha))
19
+
20
+ #### Authors: 2
21
+
22
+ - Coleman Rollins ([@jewbetcha](https://github.com/jewbetcha))
23
+ - Torkel Γ–degaard ([@torkelo](https://github.com/torkelo))
24
+
25
+ ---
26
+
1
27
  # v5.12.0 (Tue Sep 03 2024)
2
28
 
3
29
  #### πŸš€ Enhancement
@@ -29,7 +29,7 @@ function AdHocFilterPill({ filter, model, readOnly }) {
29
29
  const [shouldFocus, setShouldFocus] = useState(false);
30
30
  const pillWrapperRef = useRef(null);
31
31
  const keyLabel = (_a = filter.keyLabel) != null ? _a : filter.key;
32
- const valueLabel = (_c = (_b = filter.valueLabels) == null ? void 0 : _b[0]) != null ? _c : filter.value;
32
+ const valueLabel = ((_b = filter.valueLabels) == null ? void 0 : _b.join(", ")) || ((_c = filter.values) == null ? void 0 : _c.join(", ")) || filter.value;
33
33
  const handleChangeViewMode = useCallback(
34
34
  (event) => {
35
35
  event == null ? void 0 : event.stopPropagation();
@@ -61,7 +61,9 @@ function AdHocFilterPill({ filter, model, readOnly }) {
61
61
  "aria-label": `Edit filter with key ${keyLabel}`,
62
62
  tabIndex: 0,
63
63
  ref: pillWrapperRef
64
- }, /* @__PURE__ */ React.createElement("span", null, keyLabel, " ", filter.operator, " ", valueLabel), !readOnly ? /* @__PURE__ */ React.createElement(IconButton, {
64
+ }, /* @__PURE__ */ React.createElement("span", {
65
+ className: styles.pillText
66
+ }, keyLabel, " ", filter.operator, " ", valueLabel), !readOnly ? /* @__PURE__ */ React.createElement(IconButton, {
65
67
  onClick: (e) => {
66
68
  e.stopPropagation();
67
69
  model._removeFilter(filter);
@@ -117,6 +119,9 @@ const getStyles = (theme) => ({
117
119
  "&:hover": {
118
120
  color: theme.colors.text.primary
119
121
  }
122
+ }),
123
+ pillText: css({
124
+ whiteSpace: "break-spaces"
120
125
  })
121
126
  });
122
127
 
@@ -1 +1 @@
1
- {"version":3,"file":"AdHocFilterPill.js","sources":["../../../../../src/variables/adhoc/AdHocFiltersCombobox/AdHocFilterPill.tsx"],"sourcesContent":["import { css, cx } from '@emotion/css';\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { useStyles2, IconButton } from '@grafana/ui';\nimport React, { useState, useRef, useCallback, useEffect } from 'react';\nimport { AdHocCombobox } from './AdHocFiltersCombobox';\nimport { AdHocFilterWithLabels, AdHocFiltersVariable } from '../AdHocFiltersVariable';\n\ninterface Props {\n filter: AdHocFilterWithLabels;\n model: AdHocFiltersVariable;\n readOnly?: boolean;\n}\n\nexport function AdHocFilterPill({ filter, model, readOnly }: Props) {\n const styles = useStyles2(getStyles);\n const [viewMode, setViewMode] = useState(true);\n const [shouldFocus, setShouldFocus] = useState(false);\n const pillWrapperRef = useRef<HTMLDivElement>(null);\n\n const keyLabel = filter.keyLabel ?? filter.key;\n const valueLabel = filter.valueLabels?.[0] ?? filter.value;\n\n const handleChangeViewMode = useCallback(\n (event?: React.MouseEvent) => {\n event?.stopPropagation();\n if (readOnly) {\n return;\n }\n\n setShouldFocus(!viewMode);\n setViewMode(!viewMode);\n },\n [readOnly, viewMode]\n );\n\n useEffect(() => {\n if (shouldFocus) {\n pillWrapperRef.current?.focus();\n setShouldFocus(false);\n }\n }, [shouldFocus]);\n\n if (viewMode) {\n return (\n <div\n className={cx(styles.combinedFilterPill, { [styles.readOnlyCombinedFilter]: readOnly })}\n onClick={handleChangeViewMode}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n handleChangeViewMode();\n }\n }}\n role=\"button\"\n aria-label={`Edit filter with key ${keyLabel}`}\n tabIndex={0}\n ref={pillWrapperRef}\n >\n <span>\n {keyLabel} {filter.operator} {valueLabel}\n </span>\n {!readOnly ? (\n <IconButton\n onClick={(e) => {\n e.stopPropagation();\n model._removeFilter(filter);\n }}\n onKeyDownCapture={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n e.stopPropagation();\n model._removeFilter(filter);\n }\n }}\n name=\"times\"\n size=\"md\"\n className={styles.removeButton}\n tooltip={`Remove filter with key ${keyLabel}`}\n />\n ) : null}\n </div>\n );\n }\n\n return <AdHocCombobox filter={filter} model={model} handleChangeViewMode={handleChangeViewMode} />;\n}\n\nconst getStyles = (theme: GrafanaTheme2) => ({\n combinedFilterPill: css({\n display: 'flex',\n alignItems: 'center',\n background: theme.colors.action.selected,\n borderRadius: theme.shape.radius.default,\n border: `1px solid ${theme.colors.border.weak}`,\n padding: theme.spacing(0.125, 0, 0.125, 1),\n color: theme.colors.text.primary,\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n minHeight: theme.spacing(2.75),\n ...theme.typography.bodySmall,\n fontWeight: theme.typography.fontWeightBold,\n cursor: 'pointer',\n\n '&:hover': {\n background: theme.colors.action.hover,\n },\n }),\n readOnlyCombinedFilter: css({\n paddingRight: theme.spacing(1),\n cursor: 'text',\n '&:hover': {\n background: theme.colors.action.selected,\n },\n }),\n removeButton: css({\n marginInline: theme.spacing(0.5),\n cursor: 'pointer',\n '&:hover': {\n color: theme.colors.text.primary,\n },\n }),\n});\n"],"names":["_a"],"mappings":"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"}
1
+ {"version":3,"file":"AdHocFilterPill.js","sources":["../../../../../src/variables/adhoc/AdHocFiltersCombobox/AdHocFilterPill.tsx"],"sourcesContent":["import { css, cx } from '@emotion/css';\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { useStyles2, IconButton } from '@grafana/ui';\nimport React, { useState, useRef, useCallback, useEffect } from 'react';\nimport { AdHocCombobox } from './AdHocFiltersCombobox';\nimport { AdHocFilterWithLabels, AdHocFiltersVariable } from '../AdHocFiltersVariable';\n\ninterface Props {\n filter: AdHocFilterWithLabels;\n model: AdHocFiltersVariable;\n readOnly?: boolean;\n}\n\nexport function AdHocFilterPill({ filter, model, readOnly }: Props) {\n const styles = useStyles2(getStyles);\n const [viewMode, setViewMode] = useState(true);\n const [shouldFocus, setShouldFocus] = useState(false);\n const pillWrapperRef = useRef<HTMLDivElement>(null);\n\n const keyLabel = filter.keyLabel ?? filter.key;\n //@ts-expect-error\n const valueLabel = filter.valueLabels?.join(', ') || filter.values?.join(', ') || filter.value;\n\n const handleChangeViewMode = useCallback(\n (event?: React.MouseEvent) => {\n event?.stopPropagation();\n if (readOnly) {\n return;\n }\n\n setShouldFocus(!viewMode);\n setViewMode(!viewMode);\n },\n [readOnly, viewMode]\n );\n\n useEffect(() => {\n if (shouldFocus) {\n pillWrapperRef.current?.focus();\n setShouldFocus(false);\n }\n }, [shouldFocus]);\n\n if (viewMode) {\n return (\n <div\n className={cx(styles.combinedFilterPill, { [styles.readOnlyCombinedFilter]: readOnly })}\n onClick={handleChangeViewMode}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n handleChangeViewMode();\n }\n }}\n role=\"button\"\n aria-label={`Edit filter with key ${keyLabel}`}\n tabIndex={0}\n ref={pillWrapperRef}\n >\n <span className={styles.pillText}>\n {keyLabel} {filter.operator} {valueLabel}\n </span>\n {!readOnly ? (\n <IconButton\n onClick={(e) => {\n e.stopPropagation();\n model._removeFilter(filter);\n }}\n onKeyDownCapture={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n e.stopPropagation();\n model._removeFilter(filter);\n }\n }}\n name=\"times\"\n size=\"md\"\n className={styles.removeButton}\n tooltip={`Remove filter with key ${keyLabel}`}\n />\n ) : null}\n </div>\n );\n }\n\n return <AdHocCombobox filter={filter} model={model} handleChangeViewMode={handleChangeViewMode} />;\n}\n\nconst getStyles = (theme: GrafanaTheme2) => ({\n combinedFilterPill: css({\n display: 'flex',\n alignItems: 'center',\n background: theme.colors.action.selected,\n borderRadius: theme.shape.radius.default,\n border: `1px solid ${theme.colors.border.weak}`,\n padding: theme.spacing(0.125, 0, 0.125, 1),\n color: theme.colors.text.primary,\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n minHeight: theme.spacing(2.75),\n ...theme.typography.bodySmall,\n fontWeight: theme.typography.fontWeightBold,\n cursor: 'pointer',\n\n '&:hover': {\n background: theme.colors.action.hover,\n },\n }),\n readOnlyCombinedFilter: css({\n paddingRight: theme.spacing(1),\n cursor: 'text',\n '&:hover': {\n background: theme.colors.action.selected,\n },\n }),\n removeButton: css({\n marginInline: theme.spacing(0.5),\n cursor: 'pointer',\n '&:hover': {\n color: theme.colors.text.primary,\n },\n }),\n pillText: css({\n whiteSpace: 'break-spaces',\n }),\n});\n"],"names":["_a"],"mappings":"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"}
@@ -1,10 +1,11 @@
1
- import React, { forwardRef, useState, useId, useRef, useMemo, useCallback, useImperativeHandle, useEffect, useLayoutEffect } from 'react';
1
+ import React, { forwardRef, useState, useMemo, useId, useRef, useCallback, useImperativeHandle, useEffect, useLayoutEffect } from 'react';
2
2
  import { FloatingPortal, FloatingFocusManager } from '@floating-ui/react';
3
- import { useStyles2, Spinner, Text } from '@grafana/ui';
3
+ import { useStyles2, Spinner, Text, Button, Icon } from '@grafana/ui';
4
4
  import { cx, css } from '@emotion/css';
5
+ import { OPERATORS } from '../AdHocFiltersVariable.js';
5
6
  import { useVirtualizer } from '@tanstack/react-virtual';
6
- import { LoadingOptionsPlaceholder, OptionsErrorPlaceholder, NoOptionsPlaceholder, DropdownItem } from './DropdownItem.js';
7
- import { fuzzySearchOptions, flattenOptionGroups, setupDropdownAccessibility, VIRTUAL_LIST_ITEM_HEIGHT, VIRTUAL_LIST_OVERSCAN, generateFilterUpdatePayload, switchToNextInputType, switchInputType, ERROR_STATE_DROPDOWN_WIDTH } from './utils.js';
7
+ import { LoadingOptionsPlaceholder, OptionsErrorPlaceholder, NoOptionsPlaceholder, DropdownItem, MultiValueApplyButton } from './DropdownItem.js';
8
+ import { fuzzySearchOptions, flattenOptionGroups, setupDropdownAccessibility, VIRTUAL_LIST_ITEM_HEIGHT_WITH_DESCRIPTION, VIRTUAL_LIST_ITEM_HEIGHT, VIRTUAL_LIST_OVERSCAN, generateFilterUpdatePayload, switchToNextInputType, switchInputType, ERROR_STATE_DROPDOWN_WIDTH } from './utils.js';
8
9
  import { handleOptionGroups } from '../../utils.js';
9
10
  import { useFloatingInteractions } from './useFloatingInteractions.js';
10
11
 
@@ -37,6 +38,14 @@ const AdHocCombobox = forwardRef(function AdHocCombobox2({ filter, model, isAlwa
37
38
  const [activeIndex, setActiveIndex] = useState(null);
38
39
  const [filterInputType, setInputType] = useState(!isAlwaysWip ? "value" : "key");
39
40
  const styles = useStyles2(getStyles);
41
+ const [filterMultiValues, setFilterMultiValues] = useState([]);
42
+ const [_, setForceRefresh] = useState({});
43
+ const multiValueOperators = useMemo(
44
+ () => OPERATORS.reduce((acc, operator) => operator.isMulti ? [...acc, operator.value] : acc, []),
45
+ []
46
+ );
47
+ const hasMultiValueOperator = multiValueOperators.includes((filter == null ? void 0 : filter.operator) || "");
48
+ const isMultiValueEdit = hasMultiValueOperator && filterInputType === "value";
40
49
  const operatorIdentifier = useId();
41
50
  const listRef = useRef([]);
42
51
  const disabledIndicesRef = useRef([]);
@@ -48,22 +57,60 @@ const AdHocCombobox = forwardRef(function AdHocCombobox2({ filter, model, isAlwa
48
57
  setInputValue("");
49
58
  }
50
59
  }, [model, isAlwaysWip]);
60
+ const handleMultiValueUpdate = useCallback(
61
+ (model2, filter2, filterMultiValues2) => {
62
+ if (filterMultiValues2.length) {
63
+ const valueLabels = [];
64
+ const values = [];
65
+ filterMultiValues2.forEach((item) => {
66
+ var _a2;
67
+ valueLabels.push((_a2 = item.label) != null ? _a2 : item.value);
68
+ values.push(item.value);
69
+ });
70
+ model2._updateFilter(filter2, { valueLabels, values, value: values[0] });
71
+ setFilterMultiValues([]);
72
+ }
73
+ setTimeout(() => {
74
+ var _a2;
75
+ return (_a2 = refs.domReference.current) == null ? void 0 : _a2.focus();
76
+ });
77
+ },
78
+ []
79
+ );
80
+ const handleAddMultiValue = useCallback((selectedItem) => {
81
+ setFilterMultiValues((items) => {
82
+ if (items.some((item) => item.value === selectedItem.value)) {
83
+ return items.filter((item) => item.value !== selectedItem.value);
84
+ }
85
+ return [...items, selectedItem];
86
+ });
87
+ }, []);
88
+ const handleRemoveMultiValue = useCallback(
89
+ (item) => setFilterMultiValues((selected) => selected.filter((option) => option.value !== item.value)),
90
+ []
91
+ );
51
92
  const onOpenChange = useCallback(
52
- (nextOpen, _, reason) => {
93
+ (nextOpen, _2, reason) => {
53
94
  setOpen(nextOpen);
54
95
  if (reason && ["outside-press", "escape-key"].includes(reason)) {
96
+ if (isMultiValueEdit) {
97
+ handleMultiValueUpdate(model, filter, filterMultiValues);
98
+ }
55
99
  handleResetWip();
56
100
  handleChangeViewMode == null ? void 0 : handleChangeViewMode();
57
101
  }
58
102
  },
59
- [handleChangeViewMode, handleResetWip]
103
+ [filter, filterMultiValues, handleChangeViewMode, handleMultiValueUpdate, handleResetWip, isMultiValueEdit, model]
60
104
  );
105
+ const outsidePressIdsToIgnore = useMemo(() => {
106
+ return [operatorIdentifier, ...filterMultiValues.map((item, i) => `${item.value}-${i}`)];
107
+ }, [operatorIdentifier, filterMultiValues]);
61
108
  const { refs, floatingStyles, context, getReferenceProps, getFloatingProps, getItemProps } = useFloatingInteractions({
62
109
  open,
63
110
  onOpenChange,
64
111
  activeIndex,
65
112
  setActiveIndex,
66
- operatorIdentifier,
113
+ outsidePressIdsToIgnore,
67
114
  listRef,
68
115
  disabledIndicesRef
69
116
  });
@@ -114,24 +161,41 @@ const AdHocCombobox = forwardRef(function AdHocCombobox2({ filter, model, isAlwa
114
161
  const rowVirtualizer = useVirtualizer({
115
162
  count: filteredDropDownItems.length,
116
163
  getScrollElement: () => refs.floating.current,
117
- estimateSize: () => VIRTUAL_LIST_ITEM_HEIGHT,
164
+ estimateSize: (index) => filteredDropDownItems[index].description ? VIRTUAL_LIST_ITEM_HEIGHT_WITH_DESCRIPTION : VIRTUAL_LIST_ITEM_HEIGHT,
118
165
  overscan: VIRTUAL_LIST_OVERSCAN
119
166
  });
120
167
  const handleBackspaceInput = useCallback(
121
- (event) => {
122
- if (event.key === "Backspace" && !inputValue && filterInputType === "key") {
123
- model._removeLastFilter();
124
- handleFetchOptions(filterInputType);
168
+ (event, multiValueEdit) => {
169
+ if (event.key === "Backspace" && !inputValue) {
170
+ if (multiValueEdit) {
171
+ setFilterMultiValues((items) => {
172
+ const updated = [...items];
173
+ updated.splice(-1, 1);
174
+ return updated;
175
+ });
176
+ } else if (filterInputType === "key") {
177
+ model._removeLastFilter();
178
+ handleFetchOptions(filterInputType);
179
+ }
125
180
  }
126
181
  },
127
- [inputValue, filterInputType]
182
+ [inputValue, filterInputType, model, handleFetchOptions]
183
+ );
184
+ const handleTabInput = useCallback(
185
+ (event, multiValueEdit) => {
186
+ var _a2;
187
+ if (event.key === "Tab" && !event.shiftKey) {
188
+ if (multiValueEdit) {
189
+ event.preventDefault();
190
+ handleMultiValueUpdate(model, filter, filterMultiValues);
191
+ (_a2 = refs.domReference.current) == null ? void 0 : _a2.focus();
192
+ }
193
+ handleChangeViewMode == null ? void 0 : handleChangeViewMode();
194
+ handleResetWip();
195
+ }
196
+ },
197
+ [filter, filterMultiValues, handleChangeViewMode, handleMultiValueUpdate, handleResetWip, model, refs.domReference]
128
198
  );
129
- const handleTabInput = useCallback((event) => {
130
- if (event.key === "Tab" && !event.shiftKey) {
131
- handleChangeViewMode == null ? void 0 : handleChangeViewMode();
132
- handleResetWip();
133
- }
134
- }, []);
135
199
  const handleShiftTabInput = useCallback((event) => {
136
200
  if (event.key === "Tab" && event.shiftKey) {
137
201
  handleChangeViewMode == null ? void 0 : handleChangeViewMode();
@@ -139,18 +203,32 @@ const AdHocCombobox = forwardRef(function AdHocCombobox2({ filter, model, isAlwa
139
203
  }
140
204
  }, []);
141
205
  const handleEnterInput = useCallback(
142
- (event) => {
206
+ (event, multiValueEdit) => {
143
207
  if (event.key === "Enter" && activeIndex != null) {
144
208
  if (!filteredDropDownItems[activeIndex]) {
145
209
  return;
146
210
  }
147
- model._updateFilter(filter, generateFilterUpdatePayload(filterInputType, filteredDropDownItems[activeIndex]));
211
+ const selectedItem = filteredDropDownItems[activeIndex];
212
+ if (multiValueEdit) {
213
+ handleAddMultiValue(selectedItem);
214
+ } else {
215
+ model._updateFilter(filter, generateFilterUpdatePayload(filterInputType, selectedItem));
216
+ switchToNextInputType(filterInputType, setInputType, handleChangeViewMode, refs.domReference.current);
217
+ setActiveIndex(0);
218
+ }
148
219
  setInputValue("");
149
- setActiveIndex(0);
150
- switchToNextInputType(filterInputType, setInputType, handleChangeViewMode, refs.domReference.current);
151
220
  }
152
221
  },
153
- [activeIndex, filter, filterInputType, filteredDropDownItems, model]
222
+ [
223
+ activeIndex,
224
+ filter,
225
+ filterInputType,
226
+ filteredDropDownItems,
227
+ handleAddMultiValue,
228
+ handleChangeViewMode,
229
+ model,
230
+ refs.domReference
231
+ ]
154
232
  );
155
233
  useEffect(() => {
156
234
  if (open) {
@@ -158,13 +236,34 @@ const AdHocCombobox = forwardRef(function AdHocCombobox2({ filter, model, isAlwa
158
236
  }
159
237
  }, [open, filterInputType]);
160
238
  useEffect(() => {
161
- var _a2;
239
+ var _a2, _b2;
162
240
  if (!isAlwaysWip) {
163
241
  setInputType("value");
164
242
  setInputValue("");
165
- (_a2 = refs.domReference.current) == null ? void 0 : _a2.focus();
243
+ if (hasMultiValueOperator && ((_a2 = filter == null ? void 0 : filter.values) == null ? void 0 : _a2.length)) {
244
+ const multiValueOptions = filter.values.reduce(
245
+ (acc, value, i) => {
246
+ var _a3;
247
+ return [
248
+ ...acc,
249
+ {
250
+ label: ((_a3 = filter.valueLabels) == null ? void 0 : _a3[i]) || value,
251
+ value
252
+ }
253
+ ];
254
+ },
255
+ []
256
+ );
257
+ setFilterMultiValues(multiValueOptions);
258
+ }
259
+ (_b2 = refs.domReference.current) == null ? void 0 : _b2.focus();
166
260
  }
167
261
  }, []);
262
+ useEffect(() => {
263
+ if (isMultiValueEdit && filterMultiValues) {
264
+ setTimeout(() => setForceRefresh({}));
265
+ }
266
+ }, [filterMultiValues, isMultiValueEdit]);
168
267
  useLayoutEffect(() => {
169
268
  var _a2, _b2;
170
269
  if (activeIndex !== null && rowVirtualizer.range && (activeIndex > ((_a2 = rowVirtualizer.range) == null ? void 0 : _a2.endIndex) || activeIndex < ((_b2 = rowVirtualizer.range) == null ? void 0 : _b2.startIndex))) {
@@ -195,9 +294,12 @@ const AdHocCombobox = forwardRef(function AdHocCombobox2({ filter, model, isAlwa
195
294
  switchInputType("operator", setInputType, void 0, refs.domReference.current);
196
295
  }
197
296
  }
198
- }, filter.operator) : null, (filter == null ? void 0 : filter.key) && (filter == null ? void 0 : filter.operator) && (filter == null ? void 0 : filter.value) && !["operator", "value"].includes(filterInputType) ? /* @__PURE__ */ React.createElement("div", {
199
- className: cx(styles.basePill, styles.valuePill)
200
- }, valueLabel) : null) : null, /* @__PURE__ */ React.createElement("input", __spreadProps(__spreadValues({}, getReferenceProps({
297
+ }, filter.operator) : null, isMultiValueEdit ? filterMultiValues.map((item, i) => /* @__PURE__ */ React.createElement(MultiValuePill, {
298
+ key: `${item.value}-${i}`,
299
+ item,
300
+ index: i,
301
+ handleRemoveMultiValue
302
+ })) : null) : null, /* @__PURE__ */ React.createElement("input", __spreadProps(__spreadValues({}, getReferenceProps({
201
303
  ref: refs.setReference,
202
304
  onChange,
203
305
  value: inputValue,
@@ -211,9 +313,9 @@ const AdHocCombobox = forwardRef(function AdHocCombobox2({ filter, model, isAlwa
211
313
  if (filterInputType === "operator") {
212
314
  handleShiftTabInput(event);
213
315
  }
214
- handleBackspaceInput(event);
215
- handleTabInput(event);
216
- handleEnterInput(event);
316
+ handleBackspaceInput(event, isMultiValueEdit);
317
+ handleTabInput(event, isMultiValueEdit);
318
+ handleEnterInput(event, isMultiValueEdit);
217
319
  }
218
320
  })), {
219
321
  className: cx(styles.inputStyle, { [styles.loadingInputPadding]: !optionsLoading }),
@@ -233,7 +335,7 @@ const AdHocCombobox = forwardRef(function AdHocCombobox2({ filter, model, isAlwa
233
335
  initialFocus: -1,
234
336
  visuallyHiddenDismiss: true,
235
337
  modal: false
236
- }, /* @__PURE__ */ React.createElement("div", {
338
+ }, /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
237
339
  style: __spreadProps(__spreadValues({}, floatingStyles), {
238
340
  width: `${optionsError ? ERROR_STATE_DROPDOWN_WIDTH : maxOptionWidth}px`
239
341
  }),
@@ -274,17 +376,24 @@ const AdHocCombobox = forwardRef(function AdHocCombobox2({ filter, model, isAlwa
274
376
  listRef.current[index] = node;
275
377
  },
276
378
  onClick(event) {
379
+ var _a3;
277
380
  if (filterInputType !== "value") {
278
381
  event.stopPropagation();
279
382
  }
280
- model._updateFilter(filter, generateFilterUpdatePayload(filterInputType, item));
281
- setInputValue("");
282
- switchToNextInputType(
283
- filterInputType,
284
- setInputType,
285
- handleChangeViewMode,
286
- refs.domReference.current
287
- );
383
+ if (isMultiValueEdit) {
384
+ event.stopPropagation();
385
+ handleAddMultiValue(item);
386
+ (_a3 = refs.domReference.current) == null ? void 0 : _a3.focus();
387
+ } else {
388
+ model._updateFilter(filter, generateFilterUpdatePayload(filterInputType, item));
389
+ setInputValue("");
390
+ switchToNextInputType(
391
+ filterInputType,
392
+ setInputType,
393
+ handleChangeViewMode,
394
+ refs.domReference.current
395
+ );
396
+ }
288
397
  }
289
398
  })), {
290
399
  active: activeIndex === index,
@@ -294,19 +403,56 @@ const AdHocCombobox = forwardRef(function AdHocCombobox2({ filter, model, isAlwa
294
403
  transform: `translateY(${virtualItem.start}px)`
295
404
  },
296
405
  "aria-setsize": filteredDropDownItems.length,
297
- "aria-posinset": virtualItem.index + 1
298
- }), item.isCustom ? "Use custom value: " : "", " ", (_a2 = item.label) != null ? _a2 : item.value);
299
- }))))));
406
+ "aria-posinset": virtualItem.index + 1,
407
+ isMultiValueEdit,
408
+ checked: filterMultiValues.some((val) => val.value === item.value)
409
+ }), /* @__PURE__ */ React.createElement("span", null, item.isCustom ? "Use custom value: " : "", " ", (_a2 = item.label) != null ? _a2 : item.value), item.description ? /* @__PURE__ */ React.createElement("div", {
410
+ className: styles.descriptionText
411
+ }, item.description) : null);
412
+ }))), isMultiValueEdit && !optionsLoading && !optionsError && filteredDropDownItems.length ? /* @__PURE__ */ React.createElement(MultiValueApplyButton, {
413
+ onClick: () => handleMultiValueUpdate(model, filter, filterMultiValues),
414
+ floatingElement: refs.floating.current,
415
+ maxOptionWidth
416
+ }) : null))));
300
417
  });
418
+ const MultiValuePill = ({ item, handleRemoveMultiValue, index }) => {
419
+ var _a, _b;
420
+ const styles = useStyles2(getStyles);
421
+ return /* @__PURE__ */ React.createElement("div", {
422
+ className: cx(styles.basePill, styles.valuePill)
423
+ }, /* @__PURE__ */ React.createElement("span", null, " ", (_a = item.label) != null ? _a : item.value), /* @__PURE__ */ React.createElement(Button, {
424
+ onClick: (e) => {
425
+ e.stopPropagation();
426
+ e.preventDefault();
427
+ handleRemoveMultiValue(item);
428
+ },
429
+ onKeyDownCapture: (e) => {
430
+ if (e.key === "Enter") {
431
+ e.preventDefault();
432
+ e.stopPropagation();
433
+ handleRemoveMultiValue(item);
434
+ }
435
+ },
436
+ fill: "text",
437
+ size: "sm",
438
+ variant: "secondary",
439
+ className: styles.removeButton,
440
+ tooltip: `Remove filter value - ${(_b = item.label) != null ? _b : item.value}`
441
+ }, /* @__PURE__ */ React.createElement(Icon, {
442
+ name: "times",
443
+ size: "md",
444
+ id: `${item.value}-${index}`
445
+ })));
446
+ };
301
447
  const getStyles = (theme) => ({
302
448
  comboboxWrapper: css({
303
449
  display: "flex",
304
- flexWrap: "nowrap"
450
+ flexWrap: "wrap"
305
451
  }),
306
452
  pillWrapper: css({
307
453
  display: "flex",
308
454
  alignItems: "center",
309
- whiteSpace: "nowrap"
455
+ flexWrap: "wrap"
310
456
  }),
311
457
  basePill: css(__spreadProps(__spreadValues({
312
458
  display: "flex",
@@ -331,7 +477,8 @@ const getStyles = (theme) => ({
331
477
  }
332
478
  }),
333
479
  valuePill: css({
334
- background: theme.colors.action.selected
480
+ background: theme.colors.action.selected,
481
+ padding: theme.spacing(0.125, 0, 0.125, 1)
335
482
  }),
336
483
  dropdownWrapper: css({
337
484
  backgroundColor: theme.colors.background.primary,
@@ -364,6 +511,25 @@ const getStyles = (theme) => ({
364
511
  "&:not(:first-child)": {
365
512
  borderTop: `1px solid ${theme.colors.border.weak}`
366
513
  }
514
+ }),
515
+ removeButton: css({
516
+ marginInline: theme.spacing(0.5),
517
+ height: "100%",
518
+ padding: 0,
519
+ cursor: "pointer",
520
+ "&:hover": {
521
+ color: theme.colors.text.primary
522
+ }
523
+ }),
524
+ descriptionText: css(__spreadProps(__spreadValues({}, theme.typography.bodySmall), {
525
+ color: theme.colors.text.secondary,
526
+ paddingTop: theme.spacing(0.5)
527
+ })),
528
+ multiValueApply: css({
529
+ position: "absolute",
530
+ top: 0,
531
+ left: 0,
532
+ display: "flex"
367
533
  })
368
534
  });
369
535