@navikt/ds-react 8.5.2 → 8.7.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/cjs/data/drag-and-drop/item/DataDragAndDropItem.d.ts +27 -0
- package/cjs/data/drag-and-drop/item/DataDragAndDropItem.js +91 -0
- package/cjs/data/drag-and-drop/item/DataDragAndDropItem.js.map +1 -0
- package/cjs/data/drag-and-drop/root/DataDragAndDrop.context.d.ts +5 -0
- package/cjs/data/drag-and-drop/root/DataDragAndDrop.context.js +6 -0
- package/cjs/data/drag-and-drop/root/DataDragAndDrop.context.js.map +1 -0
- package/cjs/data/drag-and-drop/root/DataDragAndDropRoot.d.ts +24 -0
- package/cjs/data/drag-and-drop/root/DataDragAndDropRoot.js +111 -0
- package/cjs/data/drag-and-drop/root/DataDragAndDropRoot.js.map +1 -0
- package/cjs/data/table/helpers/table-keyboard.d.ts +1 -0
- package/cjs/data/table/helpers/table-keyboard.js +5 -3
- package/cjs/data/table/helpers/table-keyboard.js.map +1 -1
- package/cjs/data/table/root/DataTableRoot.context.d.ts +8 -0
- package/cjs/data/table/root/DataTableRoot.context.js +11 -0
- package/cjs/data/table/root/DataTableRoot.context.js.map +1 -0
- package/cjs/data/table/root/DataTableRoot.js +5 -3
- package/cjs/data/table/root/DataTableRoot.js.map +1 -1
- package/cjs/data/table/th/DataTableTh.d.ts +18 -2
- package/cjs/data/table/th/DataTableTh.js +45 -20
- package/cjs/data/table/th/DataTableTh.js.map +1 -1
- package/cjs/data/table/tr/DataTableTr.js +9 -2
- package/cjs/data/table/tr/DataTableTr.js.map +1 -1
- package/cjs/data/token-filter/AutoSuggest.d.ts +6 -2
- package/cjs/data/token-filter/AutoSuggest.js +46 -14
- package/cjs/data/token-filter/AutoSuggest.js.map +1 -1
- package/cjs/data/token-filter/AutoSuggest.types.d.ts +0 -1
- package/cjs/data/token-filter/TokenFilter.d.ts +10 -5
- package/cjs/data/token-filter/TokenFilter.js +110 -48
- package/cjs/data/token-filter/TokenFilter.js.map +1 -1
- package/cjs/data/token-filter/TokenFilter.types.d.ts +51 -35
- package/cjs/data/token-filter/helpers/generate-autocomplete-options.d.ts +3 -6
- package/cjs/data/token-filter/helpers/generate-autocomplete-options.js +24 -37
- package/cjs/data/token-filter/helpers/generate-autocomplete-options.js.map +1 -1
- package/cjs/data/token-filter/helpers/operators.d.ts +6 -6
- package/cjs/data/token-filter/helpers/operators.js +3 -4
- package/cjs/data/token-filter/helpers/operators.js.map +1 -1
- package/cjs/data/token-filter/helpers/parse-query-text.d.ts +2 -20
- package/cjs/data/token-filter/helpers/parse-query-text.js +1 -1
- package/cjs/data/token-filter/helpers/parse-query-text.js.map +1 -1
- package/cjs/data/token-filter/helpers/query-builder.d.ts +2 -2
- package/cjs/data/token-filter/helpers/query-builder.js.map +1 -1
- package/cjs/date/Date.Dialog.d.ts +5 -1
- package/cjs/date/Date.Dialog.js +6 -2
- package/cjs/date/Date.Dialog.js.map +1 -1
- package/cjs/date/datepicker/DatePicker.js +3 -2
- package/cjs/date/datepicker/DatePicker.js.map +1 -1
- package/cjs/date/datepicker/hooks/useDatepicker.js +5 -2
- package/cjs/date/datepicker/hooks/useDatepicker.js.map +1 -1
- package/cjs/date/datepicker/hooks/useRangeDatepicker.js +3 -1
- package/cjs/date/datepicker/hooks/useRangeDatepicker.js.map +1 -1
- package/cjs/date/datepicker/parts/DatePicker.Months.d.ts +2 -1
- package/cjs/date/datepicker/parts/DatePicker.Months.js +3 -3
- package/cjs/date/datepicker/parts/DatePicker.Months.js.map +1 -1
- package/cjs/date/datepicker/parts/DatePicker.RDP.d.ts +5 -1
- package/cjs/date/datepicker/parts/DatePicker.RDP.js +2 -2
- package/cjs/date/datepicker/parts/DatePicker.RDP.js.map +1 -1
- package/cjs/date/monthpicker/MonthPicker.js +3 -2
- package/cjs/date/monthpicker/MonthPicker.js.map +1 -1
- package/cjs/date/monthpicker/hooks/useMonthPicker.js +3 -1
- package/cjs/date/monthpicker/hooks/useMonthPicker.js.map +1 -1
- package/cjs/date/monthpicker/parts/MonthPicker.Caption.d.ts +4 -1
- package/cjs/date/monthpicker/parts/MonthPicker.Caption.js +3 -2
- package/cjs/date/monthpicker/parts/MonthPicker.Caption.js.map +1 -1
- package/cjs/dropdown/Toggle.js +5 -12
- package/cjs/dropdown/Toggle.js.map +1 -1
- package/cjs/form/combobox/Input/Input.js +1 -1
- package/cjs/form/combobox/Input/Input.js.map +1 -1
- package/cjs/inline-message/root/InlineMessage.js +2 -2
- package/cjs/inline-message/root/InlineMessage.js.map +1 -1
- package/cjs/provider/Provider.d.ts +2 -2
- package/cjs/toggle-group/useToggleGroup.js +5 -3
- package/cjs/toggle-group/useToggleGroup.js.map +1 -1
- package/cjs/tooltip/Tooltip.js +1 -3
- package/cjs/tooltip/Tooltip.js.map +1 -1
- package/cjs/utils/components/HighlightText/HighlightText.d.ts +8 -0
- package/cjs/utils/components/HighlightText/HighlightText.js +27 -0
- package/cjs/utils/components/HighlightText/HighlightText.js.map +1 -0
- package/cjs/utils/components/Listbox/group/ListboxGroup.d.ts +7 -0
- package/cjs/utils/components/Listbox/group/ListboxGroup.js +15 -0
- package/cjs/utils/components/Listbox/group/ListboxGroup.js.map +1 -0
- package/cjs/utils/components/Listbox/input-slot/ListboxInputSlot.d.ts +7 -0
- package/cjs/utils/components/Listbox/input-slot/ListboxInputSlot.js +15 -0
- package/cjs/utils/components/Listbox/input-slot/ListboxInputSlot.js.map +1 -0
- package/cjs/utils/components/Listbox/item/ListboxItem.d.ts +24 -0
- package/cjs/utils/components/Listbox/item/ListboxItem.js +33 -0
- package/cjs/utils/components/Listbox/item/ListboxItem.js.map +1 -0
- package/cjs/utils/components/Listbox/list/ListboxList.d.ts +8 -0
- package/cjs/utils/components/Listbox/list/ListboxList.js +32 -0
- package/cjs/utils/components/Listbox/list/ListboxList.js.map +1 -0
- package/cjs/utils/components/Listbox/root/ListboxRoot.d.ts +20 -0
- package/cjs/utils/components/Listbox/root/ListboxRoot.js +84 -0
- package/cjs/utils/components/Listbox/root/ListboxRoot.js.map +1 -0
- package/cjs/utils/components/Listbox/root/domHelpers.d.ts +3 -0
- package/cjs/utils/components/Listbox/root/domHelpers.js +53 -0
- package/cjs/utils/components/Listbox/root/domHelpers.js.map +1 -0
- package/cjs/utils/components/focus-boundary/FocusBoundary.js +9 -64
- package/cjs/utils/components/focus-boundary/FocusBoundary.js.map +1 -1
- package/cjs/utils/helpers/focus.d.ts +14 -0
- package/cjs/utils/helpers/focus.js +63 -0
- package/cjs/utils/helpers/focus.js.map +1 -0
- package/cjs/utils/hooks/useDeferredValue.d.ts +1 -0
- package/cjs/utils/hooks/useDeferredValue.js +14 -0
- package/cjs/utils/hooks/useDeferredValue.js.map +1 -0
- package/esm/data/drag-and-drop/item/DataDragAndDropItem.d.ts +27 -0
- package/esm/data/drag-and-drop/item/DataDragAndDropItem.js +55 -0
- package/esm/data/drag-and-drop/item/DataDragAndDropItem.js.map +1 -0
- package/esm/data/drag-and-drop/root/DataDragAndDrop.context.d.ts +5 -0
- package/esm/data/drag-and-drop/root/DataDragAndDrop.context.js +3 -0
- package/esm/data/drag-and-drop/root/DataDragAndDrop.context.js.map +1 -0
- package/esm/data/drag-and-drop/root/DataDragAndDropRoot.d.ts +24 -0
- package/esm/data/drag-and-drop/root/DataDragAndDropRoot.js +71 -0
- package/esm/data/drag-and-drop/root/DataDragAndDropRoot.js.map +1 -0
- package/esm/data/table/helpers/table-keyboard.d.ts +1 -0
- package/esm/data/table/helpers/table-keyboard.js +5 -3
- package/esm/data/table/helpers/table-keyboard.js.map +1 -1
- package/esm/data/table/root/DataTableRoot.context.d.ts +8 -0
- package/esm/data/table/root/DataTableRoot.context.js +7 -0
- package/esm/data/table/root/DataTableRoot.context.js.map +1 -0
- package/esm/data/table/root/DataTableRoot.js +5 -3
- package/esm/data/table/root/DataTableRoot.js.map +1 -1
- package/esm/data/table/th/DataTableTh.d.ts +18 -2
- package/esm/data/table/th/DataTableTh.js +46 -21
- package/esm/data/table/th/DataTableTh.js.map +1 -1
- package/esm/data/table/tr/DataTableTr.js +9 -2
- package/esm/data/table/tr/DataTableTr.js.map +1 -1
- package/esm/data/token-filter/AutoSuggest.d.ts +6 -2
- package/esm/data/token-filter/AutoSuggest.js +45 -16
- package/esm/data/token-filter/AutoSuggest.js.map +1 -1
- package/esm/data/token-filter/AutoSuggest.types.d.ts +0 -1
- package/esm/data/token-filter/TokenFilter.d.ts +10 -5
- package/esm/data/token-filter/TokenFilter.js +110 -48
- package/esm/data/token-filter/TokenFilter.js.map +1 -1
- package/esm/data/token-filter/TokenFilter.types.d.ts +51 -35
- package/esm/data/token-filter/helpers/generate-autocomplete-options.d.ts +3 -6
- package/esm/data/token-filter/helpers/generate-autocomplete-options.js +24 -37
- package/esm/data/token-filter/helpers/generate-autocomplete-options.js.map +1 -1
- package/esm/data/token-filter/helpers/operators.d.ts +6 -6
- package/esm/data/token-filter/helpers/operators.js +3 -4
- package/esm/data/token-filter/helpers/operators.js.map +1 -1
- package/esm/data/token-filter/helpers/parse-query-text.d.ts +2 -20
- package/esm/data/token-filter/helpers/parse-query-text.js +1 -1
- package/esm/data/token-filter/helpers/parse-query-text.js.map +1 -1
- package/esm/data/token-filter/helpers/query-builder.d.ts +2 -2
- package/esm/data/token-filter/helpers/query-builder.js.map +1 -1
- package/esm/date/Date.Dialog.d.ts +5 -1
- package/esm/date/Date.Dialog.js +6 -2
- package/esm/date/Date.Dialog.js.map +1 -1
- package/esm/date/datepicker/DatePicker.js +3 -2
- package/esm/date/datepicker/DatePicker.js.map +1 -1
- package/esm/date/datepicker/hooks/useDatepicker.js +5 -2
- package/esm/date/datepicker/hooks/useDatepicker.js.map +1 -1
- package/esm/date/datepicker/hooks/useRangeDatepicker.js +3 -1
- package/esm/date/datepicker/hooks/useRangeDatepicker.js.map +1 -1
- package/esm/date/datepicker/parts/DatePicker.Months.d.ts +2 -1
- package/esm/date/datepicker/parts/DatePicker.Months.js +3 -3
- package/esm/date/datepicker/parts/DatePicker.Months.js.map +1 -1
- package/esm/date/datepicker/parts/DatePicker.RDP.d.ts +5 -1
- package/esm/date/datepicker/parts/DatePicker.RDP.js +2 -2
- package/esm/date/datepicker/parts/DatePicker.RDP.js.map +1 -1
- package/esm/date/monthpicker/MonthPicker.js +3 -2
- package/esm/date/monthpicker/MonthPicker.js.map +1 -1
- package/esm/date/monthpicker/hooks/useMonthPicker.js +3 -1
- package/esm/date/monthpicker/hooks/useMonthPicker.js.map +1 -1
- package/esm/date/monthpicker/parts/MonthPicker.Caption.d.ts +4 -1
- package/esm/date/monthpicker/parts/MonthPicker.Caption.js +3 -2
- package/esm/date/monthpicker/parts/MonthPicker.Caption.js.map +1 -1
- package/esm/dropdown/Toggle.js +5 -12
- package/esm/dropdown/Toggle.js.map +1 -1
- package/esm/form/combobox/Input/Input.js +1 -1
- package/esm/form/combobox/Input/Input.js.map +1 -1
- package/esm/inline-message/root/InlineMessage.js +3 -3
- package/esm/inline-message/root/InlineMessage.js.map +1 -1
- package/esm/provider/Provider.d.ts +2 -2
- package/esm/toggle-group/useToggleGroup.js +6 -4
- package/esm/toggle-group/useToggleGroup.js.map +1 -1
- package/esm/tooltip/Tooltip.js +1 -3
- package/esm/tooltip/Tooltip.js.map +1 -1
- package/esm/utils/components/HighlightText/HighlightText.d.ts +8 -0
- package/esm/utils/components/HighlightText/HighlightText.js +21 -0
- package/esm/utils/components/HighlightText/HighlightText.js.map +1 -0
- package/esm/utils/components/Listbox/group/ListboxGroup.d.ts +7 -0
- package/esm/utils/components/Listbox/group/ListboxGroup.js +10 -0
- package/esm/utils/components/Listbox/group/ListboxGroup.js.map +1 -0
- package/esm/utils/components/Listbox/input-slot/ListboxInputSlot.d.ts +7 -0
- package/esm/utils/components/Listbox/input-slot/ListboxInputSlot.js +9 -0
- package/esm/utils/components/Listbox/input-slot/ListboxInputSlot.js.map +1 -0
- package/esm/utils/components/Listbox/item/ListboxItem.d.ts +24 -0
- package/esm/utils/components/Listbox/item/ListboxItem.js +27 -0
- package/esm/utils/components/Listbox/item/ListboxItem.js.map +1 -0
- package/esm/utils/components/Listbox/list/ListboxList.d.ts +8 -0
- package/esm/utils/components/Listbox/list/ListboxList.js +27 -0
- package/esm/utils/components/Listbox/list/ListboxList.js.map +1 -0
- package/esm/utils/components/Listbox/root/ListboxRoot.d.ts +20 -0
- package/esm/utils/components/Listbox/root/ListboxRoot.js +79 -0
- package/esm/utils/components/Listbox/root/ListboxRoot.js.map +1 -0
- package/esm/utils/components/Listbox/root/domHelpers.d.ts +3 -0
- package/esm/utils/components/Listbox/root/domHelpers.js +50 -0
- package/esm/utils/components/Listbox/root/domHelpers.js.map +1 -0
- package/esm/utils/components/focus-boundary/FocusBoundary.js +8 -63
- package/esm/utils/components/focus-boundary/FocusBoundary.js.map +1 -1
- package/esm/utils/helpers/focus.d.ts +14 -0
- package/esm/utils/helpers/focus.js +60 -0
- package/esm/utils/helpers/focus.js.map +1 -0
- package/esm/utils/hooks/useDeferredValue.d.ts +1 -0
- package/esm/utils/hooks/useDeferredValue.js +7 -0
- package/esm/utils/hooks/useDeferredValue.js.map +1 -0
- package/package.json +7 -7
- package/src/data/drag-and-drop/item/DataDragAndDropItem.tsx +101 -0
- package/src/data/drag-and-drop/root/DataDragAndDrop.context.tsx +9 -0
- package/src/data/drag-and-drop/root/DataDragAndDropRoot.tsx +98 -0
- package/src/data/table/helpers/table-keyboard.ts +7 -3
- package/src/data/table/root/DataTableRoot.context.ts +13 -0
- package/src/data/table/root/DataTableRoot.tsx +16 -13
- package/src/data/table/th/DataTableTh.tsx +110 -54
- package/src/data/table/tr/DataTableTr.tsx +13 -2
- package/src/data/token-filter/AutoSuggest.tsx +142 -35
- package/src/data/token-filter/AutoSuggest.types.ts +0 -1
- package/src/data/token-filter/TokenFilter.tsx +179 -81
- package/src/data/token-filter/TokenFilter.types.ts +70 -44
- package/src/data/token-filter/helpers/generate-autocomplete-options.test.ts +97 -157
- package/src/data/token-filter/helpers/generate-autocomplete-options.ts +56 -53
- package/src/data/token-filter/helpers/operators.test.ts +29 -29
- package/src/data/token-filter/helpers/operators.ts +16 -16
- package/src/data/token-filter/helpers/parse-query-text.test.ts +37 -35
- package/src/data/token-filter/helpers/parse-query-text.ts +7 -26
- package/src/data/token-filter/helpers/query-builder.ts +2 -2
- package/src/date/Date.Dialog.tsx +15 -0
- package/src/date/datepicker/DatePicker.tsx +3 -0
- package/src/date/datepicker/hooks/useDatepicker.tsx +7 -2
- package/src/date/datepicker/hooks/useRangeDatepicker.tsx +5 -1
- package/src/date/datepicker/parts/DatePicker.Months.tsx +9 -1
- package/src/date/datepicker/parts/DatePicker.RDP.tsx +7 -1
- package/src/date/monthpicker/MonthPicker.tsx +3 -1
- package/src/date/monthpicker/hooks/useMonthPicker.tsx +5 -1
- package/src/date/monthpicker/parts/MonthPicker.Caption.tsx +20 -2
- package/src/dropdown/Toggle.tsx +6 -12
- package/src/form/combobox/Input/Input.tsx +2 -2
- package/src/inline-message/root/InlineMessage.tsx +5 -5
- package/src/provider/Provider.tsx +2 -2
- package/src/toggle-group/useToggleGroup.ts +6 -5
- package/src/tooltip/Tooltip.tsx +1 -3
- package/src/utils/components/HighlightText/HighlightText.tsx +34 -0
- package/src/utils/components/Listbox/group/ListboxGroup.tsx +26 -0
- package/src/utils/components/Listbox/input-slot/ListboxInputSlot.tsx +22 -0
- package/src/utils/components/Listbox/item/ListboxItem.tsx +57 -0
- package/src/utils/components/Listbox/list/ListboxList.tsx +38 -0
- package/src/utils/components/Listbox/root/ListboxRoot.tsx +104 -0
- package/src/utils/components/Listbox/root/domHelpers.ts +59 -0
- package/src/utils/components/focus-boundary/FocusBoundary.tsx +8 -78
- package/src/utils/helpers/focus.ts +75 -0
- package/src/utils/hooks/useDeferredValue.ts +12 -0
- package/cjs/data/table/th/DataTableThSortHandle.d.ts +0 -6
- package/cjs/data/table/th/DataTableThSortHandle.js +0 -82
- package/cjs/data/table/th/DataTableThSortHandle.js.map +0 -1
- package/esm/data/table/th/DataTableThSortHandle.d.ts +0 -6
- package/esm/data/table/th/DataTableThSortHandle.js +0 -47
- package/esm/data/table/th/DataTableThSortHandle.js.map +0 -1
- package/src/data/table/th/DataTableThSortHandle.tsx +0 -67
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { AutoCompleteOption, OptionGroup } from "../AutoSuggest.types";
|
|
2
2
|
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
InternalParsedTextState,
|
|
4
|
+
InternalPropertyDefinition,
|
|
5
|
+
InternalPropertyOption,
|
|
6
|
+
OperatorT,
|
|
6
7
|
} from "../TokenFilter.types";
|
|
7
8
|
import { createGroups } from "./grouping";
|
|
8
9
|
import { QUERY_OPERATORS } from "./operators";
|
|
9
|
-
import { type ParsedText } from "./parse-query-text";
|
|
10
10
|
import { OPERATOR_LABELS, buildQueryString } from "./query-builder";
|
|
11
11
|
import { matchesFilterText } from "./text-matching";
|
|
12
12
|
|
|
@@ -23,11 +23,16 @@ import { matchesFilterText } from "./text-matching";
|
|
|
23
23
|
* Used by the UI to determine cursor position and input replacement.
|
|
24
24
|
* - options: Grouped suggestions to display (properties, operators, or values).
|
|
25
25
|
*/
|
|
26
|
+
type AutoCompleteResult = {
|
|
27
|
+
value: string;
|
|
28
|
+
options: OptionGroup<AutoCompleteOption>[];
|
|
29
|
+
};
|
|
30
|
+
|
|
26
31
|
function generateAutoCompleteOptions(
|
|
27
|
-
queryState:
|
|
28
|
-
filteringProperties:
|
|
29
|
-
filteringOptions:
|
|
30
|
-
) {
|
|
32
|
+
queryState: InternalParsedTextState,
|
|
33
|
+
filteringProperties: InternalPropertyDefinition[] = [],
|
|
34
|
+
filteringOptions: InternalPropertyOption[] = [],
|
|
35
|
+
): AutoCompleteResult {
|
|
31
36
|
/* State: Property and operator are matched, suggest values */
|
|
32
37
|
if (queryState.step === "property") {
|
|
33
38
|
const filterText = queryState.value || "";
|
|
@@ -51,7 +56,7 @@ function generateAutoCompleteOptions(
|
|
|
51
56
|
);
|
|
52
57
|
|
|
53
58
|
const partialQuery = buildQueryString(
|
|
54
|
-
queryState.property.
|
|
59
|
+
queryState.property.label,
|
|
55
60
|
queryState.operatorPrefix,
|
|
56
61
|
"",
|
|
57
62
|
);
|
|
@@ -60,9 +65,6 @@ function generateAutoCompleteOptions(
|
|
|
60
65
|
* Edge case: User typed an invalid operator prefix that doesn't match any operators.
|
|
61
66
|
* This can happen when typing characters that don't start any valid operator.
|
|
62
67
|
* Return empty suggestions gracefully - the UI will show "no results".
|
|
63
|
-
*
|
|
64
|
-
* TODO: When per-property operator configuration is implemented,
|
|
65
|
-
* this could also occur when a property restricts which operators are valid.
|
|
66
68
|
*/
|
|
67
69
|
if (operators.length === 0) {
|
|
68
70
|
return {
|
|
@@ -105,11 +107,14 @@ function generateAutoCompleteOptions(
|
|
|
105
107
|
*/
|
|
106
108
|
return {
|
|
107
109
|
value: queryState.value,
|
|
108
|
-
options:
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
options: [
|
|
111
|
+
...generatePropertySuggestions(filteringProperties, queryState.value),
|
|
112
|
+
...createValueSuggestions(
|
|
113
|
+
filteringOptions,
|
|
114
|
+
queryState.operator ?? "=",
|
|
115
|
+
queryState.value,
|
|
116
|
+
),
|
|
117
|
+
],
|
|
113
118
|
};
|
|
114
119
|
}
|
|
115
120
|
|
|
@@ -127,8 +132,8 @@ function generateAutoCompleteOptions(
|
|
|
127
132
|
* TODO: We omit passing the tokenType for now since it's not currently used in the UI. But will be needed for single/multi-selection.
|
|
128
133
|
*/
|
|
129
134
|
function getValidOperatorsForProperty(
|
|
130
|
-
property:
|
|
131
|
-
):
|
|
135
|
+
property: InternalPropertyDefinition,
|
|
136
|
+
): OperatorT[] {
|
|
132
137
|
const { operators } = property;
|
|
133
138
|
|
|
134
139
|
/* If no operators configured, return all available operators */
|
|
@@ -146,8 +151,8 @@ function getValidOperatorsForProperty(
|
|
|
146
151
|
|
|
147
152
|
/* Filter to only valid QUERY_OPERATORS to ensure type safety */
|
|
148
153
|
return operatorStrings.filter((op) =>
|
|
149
|
-
QUERY_OPERATORS.includes(op as
|
|
150
|
-
) as
|
|
154
|
+
QUERY_OPERATORS.includes(op as OperatorT),
|
|
155
|
+
) as OperatorT[];
|
|
151
156
|
}
|
|
152
157
|
|
|
153
158
|
/**
|
|
@@ -155,9 +160,9 @@ function getValidOperatorsForProperty(
|
|
|
155
160
|
* If the prefix is empty, all operators are returned.
|
|
156
161
|
*/
|
|
157
162
|
function filterOperatorsByPrefix(
|
|
158
|
-
operators:
|
|
163
|
+
operators: OperatorT[],
|
|
159
164
|
prefix: string,
|
|
160
|
-
):
|
|
165
|
+
): OperatorT[] {
|
|
161
166
|
if (!prefix) {
|
|
162
167
|
return operators;
|
|
163
168
|
}
|
|
@@ -166,10 +171,10 @@ function filterOperatorsByPrefix(
|
|
|
166
171
|
}
|
|
167
172
|
|
|
168
173
|
function generatePropertySuggestions(
|
|
169
|
-
filteringProperties:
|
|
174
|
+
filteringProperties: InternalPropertyDefinition[] = [],
|
|
170
175
|
filterText = "",
|
|
171
|
-
): OptionGroup<
|
|
172
|
-
const filteredProperties:
|
|
176
|
+
): OptionGroup<AutoCompleteOption>[] {
|
|
177
|
+
const filteredProperties: InternalPropertyDefinition[] = [];
|
|
173
178
|
|
|
174
179
|
for (const property of filteringProperties) {
|
|
175
180
|
if (!property) {
|
|
@@ -178,11 +183,7 @@ function generatePropertySuggestions(
|
|
|
178
183
|
|
|
179
184
|
if (
|
|
180
185
|
matchesFilterText(
|
|
181
|
-
[
|
|
182
|
-
property.propertyLabel,
|
|
183
|
-
property.groupValuesLabel,
|
|
184
|
-
property.propertyGroup,
|
|
185
|
-
].filter(Boolean),
|
|
186
|
+
[property.label, property.groupLabel, property.group].filter(Boolean),
|
|
186
187
|
filterText,
|
|
187
188
|
)
|
|
188
189
|
) {
|
|
@@ -190,15 +191,23 @@ function generatePropertySuggestions(
|
|
|
190
191
|
}
|
|
191
192
|
}
|
|
192
193
|
|
|
193
|
-
|
|
194
|
+
const groups = createGroups(
|
|
194
195
|
filteredProperties,
|
|
195
|
-
(property) => property.
|
|
196
|
+
(property) => property.group,
|
|
196
197
|
"Properties",
|
|
197
198
|
);
|
|
199
|
+
|
|
200
|
+
return groups.map((group) => ({
|
|
201
|
+
label: group.label,
|
|
202
|
+
options: group.options.map((property) => ({
|
|
203
|
+
value: buildQueryString(property.label, "", ""),
|
|
204
|
+
label: property.label,
|
|
205
|
+
})),
|
|
206
|
+
}));
|
|
198
207
|
}
|
|
199
208
|
|
|
200
209
|
function generateOperatorSuggestions(
|
|
201
|
-
property:
|
|
210
|
+
property: InternalPropertyDefinition,
|
|
202
211
|
operatorPrefix = "",
|
|
203
212
|
): OptionGroup<AutoCompleteOption>[] {
|
|
204
213
|
const operators = filterOperatorsByPrefix(
|
|
@@ -214,8 +223,8 @@ function generateOperatorSuggestions(
|
|
|
214
223
|
{
|
|
215
224
|
label: "Operators",
|
|
216
225
|
options: operators.map((operator) => ({
|
|
217
|
-
value: buildQueryString(property.
|
|
218
|
-
label: buildQueryString(property.
|
|
226
|
+
value: buildQueryString(property.label, operator, ""),
|
|
227
|
+
label: buildQueryString(property.label, operator, ""),
|
|
219
228
|
description: OPERATOR_LABELS[operator] ?? "",
|
|
220
229
|
})),
|
|
221
230
|
},
|
|
@@ -226,12 +235,15 @@ function generateOperatorSuggestions(
|
|
|
226
235
|
* Creates value suggestions for autocomplete.
|
|
227
236
|
* When scopedProperty is provided, only shows values for that property (single group).
|
|
228
237
|
* When scopedProperty is omitted, searches across all properties (multiple groups).
|
|
238
|
+
* TODO: This could potentially contain an unlimited number of options if there are many values across properties.
|
|
239
|
+
* May need virtualization/async or other filtering mechanism.
|
|
229
240
|
*/
|
|
241
|
+
|
|
230
242
|
function createValueSuggestions(
|
|
231
|
-
filteringOptions:
|
|
232
|
-
operator:
|
|
243
|
+
filteringOptions: InternalPropertyOption[] = [],
|
|
244
|
+
operator: OperatorT,
|
|
233
245
|
filterText = "",
|
|
234
|
-
scopedProperty?:
|
|
246
|
+
scopedProperty?: InternalPropertyDefinition,
|
|
235
247
|
): OptionGroup<AutoCompleteOption>[] {
|
|
236
248
|
const groups: Record<string, OptionGroup<AutoCompleteOption>> = {};
|
|
237
249
|
|
|
@@ -246,14 +258,10 @@ function createValueSuggestions(
|
|
|
246
258
|
}
|
|
247
259
|
|
|
248
260
|
/* Build search fields */
|
|
249
|
-
const searchFields = [
|
|
250
|
-
option.label,
|
|
251
|
-
...(option.tags ?? []),
|
|
252
|
-
...(option.filteringTags ?? []),
|
|
253
|
-
];
|
|
261
|
+
const searchFields = [option.label, ...(option.tags ?? [])];
|
|
254
262
|
|
|
255
263
|
if (!scopedProperty) {
|
|
256
|
-
searchFields.push(option.property.
|
|
264
|
+
searchFields.push(option.property.label);
|
|
257
265
|
}
|
|
258
266
|
|
|
259
267
|
const matches = matchesFilterText(searchFields.filter(Boolean), filterText);
|
|
@@ -262,7 +270,7 @@ function createValueSuggestions(
|
|
|
262
270
|
continue;
|
|
263
271
|
}
|
|
264
272
|
|
|
265
|
-
const groupLabel = option.property.
|
|
273
|
+
const groupLabel = option.property.groupLabel || "Values";
|
|
266
274
|
|
|
267
275
|
if (!groups[groupLabel]) {
|
|
268
276
|
groups[groupLabel] = {
|
|
@@ -272,14 +280,9 @@ function createValueSuggestions(
|
|
|
272
280
|
}
|
|
273
281
|
|
|
274
282
|
groups[groupLabel].options.push({
|
|
275
|
-
value: buildQueryString(
|
|
276
|
-
|
|
277
|
-
operator,
|
|
278
|
-
option.value,
|
|
279
|
-
),
|
|
280
|
-
label: option.label,
|
|
283
|
+
value: buildQueryString(option.property.label, operator, option.value),
|
|
284
|
+
label: buildQueryString(option.property.label, operator, option.value),
|
|
281
285
|
tags: option.tags,
|
|
282
|
-
filteringTags: option.filteringTags,
|
|
283
286
|
});
|
|
284
287
|
}
|
|
285
288
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, test } from "vitest";
|
|
2
|
-
import type {
|
|
2
|
+
import type { InternalPropertyDefinition } from "../TokenFilter.types";
|
|
3
3
|
import {
|
|
4
4
|
QUERY_OPERATORS,
|
|
5
5
|
matchFilteringProperty,
|
|
@@ -109,44 +109,44 @@ describe("matchOperator", () => {
|
|
|
109
109
|
});
|
|
110
110
|
|
|
111
111
|
describe("matchFilteringProperty", () => {
|
|
112
|
-
const properties:
|
|
112
|
+
const properties: InternalPropertyDefinition[] = [
|
|
113
113
|
{
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
key: "status",
|
|
115
|
+
label: "Status",
|
|
116
|
+
groupLabel: "",
|
|
117
|
+
group: "testgroup",
|
|
118
118
|
externalProperty: {} as any,
|
|
119
119
|
operators: [],
|
|
120
120
|
},
|
|
121
121
|
{
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
key: "hostname",
|
|
123
|
+
label: "Hostname",
|
|
124
|
+
groupLabel: "",
|
|
125
|
+
group: "testgroup",
|
|
126
126
|
externalProperty: {} as any,
|
|
127
127
|
operators: [],
|
|
128
128
|
},
|
|
129
129
|
{
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
key: "instance-id",
|
|
131
|
+
label: "Instance ID",
|
|
132
|
+
groupLabel: "",
|
|
133
|
+
group: "testgroup",
|
|
134
134
|
externalProperty: {} as any,
|
|
135
135
|
operators: [],
|
|
136
136
|
},
|
|
137
137
|
{
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
key: "region",
|
|
139
|
+
label: "Region",
|
|
140
|
+
groupLabel: "",
|
|
141
|
+
group: "testgroup",
|
|
142
142
|
externalProperty: {} as any,
|
|
143
143
|
operators: [],
|
|
144
144
|
},
|
|
145
145
|
{
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
146
|
+
key: "availability-zone",
|
|
147
|
+
label: "Availability Zone",
|
|
148
|
+
groupLabel: "",
|
|
149
|
+
group: "testgroup",
|
|
150
150
|
externalProperty: {} as any,
|
|
151
151
|
operators: [],
|
|
152
152
|
},
|
|
@@ -154,27 +154,27 @@ describe("matchFilteringProperty", () => {
|
|
|
154
154
|
|
|
155
155
|
test("should match a basic property", () => {
|
|
156
156
|
const result = matchFilteringProperty(properties, "Status");
|
|
157
|
-
expect(result?.
|
|
157
|
+
expect(result?.key).toBe("status");
|
|
158
158
|
});
|
|
159
159
|
|
|
160
160
|
test("should match property case-insensitively", () => {
|
|
161
161
|
const result = matchFilteringProperty(properties, "status");
|
|
162
|
-
expect(result?.
|
|
162
|
+
expect(result?.key).toBe("status");
|
|
163
163
|
});
|
|
164
164
|
|
|
165
165
|
test("should match property with mixed casing", () => {
|
|
166
166
|
const result = matchFilteringProperty(properties, "sTaTuS");
|
|
167
|
-
expect(result?.
|
|
167
|
+
expect(result?.key).toBe("status");
|
|
168
168
|
});
|
|
169
169
|
|
|
170
170
|
test("should use longest matching property when properties overlap", () => {
|
|
171
171
|
const result = matchFilteringProperty(properties, "Instance ID");
|
|
172
|
-
expect(result?.
|
|
172
|
+
expect(result?.key).toBe("instance-id");
|
|
173
173
|
});
|
|
174
174
|
|
|
175
175
|
test("should prefer longest property: Availability Zone vs Zone", () => {
|
|
176
176
|
const result = matchFilteringProperty(properties, "Availability Zone");
|
|
177
|
-
expect(result?.
|
|
177
|
+
expect(result?.key).toBe("availability-zone");
|
|
178
178
|
});
|
|
179
179
|
|
|
180
180
|
test("should return undefined when no property matches", () => {
|
|
@@ -189,12 +189,12 @@ describe("matchFilteringProperty", () => {
|
|
|
189
189
|
|
|
190
190
|
test("should match property from partial input", () => {
|
|
191
191
|
const result = matchFilteringProperty(properties, "Status=value");
|
|
192
|
-
expect(result?.
|
|
192
|
+
expect(result?.key).toBe("status");
|
|
193
193
|
});
|
|
194
194
|
|
|
195
195
|
test("should match property with spaces in label", () => {
|
|
196
196
|
const result = matchFilteringProperty(properties, "Instance ID:value");
|
|
197
|
-
expect(result?.
|
|
197
|
+
expect(result?.key).toBe("instance-id");
|
|
198
198
|
});
|
|
199
199
|
});
|
|
200
200
|
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
InternalPropertyDefinition,
|
|
3
|
+
OperatorT,
|
|
4
|
+
} from "../TokenFilter.types";
|
|
2
5
|
|
|
3
6
|
/**
|
|
4
7
|
* Operators ordered by specificity (longest/most specific first)
|
|
5
8
|
* This ensures longer operators like ">=" and "<=" are matched
|
|
6
9
|
* before shorter ones like ">" and "<"
|
|
7
10
|
*/
|
|
8
|
-
const Operators: Record<
|
|
11
|
+
const Operators: Record<OperatorT, null> = {
|
|
9
12
|
">=": null,
|
|
10
13
|
"<=": null,
|
|
11
14
|
"!=": null,
|
|
@@ -18,16 +21,16 @@ const Operators: Record<QueryFilterOperator, null> = {
|
|
|
18
21
|
"<": null,
|
|
19
22
|
};
|
|
20
23
|
|
|
21
|
-
const QUERY_OPERATORS:
|
|
24
|
+
const QUERY_OPERATORS: OperatorT[] = Object.keys(Operators);
|
|
22
25
|
|
|
23
26
|
/**
|
|
24
27
|
* Match an operator from the input text.
|
|
25
28
|
* Operators are already sorted by specificity, so no re-sorting needed.
|
|
26
29
|
*/
|
|
27
30
|
function matchOperator(
|
|
28
|
-
allowedOperators:
|
|
31
|
+
allowedOperators: OperatorT[],
|
|
29
32
|
text: string,
|
|
30
|
-
):
|
|
33
|
+
): OperatorT | undefined {
|
|
31
34
|
return allowedOperators.find((operator) =>
|
|
32
35
|
text.toLowerCase().startsWith(operator.toLowerCase()),
|
|
33
36
|
);
|
|
@@ -42,18 +45,15 @@ function matchOperator(
|
|
|
42
45
|
* Result: { propertyLabel: "Instance ID" }
|
|
43
46
|
*/
|
|
44
47
|
function matchFilteringProperty(
|
|
45
|
-
filteringProperties:
|
|
48
|
+
filteringProperties: InternalPropertyDefinition[],
|
|
46
49
|
text: string,
|
|
47
|
-
):
|
|
50
|
+
): InternalPropertyDefinition | undefined {
|
|
48
51
|
const lowerText = text.toLowerCase();
|
|
49
|
-
let bestMatch:
|
|
52
|
+
let bestMatch: InternalPropertyDefinition | undefined;
|
|
50
53
|
|
|
51
54
|
for (const prop of filteringProperties) {
|
|
52
|
-
if (lowerText.startsWith(prop.
|
|
53
|
-
if (
|
|
54
|
-
!bestMatch ||
|
|
55
|
-
prop.propertyLabel.length > bestMatch.propertyLabel.length
|
|
56
|
-
) {
|
|
55
|
+
if (lowerText.startsWith(prop.label.toLowerCase())) {
|
|
56
|
+
if (!bestMatch || prop.label.length > bestMatch.label.length) {
|
|
57
57
|
bestMatch = prop;
|
|
58
58
|
}
|
|
59
59
|
}
|
|
@@ -67,7 +67,7 @@ function matchFilteringProperty(
|
|
|
67
67
|
* Returns the prefix if valid, null otherwise.
|
|
68
68
|
*/
|
|
69
69
|
function matchOperatorPrefix(
|
|
70
|
-
allowedOperators:
|
|
70
|
+
allowedOperators: OperatorT[],
|
|
71
71
|
filteringText: string,
|
|
72
72
|
): string | null {
|
|
73
73
|
const trimmedText = filteringText.trim();
|
|
@@ -84,8 +84,8 @@ function matchOperatorPrefix(
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
export {
|
|
87
|
-
QUERY_OPERATORS,
|
|
88
|
-
matchOperator,
|
|
89
87
|
matchFilteringProperty,
|
|
88
|
+
matchOperator,
|
|
90
89
|
matchOperatorPrefix,
|
|
90
|
+
QUERY_OPERATORS,
|
|
91
91
|
};
|
|
@@ -1,52 +1,54 @@
|
|
|
1
1
|
import { describe, expect, test } from "vitest";
|
|
2
2
|
import type {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
ExternalPropertyDefinition,
|
|
4
|
+
InternalParsedTextState,
|
|
5
|
+
InternalPropertyDefinition,
|
|
5
6
|
} from "../TokenFilter.types";
|
|
6
7
|
import { parseQueryText } from "./parse-query-text";
|
|
7
|
-
import type { ParsedText } from "./parse-query-text";
|
|
8
8
|
|
|
9
|
-
const properties:
|
|
9
|
+
const properties: ExternalPropertyDefinition[] = [
|
|
10
10
|
{
|
|
11
|
-
|
|
11
|
+
groupLabel: "",
|
|
12
12
|
group: "testgroup",
|
|
13
13
|
key: "status",
|
|
14
|
-
|
|
14
|
+
label: "Status",
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
|
-
|
|
17
|
+
groupLabel: "",
|
|
18
18
|
group: "testgroup",
|
|
19
19
|
key: "hostname",
|
|
20
|
-
|
|
20
|
+
label: "Hostname",
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
|
-
|
|
23
|
+
groupLabel: "",
|
|
24
24
|
group: "testgroup",
|
|
25
25
|
key: "instance-id",
|
|
26
|
-
|
|
26
|
+
label: "Instance ID",
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
|
-
|
|
29
|
+
groupLabel: "",
|
|
30
30
|
group: "testgroup",
|
|
31
31
|
key: "region",
|
|
32
|
-
|
|
32
|
+
label: "Region",
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
|
-
|
|
35
|
+
groupLabel: "",
|
|
36
36
|
group: "testgroup",
|
|
37
37
|
key: "availability-zone",
|
|
38
|
-
|
|
38
|
+
label: "Availability Zone",
|
|
39
39
|
},
|
|
40
40
|
];
|
|
41
41
|
|
|
42
|
-
const parsedProperties:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
42
|
+
const parsedProperties: InternalPropertyDefinition[] = properties.map(
|
|
43
|
+
(prop) => ({
|
|
44
|
+
key: prop.key,
|
|
45
|
+
label: prop.label,
|
|
46
|
+
groupLabel: prop.groupLabel ?? "",
|
|
47
|
+
group: prop.group ?? "",
|
|
48
|
+
externalProperty: prop,
|
|
49
|
+
operators: prop.operators ?? [],
|
|
50
|
+
}),
|
|
51
|
+
);
|
|
50
52
|
|
|
51
53
|
describe("parseQueryText", () => {
|
|
52
54
|
describe("value extraction", () => {
|
|
@@ -54,7 +56,7 @@ describe("parseQueryText", () => {
|
|
|
54
56
|
const result = parseQueryText("Status=active", parsedProperties);
|
|
55
57
|
expect(result.step).toBe("property");
|
|
56
58
|
const propertyResult = result as Extract<
|
|
57
|
-
|
|
59
|
+
InternalParsedTextState,
|
|
58
60
|
{ step: "property" }
|
|
59
61
|
>;
|
|
60
62
|
expect(propertyResult.value).toBe("active");
|
|
@@ -64,7 +66,7 @@ describe("parseQueryText", () => {
|
|
|
64
66
|
const result = parseQueryText("Status= active", parsedProperties);
|
|
65
67
|
expect(result.step).toBe("property");
|
|
66
68
|
const propertyResult = result as Extract<
|
|
67
|
-
|
|
69
|
+
InternalParsedTextState,
|
|
68
70
|
{ step: "property" }
|
|
69
71
|
>;
|
|
70
72
|
expect(propertyResult.value).toBe("active");
|
|
@@ -74,7 +76,7 @@ describe("parseQueryText", () => {
|
|
|
74
76
|
const result = parseQueryText("Status=", parsedProperties);
|
|
75
77
|
expect(result.step).toBe("property");
|
|
76
78
|
const propertyResult = result as Extract<
|
|
77
|
-
|
|
79
|
+
InternalParsedTextState,
|
|
78
80
|
{ step: "property" }
|
|
79
81
|
>;
|
|
80
82
|
expect(propertyResult.value).toBe("");
|
|
@@ -84,7 +86,7 @@ describe("parseQueryText", () => {
|
|
|
84
86
|
const result = parseQueryText("Status= ", parsedProperties);
|
|
85
87
|
expect(result.step).toBe("property");
|
|
86
88
|
const propertyResult = result as Extract<
|
|
87
|
-
|
|
89
|
+
InternalParsedTextState,
|
|
88
90
|
{ step: "property" }
|
|
89
91
|
>;
|
|
90
92
|
expect(propertyResult.value).toBe("");
|
|
@@ -97,7 +99,7 @@ describe("parseQueryText", () => {
|
|
|
97
99
|
);
|
|
98
100
|
expect(result.step).toBe("property");
|
|
99
101
|
const propertyResult = result as Extract<
|
|
100
|
-
|
|
102
|
+
InternalParsedTextState,
|
|
101
103
|
{ step: "property" }
|
|
102
104
|
>;
|
|
103
105
|
expect(propertyResult.value).toBe("active and running");
|
|
@@ -107,7 +109,7 @@ describe("parseQueryText", () => {
|
|
|
107
109
|
const result = parseQueryText("Instance ID=server-123", parsedProperties);
|
|
108
110
|
expect(result.step).toBe("property");
|
|
109
111
|
const propertyResult = result as Extract<
|
|
110
|
-
|
|
112
|
+
InternalParsedTextState,
|
|
111
113
|
{ step: "property" }
|
|
112
114
|
>;
|
|
113
115
|
expect(propertyResult.value).toBe("server-123");
|
|
@@ -119,7 +121,7 @@ describe("parseQueryText", () => {
|
|
|
119
121
|
const result = parseQueryText("Status =value", parsedProperties);
|
|
120
122
|
expect(result.step).toBe("property");
|
|
121
123
|
const propertyResult = result as Extract<
|
|
122
|
-
|
|
124
|
+
InternalParsedTextState,
|
|
123
125
|
{ step: "property" }
|
|
124
126
|
>;
|
|
125
127
|
expect(propertyResult.operator).toBe("=");
|
|
@@ -130,7 +132,7 @@ describe("parseQueryText", () => {
|
|
|
130
132
|
const result = parseQueryText("Status >value", parsedProperties);
|
|
131
133
|
expect(result.step).toBe("property");
|
|
132
134
|
const propertyResult = result as Extract<
|
|
133
|
-
|
|
135
|
+
InternalParsedTextState,
|
|
134
136
|
{ step: "property" }
|
|
135
137
|
>;
|
|
136
138
|
expect(propertyResult.operator).toBe(">");
|
|
@@ -141,7 +143,7 @@ describe("parseQueryText", () => {
|
|
|
141
143
|
const result = parseQueryText("Status ", parsedProperties);
|
|
142
144
|
expect(result.step).toBe("operator");
|
|
143
145
|
const operatorResult = result as Extract<
|
|
144
|
-
|
|
146
|
+
InternalParsedTextState,
|
|
145
147
|
{ step: "operator" }
|
|
146
148
|
>;
|
|
147
149
|
expect(operatorResult.operatorPrefix).toBe("");
|
|
@@ -163,7 +165,7 @@ describe("parseQueryText", () => {
|
|
|
163
165
|
const result = parseQueryText("Status", parsedProperties);
|
|
164
166
|
expect(result.step).toBe("operator");
|
|
165
167
|
const operatorResult = result as Extract<
|
|
166
|
-
|
|
168
|
+
InternalParsedTextState,
|
|
167
169
|
{ step: "operator" }
|
|
168
170
|
>;
|
|
169
171
|
expect(operatorResult.operatorPrefix).toBe("");
|
|
@@ -173,10 +175,10 @@ describe("parseQueryText", () => {
|
|
|
173
175
|
const result = parseQueryText("Instance ID:value", parsedProperties);
|
|
174
176
|
expect(result.step).toBe("property");
|
|
175
177
|
const propertyResult = result as Extract<
|
|
176
|
-
|
|
178
|
+
InternalParsedTextState,
|
|
177
179
|
{ step: "property" }
|
|
178
180
|
>;
|
|
179
|
-
expect(propertyResult.property.
|
|
181
|
+
expect(propertyResult.property.key).toBe("instance-id");
|
|
180
182
|
expect(propertyResult.operator).toBe(":");
|
|
181
183
|
expect(propertyResult.value).toBe("value");
|
|
182
184
|
});
|
|
@@ -187,7 +189,7 @@ describe("parseQueryText", () => {
|
|
|
187
189
|
const result = parseQueryText("Random text", parsedProperties);
|
|
188
190
|
expect(result.step).toBe("free-text");
|
|
189
191
|
const freeTextResult = result as Extract<
|
|
190
|
-
|
|
192
|
+
InternalParsedTextState,
|
|
191
193
|
{ step: "free-text" }
|
|
192
194
|
>;
|
|
193
195
|
expect(freeTextResult.value).toBe("Random text");
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
InternalParsedTextState,
|
|
3
|
+
InternalPropertyDefinition,
|
|
4
|
+
} from "../TokenFilter.types";
|
|
2
5
|
import {
|
|
3
6
|
QUERY_OPERATORS,
|
|
4
7
|
matchFilteringProperty,
|
|
@@ -6,35 +9,14 @@ import {
|
|
|
6
9
|
matchOperatorPrefix,
|
|
7
10
|
} from "./operators";
|
|
8
11
|
|
|
9
|
-
type ParsedText =
|
|
10
|
-
| {
|
|
11
|
-
/** User has typed property + complete operator + value (e.g., "Status != active") */
|
|
12
|
-
step: "property";
|
|
13
|
-
property: ParsedProperty;
|
|
14
|
-
operator: QueryFilterOperator;
|
|
15
|
-
value: string;
|
|
16
|
-
}
|
|
17
|
-
| {
|
|
18
|
-
/** User is typing the operator after property (e.g., "Status !") */
|
|
19
|
-
step: "operator";
|
|
20
|
-
property: ParsedProperty;
|
|
21
|
-
operatorPrefix: string;
|
|
22
|
-
}
|
|
23
|
-
| {
|
|
24
|
-
/** No property match; treat as free-text search */
|
|
25
|
-
step: "free-text";
|
|
26
|
-
value: string;
|
|
27
|
-
operator?: QueryFilterOperator;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
12
|
/**
|
|
31
13
|
* Parse user input text to extract property, operator, and value components.
|
|
32
14
|
* Handles partial input (e.g., user typing "Status !" to complete the operator).
|
|
33
15
|
*/
|
|
34
16
|
function parseQueryText(
|
|
35
17
|
filteringText: string,
|
|
36
|
-
filteringProperties:
|
|
37
|
-
):
|
|
18
|
+
filteringProperties: InternalPropertyDefinition[],
|
|
19
|
+
): InternalParsedTextState {
|
|
38
20
|
const property = matchFilteringProperty(filteringProperties, filteringText);
|
|
39
21
|
if (!property) {
|
|
40
22
|
const freeTextOperator = matchOperator(QUERY_OPERATORS, filteringText);
|
|
@@ -53,7 +35,7 @@ function parseQueryText(
|
|
|
53
35
|
}
|
|
54
36
|
|
|
55
37
|
const textWithoutProperty = filteringText
|
|
56
|
-
.substring(property.
|
|
38
|
+
.substring(property.label.length)
|
|
57
39
|
.trimStart();
|
|
58
40
|
|
|
59
41
|
const operator = matchOperator(QUERY_OPERATORS, textWithoutProperty);
|
|
@@ -83,4 +65,3 @@ function parseQueryText(
|
|
|
83
65
|
}
|
|
84
66
|
|
|
85
67
|
export { parseQueryText };
|
|
86
|
-
export type { ParsedText };
|