nuxt-ui-tools 1.26.0 → 1.27.1
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/module.json +1 -1
- package/dist/runtime/table/builders/index.d.ts +2 -2
- package/dist/runtime/table/composables/use-filter-persistence.d.ts +14 -0
- package/dist/runtime/table/composables/use-filter-persistence.js +77 -0
- package/dist/runtime/table/composables/use-query-state.js +31 -26
- package/dist/runtime/table/composables/use-table-api.js +4 -0
- package/dist/runtime/table/composables/use-table-data.js +3 -2
- package/dist/runtime/table/composables/use-table-state.d.ts +1 -0
- package/dist/runtime/table/composables/use-table-state.js +13 -2
- package/dist/runtime/table/types/filters.d.ts +37 -6
- package/dist/runtime/table/types/table-api.d.ts +5 -0
- package/dist/runtime/table/utils/filter-persistence.d.ts +16 -0
- package/dist/runtime/table/utils/filter-persistence.js +42 -0
- package/dist/runtime/table/utils/index.d.ts +1 -0
- package/dist/runtime/table/utils/index.js +1 -0
- package/dist/runtime/table/utils/resolved-filters.d.ts +8 -0
- package/dist/runtime/table/utils/resolved-filters.js +6 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { GenericObject, TableColumnBuilder, TableColumnCollection, TableFilterBuilder, TableSortKey, TableUiFilterCollection,
|
|
1
|
+
import type { GenericObject, TableColumnBuilder, TableColumnCollection, TableFilterBuilder, TableSortKey, TableUiFilterCollection, TableUiFilterCollectionItem } from '../types/index.js';
|
|
2
2
|
export { type TableSortKey } from '../types/index.js';
|
|
3
3
|
export declare function createTableColumnBuilder<TRow extends GenericObject, TContext extends GenericObject, TPageContext extends GenericObject, TSortKey extends string = TableSortKey<TRow>, TData = unknown>(): TableColumnBuilder<TRow, TContext, TPageContext, TSortKey, TData>;
|
|
4
4
|
export declare function createTableFilterBuilder<TRow extends GenericObject, TContext extends GenericObject = GenericObject>(): TableFilterBuilder<TRow, TContext>;
|
|
5
5
|
export declare function resolveCollection<TBuilder, TResult>(collection: TResult | ((builder: TBuilder) => TResult) | undefined, builder: TBuilder): TResult | undefined;
|
|
6
6
|
export declare function resolveColumns<TRow extends GenericObject, TContext extends GenericObject, TPageContext extends GenericObject, TSortKey extends string = TableSortKey<TRow>, TData = unknown, TColumns extends TableColumnCollection<TRow, TContext, TPageContext, string, TSortKey, TData> | undefined = TableColumnCollection<TRow, TContext, TPageContext, string, TSortKey, TData> | undefined>(columns: TColumns): TColumns extends (...args: never[]) => infer TResult ? TResult : TColumns;
|
|
7
|
-
export declare function resolveUiFilters<TRow extends GenericObject, TContext extends GenericObject, TKey extends string>(filters: TableUiFilterCollection<TRow, TContext, TKey> | undefined):
|
|
7
|
+
export declare function resolveUiFilters<TRow extends GenericObject, TContext extends GenericObject, TKey extends string>(filters: TableUiFilterCollection<TRow, TContext, TKey> | undefined): TableUiFilterCollectionItem<TRow, TContext, TKey>[] | undefined;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ComputedRef, WritableComputedRef } from 'vue';
|
|
2
|
+
import type { TableFilterState, TableSchemaView } from '../types/index.js';
|
|
3
|
+
export interface UseFilterPersistenceParams {
|
|
4
|
+
schema: ComputedRef<TableSchemaView>;
|
|
5
|
+
filters: WritableComputedRef<TableFilterState>;
|
|
6
|
+
/** Writes the restored state without adding a browser history entry. */
|
|
7
|
+
restore: (state: TableFilterState) => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Keeps the value of every filter marked `behavior.persist` in `localStorage`. On setup, a stored
|
|
11
|
+
* value replaces the default of a filter the URL does not set; afterwards each change is written
|
|
12
|
+
* back, and a filter back at its default is forgotten.
|
|
13
|
+
*/
|
|
14
|
+
export declare function useFilterPersistence(params: UseFilterPersistenceParams): void;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { watch } from "vue";
|
|
2
|
+
import {
|
|
3
|
+
isTableFilterRuleDefault,
|
|
4
|
+
parsePersistedFilterRule,
|
|
5
|
+
persistedFilterStorageKey,
|
|
6
|
+
serializePersistedFilterRule
|
|
7
|
+
} from "../utils/index.js";
|
|
8
|
+
export function useFilterPersistence(params) {
|
|
9
|
+
const storage = resolveStorage();
|
|
10
|
+
const persisted = (params.schema.value.filters?.ui ?? []).filter(
|
|
11
|
+
(definition) => definition.behavior?.persist === true
|
|
12
|
+
);
|
|
13
|
+
if (!storage || persisted.length === 0) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const storageKey = (definition) => persistedFilterStorageKey({
|
|
17
|
+
tableKey: params.schema.value.tableKey,
|
|
18
|
+
filterKey: definition.key
|
|
19
|
+
});
|
|
20
|
+
const current = params.filters.value.ui;
|
|
21
|
+
const restored = persisted.flatMap((definition) => {
|
|
22
|
+
const rule = current.find((candidate) => candidate.key === definition.key);
|
|
23
|
+
if (rule && !isTableFilterRuleDefault({ definition, rule })) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
const stored = parsePersistedFilterRule({
|
|
27
|
+
definition,
|
|
28
|
+
raw: safeRead(storage, storageKey(definition))
|
|
29
|
+
});
|
|
30
|
+
return stored ? [stored] : [];
|
|
31
|
+
});
|
|
32
|
+
if (restored.length > 0) {
|
|
33
|
+
const keys = new Set(restored.map((rule) => rule.key));
|
|
34
|
+
params.restore({
|
|
35
|
+
...params.filters.value,
|
|
36
|
+
ui: [...current.filter((rule) => !keys.has(rule.key)), ...restored]
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
watch(
|
|
40
|
+
() => params.filters.value.ui,
|
|
41
|
+
(rules) => {
|
|
42
|
+
for (const definition of persisted) {
|
|
43
|
+
const rule = rules.find((candidate) => candidate.key === definition.key);
|
|
44
|
+
safeWrite(
|
|
45
|
+
storage,
|
|
46
|
+
storageKey(definition),
|
|
47
|
+
rule && !isTableFilterRuleDefault({ definition, rule }) ? serializePersistedFilterRule({ definition, rule }) : null
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
function resolveStorage() {
|
|
54
|
+
try {
|
|
55
|
+
return typeof window === "undefined" ? null : window.localStorage;
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function safeRead(storage, key) {
|
|
61
|
+
try {
|
|
62
|
+
return storage.getItem(key);
|
|
63
|
+
} catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function safeWrite(storage, key, value) {
|
|
68
|
+
try {
|
|
69
|
+
if (value === null) {
|
|
70
|
+
storage.removeItem(key);
|
|
71
|
+
} else {
|
|
72
|
+
storage.setItem(key, value);
|
|
73
|
+
}
|
|
74
|
+
} catch {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
resolveFilterSupportedOperators,
|
|
20
20
|
serializeTableFilterQueryState
|
|
21
21
|
} from "../utils/index.js";
|
|
22
|
+
import { useFilterPersistence } from "./use-filter-persistence.js";
|
|
22
23
|
export function useQueryState(params) {
|
|
23
24
|
const defaultPageSize = getDefaultPageSize({
|
|
24
25
|
layout: params.activeLayout.value,
|
|
@@ -96,32 +97,36 @@ export function useQueryState(params) {
|
|
|
96
97
|
sortingState.value = value ? { dir: value.dir, key: value.key } : { dir: void 0, key: "" };
|
|
97
98
|
}
|
|
98
99
|
});
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
100
|
+
const filterSchema = {
|
|
101
|
+
search: { codec: stringCodec, defaultValue: "" },
|
|
102
|
+
ui: dynamicQueryState({
|
|
103
|
+
defaultValue: resolveTableFilterDefaultRules(params.schema.value.filters?.ui ?? []),
|
|
104
|
+
definitions: () => params.schema.value.filters?.ui ?? [],
|
|
105
|
+
parse(entries, definitions) {
|
|
106
|
+
return parseTableFilterQueryState({ definitions, entries });
|
|
107
|
+
},
|
|
108
|
+
resolve(filter) {
|
|
109
|
+
const definition = normalizeFilterDefinition(filter);
|
|
110
|
+
const operators = resolveFilterSupportedOperators(definition);
|
|
111
|
+
const defaultOp = resolveFilterDefaultOperator(definition);
|
|
112
|
+
const codec = createTableFilterValueCodec(definition);
|
|
113
|
+
return operators.map((op) => ({
|
|
114
|
+
codec,
|
|
115
|
+
urlKey: op === defaultOp ? definition.key : `${definition.key}~${op}`
|
|
116
|
+
}));
|
|
117
|
+
},
|
|
118
|
+
serialize(rules, definitions) {
|
|
119
|
+
return serializeTableFilterQueryState({ definitions, rules });
|
|
120
|
+
},
|
|
121
|
+
urlPrefix: "ui"
|
|
122
|
+
})
|
|
123
|
+
};
|
|
124
|
+
const filters = useQueryStates({ historyMode: "push", prefix: "f", schema: filterSchema });
|
|
125
|
+
useFilterPersistence({
|
|
126
|
+
schema: params.schema,
|
|
127
|
+
filters,
|
|
128
|
+
restore(state) {
|
|
129
|
+
useQueryStates({ historyMode: "replace", prefix: "f", schema: filterSchema }).value = state;
|
|
125
130
|
}
|
|
126
131
|
});
|
|
127
132
|
return {
|
|
@@ -23,6 +23,10 @@ export function useTableApi(params) {
|
|
|
23
23
|
// SAFETY: raw rows follow the same schema source contract before client-side shaping.
|
|
24
24
|
rawRows: computed(() => params.queryContent.rawData.value.rows),
|
|
25
25
|
rawRowCount: computed(() => params.queryContent.rawData.value.rowCount),
|
|
26
|
+
// SAFETY: filtered rows are the raw source rows after client filtering and sorting.
|
|
27
|
+
filteredRows: computed(
|
|
28
|
+
() => params.queryContent.filteredRows.value
|
|
29
|
+
),
|
|
26
30
|
context: computed(
|
|
27
31
|
// SAFETY: context keys are decoded from the schema context items before publication.
|
|
28
32
|
() => params.queryContent.contextData.value
|
|
@@ -59,6 +59,7 @@ export function useTableData(params) {
|
|
|
59
59
|
() => params.state.queryState.sorting.value ? [params.state.queryState.sorting.value] : []
|
|
60
60
|
);
|
|
61
61
|
const requestFilters = computed(() => params.state.resolvedFilterState.value);
|
|
62
|
+
const rowFilters = computed(() => params.state.rowFilterState.value);
|
|
62
63
|
const requestSearch = computed(() => ({
|
|
63
64
|
fields: params.schema.value.filters?.search?.fields ?? [],
|
|
64
65
|
value: params.state.queryState.filters.value.search
|
|
@@ -214,7 +215,7 @@ export function useTableData(params) {
|
|
|
214
215
|
return rawData.value.rows;
|
|
215
216
|
}
|
|
216
217
|
return filterClientRows({
|
|
217
|
-
filters:
|
|
218
|
+
filters: rowFilters.value,
|
|
218
219
|
rows: rawData.value.rows,
|
|
219
220
|
search: requestSearch.value
|
|
220
221
|
});
|
|
@@ -269,7 +270,7 @@ export function useTableData(params) {
|
|
|
269
270
|
if (params.schema.value.source.mode === "client") {
|
|
270
271
|
return executeClientFacets({
|
|
271
272
|
facets: clientFacetDescriptors.value,
|
|
272
|
-
request: requestContext.value,
|
|
273
|
+
request: { ...requestContext.value, filters: rowFilters.value },
|
|
273
274
|
rows: rawData.value.rows
|
|
274
275
|
});
|
|
275
276
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { computed } from "vue";
|
|
2
|
-
import { createResolvedFilterState } from "../utils/index.js";
|
|
2
|
+
import { createResolvedFilterState, withoutQueryFilterRules } from "../utils/index.js";
|
|
3
3
|
import { useQueryState } from "./use-query-state.js";
|
|
4
4
|
export function useTableState(params) {
|
|
5
5
|
const queryState = useQueryState({
|
|
@@ -13,8 +13,19 @@ export function useTableState(params) {
|
|
|
13
13
|
staticFilters: params.schema.value.filters?.static
|
|
14
14
|
})
|
|
15
15
|
);
|
|
16
|
+
const rowFilterState = computed(
|
|
17
|
+
() => createResolvedFilterState({
|
|
18
|
+
definitions: params.schema.value.filters?.ui ?? [],
|
|
19
|
+
filters: withoutQueryFilterRules({
|
|
20
|
+
definitions: params.schema.value.filters?.ui ?? [],
|
|
21
|
+
filters: queryState.filters.value
|
|
22
|
+
}),
|
|
23
|
+
staticFilters: params.schema.value.filters?.static
|
|
24
|
+
})
|
|
25
|
+
);
|
|
16
26
|
return {
|
|
17
27
|
queryState,
|
|
18
|
-
resolvedFilterState
|
|
28
|
+
resolvedFilterState,
|
|
29
|
+
rowFilterState
|
|
19
30
|
};
|
|
20
31
|
}
|
|
@@ -31,6 +31,17 @@ export interface TableFilterBehaviorCommon<TOperator extends TableFilterOperator
|
|
|
31
31
|
commitMode?: TableFilterCommitMode;
|
|
32
32
|
clearOnOperatorChange?: boolean;
|
|
33
33
|
reopenOnOperatorChange?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* What the filter narrows. `rows` (default) matches every row against it. `query` only hands the
|
|
36
|
+
* value to the source query, through its `filters`, so a client source can ask the server for a
|
|
37
|
+
* different dataset (a period, a scope) while its rows are never matched against the rule.
|
|
38
|
+
*/
|
|
39
|
+
applyTo?: 'rows' | 'query';
|
|
40
|
+
/**
|
|
41
|
+
* Remembers the last value in `localStorage`, per table key and filter key. It is restored when
|
|
42
|
+
* the URL carries no value of its own, and forgotten once the filter returns to its default.
|
|
43
|
+
*/
|
|
44
|
+
persist?: boolean;
|
|
34
45
|
}
|
|
35
46
|
export interface TableFilterUiActionLabelsConfig {
|
|
36
47
|
actions?: {
|
|
@@ -697,14 +708,34 @@ export type TableOptionFilterOptions<TRow extends GenericObject = GenericObject,
|
|
|
697
708
|
export type TableBooleanFilterOptions<TRow extends GenericObject = GenericObject, TContext extends GenericObject = GenericObject, TKey extends string = TableKnownFieldPath<TRow>> = Omit<TableBooleanFilterDefinition<TRow, TContext, TKey>, 'key' | 'kind'>;
|
|
698
709
|
export type TableNumberFilterOptions<TRow extends GenericObject = GenericObject, TContext extends GenericObject = GenericObject, TKey extends string = TableKnownFieldPath<TRow>> = Omit<TableNumberFilterDefinition<TRow, TContext, TKey>, 'key' | 'kind'>;
|
|
699
710
|
export type TableDateFilterOptions<TRow extends GenericObject = GenericObject, TContext extends GenericObject = GenericObject, TKey extends string = TableKnownFieldPath<TRow>> = Omit<TableDateFilterDefinition<TRow, TContext, TKey>, 'key' | 'kind'>;
|
|
711
|
+
/**
|
|
712
|
+
* Keys a filter may use. A row field path filters rows; any other key names a query parameter of
|
|
713
|
+
* the source and requires `behavior.applyTo: 'query'`.
|
|
714
|
+
*/
|
|
715
|
+
export type TableFilterKey<TRow extends GenericObject = GenericObject> = TableKnownFieldPath<TRow> | (string & {});
|
|
716
|
+
/** What a filter key adds to its options: nothing for a row field, `applyTo: 'query'` otherwise. */
|
|
717
|
+
export type TableFilterKeyScope<TRow extends GenericObject, TKey extends string> = TKey extends TableKnownFieldPath<TRow> ? unknown : {
|
|
718
|
+
behavior: {
|
|
719
|
+
applyTo: 'query';
|
|
720
|
+
};
|
|
721
|
+
};
|
|
700
722
|
export interface TableFilterBuilder<TRow extends GenericObject = GenericObject, TContext extends GenericObject = GenericObject> {
|
|
701
|
-
text<TKey extends
|
|
702
|
-
option<TKey extends
|
|
703
|
-
boolean<TKey extends
|
|
704
|
-
number<TKey extends
|
|
705
|
-
date<TKey extends
|
|
723
|
+
text<TKey extends TableFilterKey<TRow>>(key: TKey, options: TableTextFilterOptions<TRow, TContext, TKey> & TableFilterKeyScope<TRow, TKey>): TableTextFilterDefinition<TRow, TContext, TKey> & TableFilterKeyScope<TRow, TKey>;
|
|
724
|
+
option<TKey extends TableFilterKey<TRow>, TValue extends TableFilterPrimitiveValue, TPresentation extends TableOptionFilterPresentation = TableOptionFilterPresentation>(key: TKey, options: TableOptionFilterOptions<TRow, TContext, TKey, TValue, TPresentation> & TableFilterKeyScope<TRow, TKey>): TableOptionFilterDefinition<TRow, TContext, TKey, TValue, TPresentation> & TableFilterKeyScope<TRow, TKey>;
|
|
725
|
+
boolean<TKey extends TableFilterKey<TRow>>(key: TKey, options: TableBooleanFilterOptions<TRow, TContext, TKey> & TableFilterKeyScope<TRow, TKey>): TableBooleanFilterDefinition<TRow, TContext, TKey> & TableFilterKeyScope<TRow, TKey>;
|
|
726
|
+
number<TKey extends TableFilterKey<TRow>>(key: TKey, options: TableNumberFilterOptions<TRow, TContext, TKey> & TableFilterKeyScope<TRow, TKey>): TableNumberFilterDefinition<TRow, TContext, TKey> & TableFilterKeyScope<TRow, TKey>;
|
|
727
|
+
date<TKey extends TableFilterKey<TRow>>(key: TKey, options: TableDateFilterOptions<TRow, TContext, TKey> & TableFilterKeyScope<TRow, TKey>): TableDateFilterDefinition<TRow, TContext, TKey> & TableFilterKeyScope<TRow, TKey>;
|
|
706
728
|
}
|
|
707
|
-
|
|
729
|
+
/**
|
|
730
|
+
* One filter of a table: a row filter keyed by a row field, or a query filter
|
|
731
|
+
* (`behavior.applyTo: 'query'`) keyed by any query parameter.
|
|
732
|
+
*/
|
|
733
|
+
export type TableUiFilterCollectionItem<TRow extends GenericObject = GenericObject, TContext extends GenericObject = GenericObject, TKey extends string = TableKnownFieldPath<TRow>> = TableUiFilterDefinition<TRow, TContext, TKey> | (TableUiFilterDefinition<TRow, TContext, string> & {
|
|
734
|
+
behavior: {
|
|
735
|
+
applyTo: 'query';
|
|
736
|
+
};
|
|
737
|
+
});
|
|
738
|
+
export type TableUiFilterCollection<TRow extends GenericObject = GenericObject, TContext extends GenericObject = GenericObject, TKey extends string = TableKnownFieldPath<TRow>> = TableUiFilterCollectionItem<TRow, TContext, TKey>[] | ((filter: TableFilterBuilder<TRow, TContext>) => TableUiFilterCollectionItem<TRow, TContext, TKey>[]);
|
|
708
739
|
export interface TableFiltersSchema<TRow extends GenericObject = GenericObject, TContext extends GenericObject = GenericObject, TKey extends string = TableKnownFieldPath<TRow>> {
|
|
709
740
|
search?: TableSearchFilter<TRow>;
|
|
710
741
|
static?: TableStaticFilterNode<TRow, TContext, TKey>[];
|
|
@@ -87,6 +87,11 @@ export interface TableApi<TSchema = TableSchemaView> {
|
|
|
87
87
|
totalRowCount: ComputedRef<number | null>;
|
|
88
88
|
rawRows: ComputedRef<ExtractTableRow<TSchema>[]>;
|
|
89
89
|
rawRowCount: ComputedRef<number | null>;
|
|
90
|
+
/**
|
|
91
|
+
* Every row that passes the filters and the search, sorted, before pagination. Client sources
|
|
92
|
+
* only; `undefined` for remote sources, which never hold the whole result.
|
|
93
|
+
*/
|
|
94
|
+
filteredRows: ComputedRef<ExtractTableRow<TSchema>[] | undefined>;
|
|
90
95
|
context: ComputedRef<ExtractTableContextData<TSchema>>;
|
|
91
96
|
pageContext: ComputedRef<ExtractTablePageContextData<TSchema>>;
|
|
92
97
|
requestContext: ReturnType<typeof useTableData>['requestContext'];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TableQueryStateFilterRule, TableUiFilterDefinition } from '../types/index.js';
|
|
2
|
+
/** Storage key of one persisted filter, scoped by table key. */
|
|
3
|
+
export declare function persistedFilterStorageKey(options: {
|
|
4
|
+
tableKey: string;
|
|
5
|
+
filterKey: string;
|
|
6
|
+
}): string;
|
|
7
|
+
/** Serializes a rule with the filter's URL codec, or returns `null` when it has nothing to keep. */
|
|
8
|
+
export declare function serializePersistedFilterRule(options: {
|
|
9
|
+
definition: TableUiFilterDefinition;
|
|
10
|
+
rule: TableQueryStateFilterRule;
|
|
11
|
+
}): string | null;
|
|
12
|
+
/** Reads a stored rule back, dropping anything the filter no longer accepts. */
|
|
13
|
+
export declare function parsePersistedFilterRule(options: {
|
|
14
|
+
definition: TableUiFilterDefinition;
|
|
15
|
+
raw: string | null;
|
|
16
|
+
}): TableQueryStateFilterRule | null;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { isObject, isString } from "../../shared/utils/predicate.js";
|
|
2
|
+
import {
|
|
3
|
+
createTableFilterValueCodec,
|
|
4
|
+
normalizeFilterDefinition,
|
|
5
|
+
resolveFilterDefaultOperator,
|
|
6
|
+
resolveFilterSupportedOperators
|
|
7
|
+
} from "./query-state.js";
|
|
8
|
+
const STORAGE_PREFIX = "nuxt-ui-tools:table-filter";
|
|
9
|
+
export function persistedFilterStorageKey(options) {
|
|
10
|
+
return `${STORAGE_PREFIX}:${options.tableKey}:${options.filterKey}`;
|
|
11
|
+
}
|
|
12
|
+
export function serializePersistedFilterRule(options) {
|
|
13
|
+
const normalized = normalizeFilterDefinition(options.definition);
|
|
14
|
+
const value = createTableFilterValueCodec(normalized).serialize(options.rule.value);
|
|
15
|
+
return value === null ? null : JSON.stringify({
|
|
16
|
+
operator: options.rule.operator ?? resolveFilterDefaultOperator(normalized),
|
|
17
|
+
value
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export function parsePersistedFilterRule(options) {
|
|
21
|
+
if (!options.raw) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const stored = parseStoredRule(options.raw);
|
|
25
|
+
if (!stored) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const normalized = normalizeFilterDefinition(options.definition);
|
|
29
|
+
const operator = resolveFilterSupportedOperators(normalized).find(
|
|
30
|
+
(candidate) => candidate === stored.operator
|
|
31
|
+
);
|
|
32
|
+
const value = createTableFilterValueCodec(normalized).parse(stored.value);
|
|
33
|
+
return operator && value !== void 0 ? { key: options.definition.key, operator, value } : null;
|
|
34
|
+
}
|
|
35
|
+
function parseStoredRule(raw) {
|
|
36
|
+
try {
|
|
37
|
+
const stored = JSON.parse(raw);
|
|
38
|
+
return isObject(stored) && isString(stored.operator) && isString(stored.value) ? { operator: stored.operator, value: stored.value } : null;
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -4,6 +4,7 @@ export * from './columns/index.js';
|
|
|
4
4
|
export * from './cursor-query.js';
|
|
5
5
|
export * from './data-list-ui.js';
|
|
6
6
|
export * from './facets.js';
|
|
7
|
+
export * from './filter-persistence.js';
|
|
7
8
|
export * from './filters/index.js';
|
|
8
9
|
export * from './pagination.js';
|
|
9
10
|
export * from './prefetch.js';
|
|
@@ -4,6 +4,7 @@ export * from "./columns/index.js";
|
|
|
4
4
|
export * from "./cursor-query.js";
|
|
5
5
|
export * from "./data-list-ui.js";
|
|
6
6
|
export * from "./facets.js";
|
|
7
|
+
export * from "./filter-persistence.js";
|
|
7
8
|
export * from "./filters/index.js";
|
|
8
9
|
export * from "./pagination.js";
|
|
9
10
|
export * from "./prefetch.js";
|
|
@@ -5,3 +5,11 @@ export declare function createResolvedFilterState<TRow extends GenericObject = G
|
|
|
5
5
|
staticFilters?: TableStaticFilterNode<TRow, TContext, TKey>[];
|
|
6
6
|
context?: TContext;
|
|
7
7
|
}): TableResolvedFilterGroup<string>;
|
|
8
|
+
/**
|
|
9
|
+
* Drops the rules of filters marked `behavior.applyTo: 'query'`, which feed the source query but
|
|
10
|
+
* never narrow client rows.
|
|
11
|
+
*/
|
|
12
|
+
export declare function withoutQueryFilterRules(options: {
|
|
13
|
+
definitions: TableUiFilterDefinition[];
|
|
14
|
+
filters: TableFilterState;
|
|
15
|
+
}): TableFilterState;
|
|
@@ -67,3 +67,9 @@ function normalizeResolvedFilterNode(node) {
|
|
|
67
67
|
function isResolvedFilterGroup(value) {
|
|
68
68
|
return !!value && isObject(value) && "type" in value && value.type === "group" && "children" in value && isArray(value.children);
|
|
69
69
|
}
|
|
70
|
+
export function withoutQueryFilterRules(options) {
|
|
71
|
+
const queryKeys = new Set(
|
|
72
|
+
options.definitions.filter((definition) => definition.behavior?.applyTo === "query").map((definition) => definition.key)
|
|
73
|
+
);
|
|
74
|
+
return queryKeys.size === 0 ? options.filters : { ...options.filters, ui: options.filters.ui.filter((rule) => !queryKeys.has(rule.key)) };
|
|
75
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-ui-tools",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.27.1",
|
|
4
4
|
"description": "Nuxt module and runtime toolkit for UI-heavy Nuxt applications",
|
|
5
5
|
"homepage": "https://github.com/ChronicStone/nuxt-ui-tools#readme",
|
|
6
6
|
"bugs": "https://github.com/ChronicStone/nuxt-ui-tools/issues",
|