@platforma-sdk/ui-vue 1.63.12 → 1.65.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/.turbo/turbo-build.log +38 -32
- package/.turbo/turbo-formatter$colon$check.log +2 -2
- package/.turbo/turbo-linter$colon$check.log +2 -2
- package/.turbo/turbo-types$colon$check.log +1 -1
- package/CHANGELOG.md +24 -0
- package/dist/components/PlAdvancedFilter/FilterEditor.js.map +1 -1
- package/dist/components/PlAdvancedFilter/FilterEditor.style.js.map +1 -1
- package/dist/components/PlAdvancedFilter/FilterEditor.vue.d.ts +3 -8
- package/dist/components/PlAdvancedFilter/FilterEditor.vue.d.ts.map +1 -1
- package/dist/components/PlAdvancedFilter/FilterEditor.vue2.js +164 -151
- package/dist/components/PlAdvancedFilter/FilterEditor.vue2.js.map +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.js.map +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.style.js +8 -7
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.style.js.map +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue.css +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue.d.ts +24 -8
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue.d.ts.map +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js +176 -110
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js.map +1 -1
- package/dist/components/PlAdvancedFilter/types.d.ts +2 -0
- package/dist/components/PlAdvancedFilter/types.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.style.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js +116 -109
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js.map +1 -1
- package/dist/components/PlAgDataTable/compositions/useFilterableColumns.js +3 -3
- package/dist/components/PlAgDataTable/compositions/useFilterableColumns.js.map +1 -1
- package/dist/components/PlAgDataTable/sources/table-source-v2.d.ts +6 -5
- package/dist/components/PlAgDataTable/sources/table-source-v2.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/sources/table-source-v2.js +122 -88
- package/dist/components/PlAgDataTable/sources/table-source-v2.js.map +1 -1
- package/dist/components/PlAgDataTable/sources/table-state-v2.d.ts +6 -3
- package/dist/components/PlAgDataTable/sources/table-state-v2.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/sources/table-state-v2.js +182 -97
- package/dist/components/PlAgDataTable/sources/table-state-v2.js.map +1 -1
- package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.js.map +1 -1
- package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.style.js.map +1 -1
- package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue.d.ts.map +1 -1
- package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue2.js +37 -42
- package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue2.js.map +1 -1
- package/dist/components/PlAgGridColumnManager/useFilteredItems.d.ts +5 -5
- package/dist/components/PlAgGridColumnManager/useFilteredItems.d.ts.map +1 -1
- package/dist/components/PlAgGridColumnManager/useFilteredItems.js +2 -2
- package/dist/components/PlAgGridColumnManager/useFilteredItems.js.map +1 -1
- package/dist/components/PlAgGridColumnManager/useGridColumns.js +14 -0
- package/dist/components/PlAgGridColumnManager/useGridColumns.js.map +1 -0
- package/dist/components/PlAnnotations/components/FilterSidebar.js.map +1 -1
- package/dist/components/PlAnnotations/components/FilterSidebar.style.js.map +1 -1
- package/dist/components/PlAnnotations/components/FilterSidebar.vue.d.ts.map +1 -1
- package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js +7 -4
- package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js.map +1 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.js.map +1 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.style.js +5 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.style.js.map +1 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.vue.css +1 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.vue.d.ts +7 -9
- package/dist/components/PlTableFilters/PlTableFiltersV2.vue.d.ts.map +1 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.vue2.js +72 -47
- package/dist/components/PlTableFilters/PlTableFiltersV2.vue2.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/util/helpers/dist/functions.js.map +1 -1
- package/dist/lib/util/helpers/dist/objects.js +4 -1
- package/dist/lib/util/helpers/dist/objects.js.map +1 -1
- package/package.json +8 -7
- package/src/components/PlAdvancedFilter/FilterEditor.vue +99 -55
- package/src/components/PlAdvancedFilter/PlAdvancedFilter.vue +163 -95
- package/src/components/PlAdvancedFilter/types.ts +6 -1
- package/src/components/PlAgDataTable/PlAgDataTableV2.vue +26 -7
- package/src/components/PlAgDataTable/compositions/useFilterableColumns.ts +4 -4
- package/src/components/PlAgDataTable/sources/table-source-v2.ts +231 -131
- package/src/components/PlAgDataTable/sources/table-state-v2.ts +249 -70
- package/src/components/PlAgGridColumnManager/PlAgGridColumnManager.vue +17 -35
- package/src/components/PlAgGridColumnManager/useFilteredItems.ts +9 -11
- package/src/components/PlAgGridColumnManager/useGridColumns.ts +26 -0
- package/src/components/PlAnnotations/components/FilterSidebar.vue +3 -2
- package/src/components/PlTableFilters/PlTableFiltersV2.vue +76 -26
- package/src/index.ts +4 -0
|
@@ -12,18 +12,19 @@ import {
|
|
|
12
12
|
type PlDataTableStateV2,
|
|
13
13
|
type PlDataTableStateV2CacheEntry,
|
|
14
14
|
type PlDataTableStateV2Normalized,
|
|
15
|
-
type PObjectId,
|
|
16
15
|
type PTableParamsV2,
|
|
17
16
|
type PTableSorting,
|
|
17
|
+
type PlDataTableFilterSpecLeaf,
|
|
18
|
+
type PlDataTableFilterMeta,
|
|
18
19
|
type PlDataTableFilters,
|
|
19
20
|
distillFilterSpec,
|
|
20
21
|
PlDataTableFiltersWithMeta,
|
|
21
22
|
getPTableColumnId,
|
|
22
23
|
CanonicalizedJson,
|
|
23
24
|
} from "@platforma-sdk/model";
|
|
24
|
-
import { computed,
|
|
25
|
+
import { computed, type Ref, type WritableComputedRef } from "vue";
|
|
25
26
|
import type { PlDataTableSettingsV2 } from "../types";
|
|
26
|
-
import { isJsonEqual, randomInt } from "@milaboratories/helpers";
|
|
27
|
+
import { isJsonEqual, randomInt, getField, Nil } from "@milaboratories/helpers";
|
|
27
28
|
import { computedCached } from "@milaboratories/uikit";
|
|
28
29
|
import { isStringValueType, isNumericValueType } from "../../PlAdvancedFilter/utils";
|
|
29
30
|
import { debounce, isNil } from "es-toolkit";
|
|
@@ -32,11 +33,15 @@ export function useTableState(
|
|
|
32
33
|
tableStateDenormalized: Ref<PlDataTableStateV2>,
|
|
33
34
|
settings: Ref<PlDataTableSettingsV2>,
|
|
34
35
|
columns: Ref<PTableColumnSpec[]>,
|
|
36
|
+
defaultFilters: Ref<Nil | PlDataTableFilters>,
|
|
35
37
|
): {
|
|
36
38
|
gridState: WritableComputedRef<PlDataTableGridStateCore>;
|
|
37
39
|
sheetsState: WritableComputedRef<PlDataTableSheetState[]>;
|
|
38
|
-
|
|
40
|
+
|
|
39
41
|
searchString: WritableComputedRef<string>;
|
|
42
|
+
filtersState: Ref<PlDataTableFiltersWithMeta>;
|
|
43
|
+
defaultFiltersState: Ref<null | PlDataTableFiltersWithMeta>;
|
|
44
|
+
resetDefaultFilters: () => void;
|
|
40
45
|
} {
|
|
41
46
|
const tableStateNormalized = computedCached<PlDataTableStateV2Normalized>({
|
|
42
47
|
get: () => upgradePlDataTableStateV2(tableStateDenormalized.value),
|
|
@@ -113,18 +118,11 @@ export function useTableState(
|
|
|
113
118
|
},
|
|
114
119
|
});
|
|
115
120
|
|
|
121
|
+
// --- User filters (editable by user) ---
|
|
116
122
|
const filtersState = computed<PlDataTableFiltersWithMeta>({
|
|
117
123
|
get: () => {
|
|
118
124
|
const raw = tableState.value.filtersState;
|
|
119
|
-
|
|
120
|
-
raw &&
|
|
121
|
-
(raw.type === "and" || raw.type === "or") &&
|
|
122
|
-
"filters" in raw &&
|
|
123
|
-
Array.isArray(raw.filters);
|
|
124
|
-
|
|
125
|
-
return isCorrect
|
|
126
|
-
? (raw satisfies PlDataTableFiltersWithMeta)
|
|
127
|
-
: { id: randomInt(), type: "and" as const, isExpanded: true, filters: [] };
|
|
125
|
+
return isNil(raw) ? getEmptyGroupWithMeta() : normalizeFiltersState(raw);
|
|
128
126
|
},
|
|
129
127
|
set: (filtersState: PlDataTableFiltersWithMeta) => {
|
|
130
128
|
const oldState = tableState.value;
|
|
@@ -136,12 +134,35 @@ export function useTableState(
|
|
|
136
134
|
}
|
|
137
135
|
},
|
|
138
136
|
});
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
(
|
|
143
|
-
|
|
144
|
-
|
|
137
|
+
|
|
138
|
+
// --- Default filters (from model, separate list) ---
|
|
139
|
+
const defaultFiltersState = computed<null | PlDataTableFiltersWithMeta>({
|
|
140
|
+
get: () => {
|
|
141
|
+
const raw = tableState.value.defaultFiltersState;
|
|
142
|
+
if (!isNil(raw)) {
|
|
143
|
+
return normalizeFiltersState(raw);
|
|
144
|
+
}
|
|
145
|
+
if (!isNil(defaultFilters.value)) {
|
|
146
|
+
return annotateFiltersWithIds(normalizeFiltersState(defaultFilters.value));
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
},
|
|
150
|
+
set: (defaultFiltersState: null | PlDataTableFiltersWithMeta) => {
|
|
151
|
+
const oldState = tableState.value;
|
|
152
|
+
if (oldState.sourceId) {
|
|
153
|
+
tableState.value = {
|
|
154
|
+
...oldState,
|
|
155
|
+
defaultFiltersState,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
function resetDefaultFilters(): void {
|
|
162
|
+
defaultFiltersState.value = isNil(defaultFilters.value)
|
|
163
|
+
? null
|
|
164
|
+
: annotateFiltersWithIds(normalizeFiltersState(defaultFilters.value));
|
|
165
|
+
}
|
|
145
166
|
|
|
146
167
|
const searchString = computed<string>({
|
|
147
168
|
get: () => tableState.value.searchString ?? "",
|
|
@@ -156,9 +177,18 @@ export function useTableState(
|
|
|
156
177
|
},
|
|
157
178
|
});
|
|
158
179
|
|
|
159
|
-
return {
|
|
180
|
+
return {
|
|
181
|
+
gridState,
|
|
182
|
+
sheetsState,
|
|
183
|
+
searchString,
|
|
184
|
+
filtersState,
|
|
185
|
+
defaultFiltersState,
|
|
186
|
+
resetDefaultFilters,
|
|
187
|
+
};
|
|
160
188
|
}
|
|
161
189
|
|
|
190
|
+
// --- Types ---
|
|
191
|
+
|
|
162
192
|
type PlDataTableStateV2CacheEntryNullable =
|
|
163
193
|
| PlDataTableStateV2CacheEntry
|
|
164
194
|
| {
|
|
@@ -166,51 +196,138 @@ type PlDataTableStateV2CacheEntryNullable =
|
|
|
166
196
|
gridState: Record<string, never>;
|
|
167
197
|
sheetsState: [];
|
|
168
198
|
filtersState: null;
|
|
199
|
+
defaultFiltersState: null;
|
|
169
200
|
searchString?: string;
|
|
170
201
|
};
|
|
171
202
|
|
|
172
|
-
|
|
203
|
+
type FilterNode = FilterSpec<PlDataTableFilterSpecLeaf>;
|
|
204
|
+
type AnnotatedFilterSpec = FilterSpec<PlDataTableFilterSpecLeaf, PlDataTableFilterMeta>;
|
|
205
|
+
|
|
206
|
+
// --- Core ---
|
|
207
|
+
|
|
208
|
+
function createPTableParams(
|
|
209
|
+
state: PlDataTableStateV2CacheEntry,
|
|
210
|
+
filterableColumns: PTableColumnSpec[],
|
|
211
|
+
): PTableParamsV2 {
|
|
212
|
+
// User filters: sheets + user filter state + search
|
|
213
|
+
const searchNode = createSearchFilterNode(filterableColumns, state.searchString);
|
|
214
|
+
const unsuppressedUserFilters = isNil(state.filtersState)
|
|
215
|
+
? null
|
|
216
|
+
: stripSuppressedFilters(state.filtersState);
|
|
217
|
+
const userParts = [
|
|
218
|
+
...convertPartitionFiltersToFilterSpec(state.sheetsState),
|
|
219
|
+
...(isNil(unsuppressedUserFilters) ? [] : [unsuppressedUserFilters]),
|
|
220
|
+
...(isNil(searchNode) ? [] : [searchNode]),
|
|
221
|
+
];
|
|
222
|
+
const filters: null | PlDataTableFilters = distillFilterSpec(
|
|
223
|
+
userParts.length === 0
|
|
224
|
+
? null
|
|
225
|
+
: userParts.length === 1
|
|
226
|
+
? userParts[0]
|
|
227
|
+
: { type: "and", filters: userParts },
|
|
228
|
+
);
|
|
229
|
+
const unsuppressedDefaultFilters = isNil(state.defaultFiltersState)
|
|
230
|
+
? null
|
|
231
|
+
: stripSuppressedFilters(state.defaultFiltersState);
|
|
232
|
+
const defaultFilters: null | PlDataTableFilters = isNil(unsuppressedDefaultFilters)
|
|
233
|
+
? null
|
|
234
|
+
: // If all filters are suppressed, we should pass an empty filter group instead of null to prevent fallback to defaults in the model
|
|
235
|
+
(distillFilterSpec(unsuppressedDefaultFilters) ?? getEmptyGroup());
|
|
236
|
+
|
|
173
237
|
return {
|
|
174
|
-
sourceId:
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
238
|
+
sourceId: state.sourceId,
|
|
239
|
+
hiddenColIds: getHiddenColIds(state.gridState.columnVisibility),
|
|
240
|
+
sorting: convertAgSortingToPTableSorting(state.gridState.sort),
|
|
241
|
+
filters,
|
|
242
|
+
defaultFilters,
|
|
178
243
|
};
|
|
179
244
|
}
|
|
180
245
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
246
|
+
/**
|
|
247
|
+
* Normalizes raw filter state into a valid root filter structure.
|
|
248
|
+
* Valid structure is Root(Group, Group, ...) — double nesting required:
|
|
249
|
+
* root is and/or group, each child is also and/or group containing leaf filters.
|
|
250
|
+
* - null/undefined/invalid → empty root
|
|
251
|
+
* - Leaf node → Root(Group(leaf))
|
|
252
|
+
* - Group with leaf children → Root(Group(leaves...))
|
|
253
|
+
* - Group with group children → as-is
|
|
254
|
+
*/
|
|
255
|
+
function normalizeFiltersState(raw: FilterNode) {
|
|
256
|
+
// Leaf node → wrap in double nesting: Root(Group(leaf))
|
|
257
|
+
if (raw.type !== "and" && raw.type !== "or" && raw.type !== "not") {
|
|
258
|
+
if ("type" in raw && !isNil(raw.type)) {
|
|
259
|
+
return {
|
|
260
|
+
id: randomInt(),
|
|
261
|
+
type: "and" as const,
|
|
262
|
+
isExpanded: true,
|
|
263
|
+
filters: [
|
|
264
|
+
{
|
|
265
|
+
id: randomInt(),
|
|
266
|
+
type: "and" as const,
|
|
267
|
+
isExpanded: true,
|
|
268
|
+
filters: [raw as AnnotatedFilterSpec],
|
|
269
|
+
} as AnnotatedFilterSpec,
|
|
270
|
+
],
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
return getEmptyGroupWithMeta();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Already a group — ensure children are also groups (double nesting)
|
|
277
|
+
if ((raw.type === "and" || raw.type === "or") && "filters" in raw && Array.isArray(raw.filters)) {
|
|
278
|
+
const allChildrenAreGroups = raw.filters.every(
|
|
279
|
+
(f: FilterNode) => f.type === "and" || f.type === "or" || f.type === "not",
|
|
280
|
+
);
|
|
281
|
+
if (allChildrenAreGroups) {
|
|
282
|
+
return raw as PlDataTableFiltersWithMeta;
|
|
283
|
+
}
|
|
284
|
+
// Children are leaves — wrap them in a single group
|
|
285
|
+
return {
|
|
286
|
+
id: randomInt(),
|
|
287
|
+
type: raw.type as "and" | "or",
|
|
288
|
+
isExpanded: true,
|
|
289
|
+
filters: [
|
|
290
|
+
{
|
|
291
|
+
id: randomInt(),
|
|
292
|
+
type: raw.type as "and" | "or",
|
|
293
|
+
isExpanded: true,
|
|
294
|
+
filters: raw.filters as AnnotatedFilterSpec[],
|
|
295
|
+
} as AnnotatedFilterSpec,
|
|
296
|
+
],
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return getEmptyGroupWithMeta();
|
|
190
301
|
}
|
|
191
302
|
|
|
192
|
-
function
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
303
|
+
function getEmptyGroup(): PlDataTableFilters {
|
|
304
|
+
return {
|
|
305
|
+
type: "and" as const,
|
|
306
|
+
filters: [],
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
function getEmptyGroupWithMeta(): PlDataTableFiltersWithMeta {
|
|
310
|
+
return {
|
|
311
|
+
...getEmptyGroup(),
|
|
312
|
+
id: randomInt(),
|
|
313
|
+
isExpanded: true,
|
|
314
|
+
} as PlDataTableFiltersWithMeta;
|
|
201
315
|
}
|
|
202
316
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
317
|
+
/**
|
|
318
|
+
* Recursively removes nodes where isSuppressed === true from a PlDataTableFiltersWithMeta tree.
|
|
319
|
+
*/
|
|
320
|
+
function stripSuppressedFilters(node: PlDataTableFiltersWithMeta): PlDataTableFiltersWithMeta {
|
|
321
|
+
return {
|
|
322
|
+
...node,
|
|
323
|
+
filters: node.filters
|
|
324
|
+
.filter((child) => !("isSuppressed" in child && child.isSuppressed === true))
|
|
325
|
+
.map((child) =>
|
|
326
|
+
"filters" in child && (child.type === "and" || child.type === "or")
|
|
327
|
+
? stripSuppressedFilters(child as PlDataTableFiltersWithMeta)
|
|
328
|
+
: child,
|
|
329
|
+
),
|
|
330
|
+
};
|
|
214
331
|
}
|
|
215
332
|
|
|
216
333
|
function createSearchFilterNode(
|
|
@@ -242,24 +359,86 @@ function createSearchFilterNode(
|
|
|
242
359
|
return { type: "or", filters: parts };
|
|
243
360
|
}
|
|
244
361
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
362
|
+
// --- Helpers ---
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Recursively ensures every node in a filter tree has an `id` field.
|
|
366
|
+
* Does not set `source` meta — defaults are now a separate list.
|
|
367
|
+
*/
|
|
368
|
+
function annotateFiltersWithIds(
|
|
369
|
+
filters: PlDataTableFilters | PlDataTableFiltersWithMeta,
|
|
370
|
+
): PlDataTableFiltersWithMeta {
|
|
371
|
+
return annotateNodeWithIds(filters) as PlDataTableFiltersWithMeta;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function annotateNodeWithIds(
|
|
375
|
+
node: FilterNode | PlDataTableFilters | PlDataTableFiltersWithMeta,
|
|
376
|
+
): AnnotatedFilterSpec {
|
|
377
|
+
switch (node.type) {
|
|
378
|
+
case "and":
|
|
379
|
+
return {
|
|
380
|
+
id: getField(node, "id") ?? randomInt(),
|
|
381
|
+
isExpanded: getField(node, "isExpanded") ?? true,
|
|
382
|
+
type: "and" as const,
|
|
383
|
+
filters: node.filters.map((child) => annotateNodeWithIds(child)),
|
|
384
|
+
};
|
|
385
|
+
case "or":
|
|
386
|
+
return {
|
|
387
|
+
id: getField(node, "id") ?? randomInt(),
|
|
388
|
+
isExpanded: getField(node, "isExpanded") ?? true,
|
|
389
|
+
type: "or" as const,
|
|
390
|
+
filters: node.filters.map((child) => annotateNodeWithIds(child)),
|
|
391
|
+
};
|
|
392
|
+
case "not":
|
|
393
|
+
return {
|
|
394
|
+
id: randomInt(),
|
|
395
|
+
isExpanded: true,
|
|
396
|
+
type: "not" as const,
|
|
397
|
+
filter: annotateNodeWithIds(node.filter),
|
|
398
|
+
};
|
|
399
|
+
default:
|
|
400
|
+
return { ...node, id: getField(node, "id") ?? randomInt() } as AnnotatedFilterSpec;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// --- Utilities ---
|
|
405
|
+
|
|
406
|
+
function convertPartitionFiltersToFilterSpec(
|
|
407
|
+
sheetsState: PlDataTableSheetState[],
|
|
408
|
+
): FilterSpec<FilterSpecLeaf<CanonicalizedJson<PTableColumnId>>>[] {
|
|
409
|
+
return sheetsState.map((s) => {
|
|
410
|
+
const column = canonicalizeJson<PTableColumnId>({ type: "axis", id: s.axisId });
|
|
411
|
+
return typeof s.value === "number"
|
|
412
|
+
? { type: "equal" as const, column, x: s.value }
|
|
413
|
+
: { type: "patternEquals" as const, column, value: s.value };
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function convertAgSortingToPTableSorting(state: PlDataTableGridStateCore["sort"]): PTableSorting[] {
|
|
418
|
+
return (
|
|
419
|
+
state?.sortModel.map((item) => {
|
|
420
|
+
const { spec: _, ...column } = parseJson(item.colId).labeled;
|
|
421
|
+
return {
|
|
422
|
+
column,
|
|
423
|
+
ascending: item.sort === "asc",
|
|
424
|
+
naAndAbsentAreLeastValues: item.sort === "asc",
|
|
425
|
+
};
|
|
426
|
+
}) ?? []
|
|
257
427
|
);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function getHiddenColIds(
|
|
431
|
+
state: PlDataTableGridStateCore["columnVisibility"],
|
|
432
|
+
): PTableColumnId[] | null {
|
|
433
|
+
return state?.hiddenColIds?.map((json) => getPTableColumnId(parseJson(json).source)) ?? null;
|
|
434
|
+
}
|
|
258
435
|
|
|
436
|
+
function makeDefaultState(): PlDataTableStateV2CacheEntryNullable {
|
|
259
437
|
return {
|
|
260
|
-
sourceId:
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
438
|
+
sourceId: null,
|
|
439
|
+
gridState: {},
|
|
440
|
+
sheetsState: [],
|
|
441
|
+
filtersState: null,
|
|
442
|
+
defaultFiltersState: null,
|
|
264
443
|
};
|
|
265
444
|
}
|
|
@@ -6,10 +6,11 @@ import {
|
|
|
6
6
|
PlSlideModal,
|
|
7
7
|
usePlBlockPageTitleTeleportTarget,
|
|
8
8
|
} from "@milaboratories/uikit";
|
|
9
|
-
import { type
|
|
10
|
-
import { computed, ref
|
|
9
|
+
import { type GridApi } from "ag-grid-enterprise";
|
|
10
|
+
import { computed, ref } from "vue";
|
|
11
11
|
import { PlAgDataTableRowNumberColId } from "../PlAgDataTable/sources/row-number";
|
|
12
12
|
import { useFilteredItems } from "./useFilteredItems";
|
|
13
|
+
import { useGridColumns } from "./useGridColumns";
|
|
13
14
|
|
|
14
15
|
const props = defineProps<{
|
|
15
16
|
/**
|
|
@@ -25,44 +26,25 @@ const props = defineProps<{
|
|
|
25
26
|
width?: string;
|
|
26
27
|
}>();
|
|
27
28
|
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
watch(
|
|
32
|
-
() => gridApi.value,
|
|
33
|
-
(gridApi) => {
|
|
34
|
-
if (gridApi.isDestroyed()) return;
|
|
35
|
-
|
|
36
|
-
gridApi.addEventListener("displayedColumnsChanged", (event: DisplayedColumnsChangedEvent) => {
|
|
37
|
-
columns.value = event.api.getAllGridColumns();
|
|
38
|
-
});
|
|
29
|
+
const query = ref("");
|
|
30
|
+
const slideModal = ref(false);
|
|
31
|
+
const teleportTarget = usePlBlockPageTitleTeleportTarget("PlAgGridColumnManager");
|
|
39
32
|
|
|
40
|
-
|
|
41
|
-
if (columns.value.length > 0) {
|
|
42
|
-
gridApi.moveColumns(columns.value, 0);
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
{ immediate: true },
|
|
46
|
-
);
|
|
33
|
+
const columns = useGridColumns(props);
|
|
47
34
|
|
|
48
35
|
const items = computed(() => {
|
|
49
|
-
return columns.value.map((col) => ({
|
|
36
|
+
return columns.value.map((col, i) => ({
|
|
50
37
|
column: col,
|
|
51
38
|
id: col.getId(),
|
|
52
|
-
label: col.getColDef().headerName
|
|
39
|
+
label: col.getColDef().headerName ?? `Unnamed Column (${i + 1})`,
|
|
53
40
|
}));
|
|
54
41
|
});
|
|
55
42
|
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const teleportTarget = usePlBlockPageTitleTeleportTarget("PlAgGridColumnManager");
|
|
60
|
-
|
|
61
|
-
const { filteredItems, segments } = useFilteredItems(() => ({
|
|
62
|
-
items: items.value,
|
|
63
|
-
query: query.value,
|
|
43
|
+
const { filteredItems, segments } = useFilteredItems({
|
|
44
|
+
items,
|
|
45
|
+
query,
|
|
64
46
|
getStrings: (item) => [item.label],
|
|
65
|
-
})
|
|
47
|
+
});
|
|
66
48
|
</script>
|
|
67
49
|
|
|
68
50
|
<template>
|
|
@@ -79,17 +61,17 @@ const { filteredItems, segments } = useFilteredItems(() => ({
|
|
|
79
61
|
:is-draggable="(item) => !item.column.getColDef().lockPosition"
|
|
80
62
|
:on-sort="
|
|
81
63
|
(fromIndex, toIndex) => {
|
|
82
|
-
if (!
|
|
64
|
+
if (!props.api.isDestroyed()) {
|
|
83
65
|
const columnToMove = columns[fromIndex];
|
|
84
|
-
|
|
66
|
+
props.api.moveColumns([columnToMove], toIndex);
|
|
85
67
|
}
|
|
86
68
|
return true; // Let PlElementList handle the visual update
|
|
87
69
|
}
|
|
88
70
|
"
|
|
89
71
|
:on-toggle="
|
|
90
72
|
(item) => {
|
|
91
|
-
if (!
|
|
92
|
-
|
|
73
|
+
if (!props.api.isDestroyed()) {
|
|
74
|
+
props.api.setColumnsVisible([item.column], !item.column.isVisible());
|
|
93
75
|
}
|
|
94
76
|
}
|
|
95
77
|
"
|
|
@@ -1,25 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ref, computed, toValue } from "vue";
|
|
2
2
|
|
|
3
|
-
export function useFilteredItems<T>(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}>,
|
|
9
|
-
) {
|
|
3
|
+
export function useFilteredItems<T>(props: {
|
|
4
|
+
items: Ref<T[]>;
|
|
5
|
+
query: Ref<string>;
|
|
6
|
+
getStrings: (item: T) => Iterable<string>;
|
|
7
|
+
}) {
|
|
10
8
|
const result = computed(() => {
|
|
11
9
|
const { items, query, getStrings } = toValue(props);
|
|
12
10
|
const filteredItems: T[] = [];
|
|
13
11
|
const segments = new Map<string, StringSegment[]>();
|
|
14
|
-
for (const item of items) {
|
|
12
|
+
for (const item of items.value) {
|
|
15
13
|
let kept = false;
|
|
16
14
|
for (const string of getStrings(item)) {
|
|
17
15
|
let stringSegments = segments.get(string);
|
|
18
16
|
if (!stringSegments) {
|
|
19
|
-
stringSegments = matchSubstrings(string, query);
|
|
17
|
+
stringSegments = matchSubstrings(string, query.value);
|
|
20
18
|
segments.set(string, stringSegments);
|
|
21
19
|
}
|
|
22
|
-
if (!kept && (!query || stringSegments.some(({ match }) => match))) {
|
|
20
|
+
if (!kept && (!query.value || stringSegments.some(({ match }) => match))) {
|
|
23
21
|
filteredItems.push(item);
|
|
24
22
|
kept = true;
|
|
25
23
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Column, GridApi } from "ag-grid-enterprise";
|
|
2
|
+
import { ref, watch } from "vue";
|
|
3
|
+
|
|
4
|
+
export function useGridColumns(props: { api: GridApi }) {
|
|
5
|
+
const columns = ref<Column[]>([]);
|
|
6
|
+
const syncColumns = () => {
|
|
7
|
+
columns.value = props.api.getAllGridColumns();
|
|
8
|
+
};
|
|
9
|
+
watch(
|
|
10
|
+
() => props.api,
|
|
11
|
+
(gridApi, _, onCleanup) => {
|
|
12
|
+
if (gridApi.isDestroyed()) return;
|
|
13
|
+
|
|
14
|
+
gridApi.addEventListener("displayedColumnsChanged", syncColumns);
|
|
15
|
+
onCleanup(() => gridApi.removeEventListener("displayedColumnsChanged", syncColumns));
|
|
16
|
+
|
|
17
|
+
columns.value = gridApi.getAllGridColumns();
|
|
18
|
+
if (columns.value.length > 0) {
|
|
19
|
+
gridApi.moveColumns(columns.value, 0);
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
{ immediate: true },
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
return columns;
|
|
26
|
+
}
|
|
@@ -116,13 +116,14 @@ const supportedFilters = [
|
|
|
116
116
|
</template>
|
|
117
117
|
<template #body-content>
|
|
118
118
|
<PlAdvancedFilterComponent
|
|
119
|
-
|
|
119
|
+
:filters="step.filter as PlAdvancedFilter"
|
|
120
120
|
:class="[$style.root, { [$commonStyle.disabled]: step.label.length === 0 }]"
|
|
121
|
-
:
|
|
121
|
+
:options="props.columns"
|
|
122
122
|
:supported-filters="supportedFilters"
|
|
123
123
|
:get-suggest-options="props.getSuggestOptions"
|
|
124
124
|
:enable-dnd="false"
|
|
125
125
|
:enable-add-group-button="true"
|
|
126
|
+
@update-filters="(v) => (step = { ...step, filter: v as typeof step.filter })"
|
|
126
127
|
>
|
|
127
128
|
<template #add-group-buttons>
|
|
128
129
|
<div :class="$style.actions">
|