@platforma-sdk/ui-vue 1.64.0 → 1.65.3

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.
Files changed (63) hide show
  1. package/.turbo/turbo-build.log +25 -25
  2. package/.turbo/turbo-formatter$colon$check.log +2 -2
  3. package/.turbo/turbo-linter$colon$check.log +2 -2
  4. package/.turbo/turbo-types$colon$check.log +1 -1
  5. package/CHANGELOG.md +19 -0
  6. package/dist/components/PlAdvancedFilter/FilterEditor.js.map +1 -1
  7. package/dist/components/PlAdvancedFilter/FilterEditor.style.js.map +1 -1
  8. package/dist/components/PlAdvancedFilter/FilterEditor.vue.d.ts +3 -8
  9. package/dist/components/PlAdvancedFilter/FilterEditor.vue.d.ts.map +1 -1
  10. package/dist/components/PlAdvancedFilter/FilterEditor.vue2.js +164 -151
  11. package/dist/components/PlAdvancedFilter/FilterEditor.vue2.js.map +1 -1
  12. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.js.map +1 -1
  13. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.style.js +8 -7
  14. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.style.js.map +1 -1
  15. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue.css +1 -1
  16. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue.d.ts +24 -8
  17. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue.d.ts.map +1 -1
  18. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js +176 -110
  19. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js.map +1 -1
  20. package/dist/components/PlAdvancedFilter/types.d.ts +2 -0
  21. package/dist/components/PlAdvancedFilter/types.d.ts.map +1 -1
  22. package/dist/components/PlAgDataTable/PlAgDataTableV2.js.map +1 -1
  23. package/dist/components/PlAgDataTable/PlAgDataTableV2.style.js.map +1 -1
  24. package/dist/components/PlAgDataTable/PlAgDataTableV2.vue.d.ts.map +1 -1
  25. package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js +116 -109
  26. package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js.map +1 -1
  27. package/dist/components/PlAgDataTable/sources/table-source-v2.d.ts +6 -5
  28. package/dist/components/PlAgDataTable/sources/table-source-v2.d.ts.map +1 -1
  29. package/dist/components/PlAgDataTable/sources/table-source-v2.js +26 -26
  30. package/dist/components/PlAgDataTable/sources/table-source-v2.js.map +1 -1
  31. package/dist/components/PlAgDataTable/sources/table-state-v2.d.ts +6 -3
  32. package/dist/components/PlAgDataTable/sources/table-state-v2.d.ts.map +1 -1
  33. package/dist/components/PlAgDataTable/sources/table-state-v2.js +182 -97
  34. package/dist/components/PlAgDataTable/sources/table-state-v2.js.map +1 -1
  35. package/dist/components/PlAnnotations/components/FilterSidebar.js.map +1 -1
  36. package/dist/components/PlAnnotations/components/FilterSidebar.style.js.map +1 -1
  37. package/dist/components/PlAnnotations/components/FilterSidebar.vue.d.ts.map +1 -1
  38. package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js +7 -4
  39. package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js.map +1 -1
  40. package/dist/components/PlTableFilters/PlTableFiltersV2.js.map +1 -1
  41. package/dist/components/PlTableFilters/PlTableFiltersV2.style.js +5 -1
  42. package/dist/components/PlTableFilters/PlTableFiltersV2.style.js.map +1 -1
  43. package/dist/components/PlTableFilters/PlTableFiltersV2.vue.css +1 -1
  44. package/dist/components/PlTableFilters/PlTableFiltersV2.vue.d.ts +7 -9
  45. package/dist/components/PlTableFilters/PlTableFiltersV2.vue.d.ts.map +1 -1
  46. package/dist/components/PlTableFilters/PlTableFiltersV2.vue2.js +73 -42
  47. package/dist/components/PlTableFilters/PlTableFiltersV2.vue2.js.map +1 -1
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +2 -0
  50. package/dist/index.js.map +1 -1
  51. package/dist/lib/util/helpers/dist/functions.js.map +1 -1
  52. package/dist/lib/util/helpers/dist/objects.js +4 -1
  53. package/dist/lib/util/helpers/dist/objects.js.map +1 -1
  54. package/package.json +7 -6
  55. package/src/components/PlAdvancedFilter/FilterEditor.vue +99 -55
  56. package/src/components/PlAdvancedFilter/PlAdvancedFilter.vue +163 -95
  57. package/src/components/PlAdvancedFilter/types.ts +6 -1
  58. package/src/components/PlAgDataTable/PlAgDataTableV2.vue +24 -6
  59. package/src/components/PlAgDataTable/sources/table-source-v2.ts +11 -9
  60. package/src/components/PlAgDataTable/sources/table-state-v2.ts +249 -64
  61. package/src/components/PlAnnotations/components/FilterSidebar.vue +3 -2
  62. package/src/components/PlTableFilters/PlTableFiltersV2.vue +75 -21
  63. package/src/index.ts +4 -0
@@ -1,7 +1,8 @@
1
1
  <script lang="ts" setup generic="T extends RootFilter">
2
2
  import { PlBtnSecondary, PlCheckbox, PlElementList } from "@milaboratories/uikit";
3
3
  import type { ListOptionBase } from "@platforma-sdk/model";
4
- import { computed, toRaw } from "vue";
4
+ import { produce } from "immer";
5
+ import { computed } from "vue";
5
6
  import FilterEditor from "./FilterEditor.vue";
6
7
  import OperandButton from "./OperandButton.vue";
7
8
  import { DEFAULT_FILTER_TYPE, DEFAULT_FILTERS, SUPPORTED_FILTER_TYPES } from "./constants";
@@ -9,24 +10,35 @@ import type {
9
10
  CommonFilter,
10
11
  EditableFilter,
11
12
  NodeFilter,
13
+ Operand,
12
14
  PlAdvancedFilterColumnId,
13
15
  RootFilter,
14
16
  SourceOptionInfo,
15
17
  } from "./types";
16
18
  import { createNewGroup, getNewId, isValidColumnId } from "./utils";
17
19
 
18
- const model = defineModel<T>("filters", { required: true });
19
-
20
20
  const props = withDefaults(
21
21
  defineProps<{
22
+ filters: T;
23
+ onUpdateFilters: (filters: T) => void;
22
24
  /** List of ids of sources (columns, axes) that can be selected in filters */
23
- items: SourceOptionInfo[];
25
+ options: SourceOptionInfo[];
24
26
  /** List of supported filter types */
25
27
  supportedFilters?: typeof SUPPORTED_FILTER_TYPES;
26
28
  /** If true - new filter can be added by droppind element into filter group; else new column is added by button click */
27
29
  enableDnd?: boolean;
28
30
  /** If true - "Add group" button is shown below the filter groups */
29
31
  enableAddGroupButton?: boolean;
32
+ /** If true - eye icon is shown per group to toggle suppression */
33
+ enableToggling?: boolean;
34
+ /** Function to determine if a filter is pinned */
35
+ isPinned?: (item: NodeFilter, index: number) => boolean;
36
+ /** Function to determine if a filter is removable */
37
+ isRemovable?: (item: NodeFilter, index: number) => boolean;
38
+ /** Function to determine if a filter is draggable */
39
+ isDraggable?: (item: NodeFilter, index: number) => boolean;
40
+ /** Function to determine if a group is complete */
41
+ isCompletedGroup?: (group: NodeFilter, index: number) => boolean;
30
42
  /** Loading function for unique values for Equal/InSet filters and fixed axes options. */
31
43
  getSuggestOptions: (params: {
32
44
  columnId: PlAdvancedFilterColumnId;
@@ -37,14 +49,23 @@ const props = withDefaults(
37
49
  }>(),
38
50
  {
39
51
  supportedFilters: () => SUPPORTED_FILTER_TYPES,
52
+ isCompletedGroup: () => false,
53
+ isPinned: () => false,
54
+ isRemovable: () => true,
55
+ isDraggable: () => true,
56
+
40
57
  getSuggestModel: undefined,
41
58
 
42
59
  enableDnd: false,
43
60
  enableAddGroupButton: false,
61
+ enableToggling: false,
44
62
  },
45
63
  );
64
+ const produceFiltersUpdate = (updater: (draft: T) => void) => {
65
+ props.onUpdateFilters(produce(props.filters, updater));
66
+ };
46
67
 
47
- const firstColumnId = computed(() => props.items[0]?.id);
68
+ const firstColumnId = computed(() => props.options[0]?.id);
48
69
  const emptyGroup: NodeFilter[] = [
49
70
  {
50
71
  id: -1,
@@ -54,93 +75,100 @@ const emptyGroup: NodeFilter[] = [
54
75
  },
55
76
  ];
56
77
 
78
+ const rootFilters = computed({
79
+ get: () => props.filters.filters,
80
+ set: (filters) => props.onUpdateFilters({ ...props.filters, filters: filters }),
81
+ });
82
+
57
83
  function getRootGroups() {
58
- if (model.value.type !== "or" && model.value.type !== "and") {
84
+ if (props.filters.type !== "or" && props.filters.type !== "and") {
59
85
  throw new Error('Invalid model structure, expected root to be "or" or "and" group');
60
86
  }
61
- return model.value.filters;
87
+ return props.filters.filters;
62
88
  }
63
89
 
64
- function getRootGroup(idx: number): NodeFilter {
65
- const groups = getRootGroups();
66
- const group = groups[idx];
67
- if (group.type !== "and" && group.type !== "or" && group.type !== "not") {
90
+ function getDraftGroupContent(
91
+ draft: RootFilter,
92
+ idx: number,
93
+ ): Exclude<NodeFilter, { type: "not" }> {
94
+ const group = draft.filters[idx];
95
+ if (group.type === "not") {
96
+ if (group.filter.type !== "and" && group.filter.type !== "or") {
97
+ throw new Error('Invalid group structure, expected "and" or "or" group inside "not"');
98
+ }
99
+ return group.filter;
100
+ }
101
+ if (group.type !== "and" && group.type !== "or") {
68
102
  throw new Error('Invalid group structure, expected "and", "or" or "not" group');
69
103
  }
70
104
  return group;
71
105
  }
72
106
 
73
- function getRootGroupContent(idx: number): Exclude<NodeFilter, { type: "not" }> {
74
- const group = getRootGroup(idx);
75
-
76
- if (group.type !== "not") {
77
- return group;
78
- }
79
-
80
- if (group.filter.type !== "and" && group.filter.type !== "or") {
81
- throw new Error('Invalid group structure, expected "and" or "or" group inside "not"');
82
- }
83
-
84
- return group.filter;
107
+ function getNotContent<T extends CommonFilter>(item: T): Exclude<T, { type: "not" }> {
108
+ return item.type === "not"
109
+ ? (item.filter as Exclude<T, { type: "not" }>)
110
+ : (item as Exclude<T, { type: "not" }>);
85
111
  }
86
112
 
87
113
  function addColumnToGroup(groupIdx: number, selectedSourceId: PlAdvancedFilterColumnId) {
88
- const group = getRootGroupContent(groupIdx);
89
-
90
- group.filters.push({
91
- ...DEFAULT_FILTERS[DEFAULT_FILTER_TYPE],
92
- column: selectedSourceId,
93
- id: getNewId(),
94
- isExpanded: true,
95
- } as CommonFilter);
114
+ produceFiltersUpdate((draft: RootFilter) => {
115
+ const group = getDraftGroupContent(draft, groupIdx);
116
+ group.filters.push({
117
+ ...DEFAULT_FILTERS[DEFAULT_FILTER_TYPE],
118
+ column: selectedSourceId,
119
+ id: getNewId(),
120
+ isExpanded: true,
121
+ } as CommonFilter);
122
+ });
96
123
  }
97
124
 
98
125
  function removeFilterFromGroup(groupIdx: number, filterIdx: number) {
99
- const group = getRootGroupContent(groupIdx);
100
-
101
- if (group.filters.length === 1 && filterIdx === 0) {
102
- removeGroup(groupIdx);
103
- } else {
104
- group.filters.splice(filterIdx, 1);
105
- }
126
+ produceFiltersUpdate((draft: RootFilter) => {
127
+ const group = getDraftGroupContent(draft, groupIdx);
128
+ if (group.filters.length === 1 && filterIdx === 0) {
129
+ draft.filters.splice(groupIdx, 1);
130
+ } else {
131
+ group.filters.splice(filterIdx, 1);
132
+ }
133
+ });
106
134
  }
135
+
107
136
  function inverseRootNode(groupIdx: number) {
108
- const groups = getRootGroups();
109
- const group = groups[groupIdx];
110
- if (group.type === "not") {
111
- if (group.filter.type !== "and" && group.filter.type !== "or") {
112
- throw new Error('Invalid group structure, expected "and" or "or" group inside "not"');
113
- }
114
- groups[groupIdx] = group.filter;
115
- } else {
116
- const type = groups[groupIdx].type;
117
- if (type !== "and" && type !== "or" && type !== "not") {
118
- throw new Error('Invalid group structure, expected "and", "or" or "not" group');
137
+ produceFiltersUpdate((draft: RootFilter) => {
138
+ const group = draft.filters[groupIdx];
139
+ if (group.type === "not") {
140
+ if (group.filter.type !== "and" && group.filter.type !== "or") {
141
+ throw new Error('Invalid group structure, expected "and" or "or" group inside "not"');
142
+ }
143
+ draft.filters[groupIdx] = {
144
+ ...draft.filters[groupIdx],
145
+ ...group.filter,
146
+ };
147
+ } else {
148
+ const type = draft.filters[groupIdx].type;
149
+ if (type !== "and" && type !== "or" && type !== "not") {
150
+ throw new Error('Invalid group structure, expected "and", "or" or "not" group');
151
+ }
152
+ draft.filters[groupIdx] = {
153
+ ...draft.filters[groupIdx],
154
+ id: getNewId(),
155
+ type: "not",
156
+ filter: draft.filters[groupIdx],
157
+ };
119
158
  }
120
-
121
- groups[groupIdx] = {
122
- id: getNewId(),
123
- isExpanded: true,
124
- type: "not",
125
- filter: groups[groupIdx],
126
- };
127
- }
159
+ });
128
160
  }
129
161
 
130
- function getNotContent<T extends CommonFilter>(item: T): Exclude<T, { type: "not" }> {
131
- return item.type === "not"
132
- ? (item.filter as Exclude<T, { type: "not" }>)
133
- : (item as Exclude<T, { type: "not" }>);
162
+ function addGroup(selectedSourceId: PlAdvancedFilterColumnId) {
163
+ produceFiltersUpdate((draft: RootFilter) => {
164
+ draft.filters.push(createNewGroup(selectedSourceId));
165
+ });
134
166
  }
135
167
 
136
- function removeGroup(groupIdx: number) {
137
- const groups = getRootGroups();
138
- groups.splice(groupIdx, 1);
139
- }
140
- function addGroup(selectedSourceId: PlAdvancedFilterColumnId) {
141
- const newGroup = createNewGroup(selectedSourceId);
142
- const groups = getRootGroups();
143
- groups.push(newGroup);
168
+ function updateFilter(groupIdx: number, filterIdx: number, updatedFilter: EditableFilter) {
169
+ produceFiltersUpdate((draft: RootFilter) => {
170
+ getDraftGroupContent(draft, groupIdx).filters[filterIdx] = updatedFilter as CommonFilter;
171
+ });
144
172
  }
145
173
 
146
174
  function handleDropToExistingGroup(groupIdx: number, event: DragEvent) {
@@ -152,6 +180,7 @@ function handleDropToExistingGroup(groupIdx: number, event: DragEvent) {
152
180
  }
153
181
  }
154
182
  }
183
+
155
184
  function handleDropToNewGroup(event: DragEvent) {
156
185
  const dataTransfer = event.dataTransfer;
157
186
  if (dataTransfer?.getData("text/plain")) {
@@ -161,10 +190,35 @@ function handleDropToNewGroup(event: DragEvent) {
161
190
  }
162
191
  }
163
192
  }
193
+
164
194
  function dragOver(event: DragEvent) {
165
195
  event.preventDefault();
166
196
  }
167
197
 
198
+ function toggleExpand(_: NodeFilter, index: number) {
199
+ produceFiltersUpdate((draft: RootFilter) => {
200
+ draft.filters[index].isExpanded = !draft.filters[index].isExpanded;
201
+ });
202
+ }
203
+
204
+ function toggleSuppress(_: NodeFilter, index: number) {
205
+ produceFiltersUpdate((draft: RootFilter) => {
206
+ draft.filters[index].isSuppressed = !draft.filters[index].isSuppressed;
207
+ });
208
+ }
209
+
210
+ function changeGroupOperand(index: number, v: Operand) {
211
+ produceFiltersUpdate((draft: RootFilter) => {
212
+ getDraftGroupContent(draft, index).type = v;
213
+ });
214
+ }
215
+
216
+ function changeRootOperand(v: Operand) {
217
+ produceFiltersUpdate((draft: RootFilter) => {
218
+ draft.type = v;
219
+ });
220
+ }
221
+
168
222
  function validateFilter<T extends CommonFilter>(item: T): EditableFilter {
169
223
  if (item.type === "and" || item.type === "or" || item.type === "not") {
170
224
  throw new Error("Invalid filter structure, expected leaf filter");
@@ -172,34 +226,38 @@ function validateFilter<T extends CommonFilter>(item: T): EditableFilter {
172
226
 
173
227
  return item as EditableFilter;
174
228
  }
175
-
176
- function updateFilter(filters: CommonFilter[], idx: number, updatedFilter: EditableFilter) {
177
- filters[idx] = toRaw(updatedFilter as CommonFilter);
178
- }
179
229
  </script>
180
230
  <template>
181
231
  <div>
182
232
  <PlElementList
183
- v-model:items="model.filters"
233
+ v-model:items="rootFilters"
184
234
  :get-item-key="(filter) => filter.id"
185
235
  :item-class="$style.filterGroup"
186
236
  :item-class-content="$style.filterGroupContent"
187
237
  :item-class-title="$style.filterGroupTitle"
188
238
  :is-expanded="(filter) => filter.isExpanded === true"
189
- :on-expand="
190
- (group) => {
191
- group.isExpanded = !group.isExpanded;
192
- }
193
- "
194
- :disableDragging="false"
195
- :disableRemoving="false"
196
- :disableToggling="true"
197
- :disablePinning="true"
239
+ :on-expand="toggleExpand"
240
+ :is-toggled="(item) => item.isSuppressed === true"
241
+ :on-toggle="toggleSuppress"
242
+ :is-pinned="(item, index) => props.isPinned?.(item, index) === true"
243
+ :is-pinnable="() => false"
244
+ :is-removable="(item, index) => props.isRemovable?.(item, index) === true"
245
+ :is-draggable="(item, index) => props.isDraggable?.(item, index) === true"
246
+ :disable-toggling="props.enableToggling !== true"
247
+ :disable-dragging="false"
248
+ :disable-removing="false"
198
249
  >
199
- <template #item-title> Filter group </template>
250
+ <template #item-title="{ item, index }">
251
+ <slot name="group-title" :item="item" :index="index">Filter group</slot>
252
+ </template>
200
253
  <template #item-content="{ item, index }">
201
254
  <div
202
- :class="$style.groupContent"
255
+ :class="[
256
+ $style.groupContent,
257
+ {
258
+ [$style.suppressedLabel]: item.isSuppressed,
259
+ },
260
+ ]"
203
261
  dropzone="true"
204
262
  @drop="(event) => handleDropToExistingGroup(index, event)"
205
263
  @dragover="dragOver"
@@ -215,22 +273,24 @@ function updateFilter(filters: CommonFilter[], idx: number, updatedFilter: Edita
215
273
  <FilterEditor
216
274
  :filter="validateFilter(getNotContent(item).filters[filterIdx])"
217
275
  :operand="getNotContent(item).type"
218
- :column-options="items"
276
+ :column-options="options"
219
277
  :supported-filters="props.supportedFilters"
220
278
  :get-suggest-options="props.getSuggestOptions"
221
279
  :enable-dnd="Boolean(props.enableDnd)"
222
280
  :is-last="filterIdx === getNotContent(item).filters.length - 1"
223
- :on-change-operand="(v) => (getNotContent(item).type = v)"
224
- :on-delete="() => removeFilterFromGroup(index, filterIdx)"
225
- @update:filter="
226
- (value) => updateFilter(getNotContent(item).filters, filterIdx, value)
227
- "
281
+ @delete="() => removeFilterFromGroup(index, filterIdx)"
282
+ @update-filter="(value) => updateFilter(index, filterIdx, value)"
283
+ @change-operand="(v) => changeGroupOperand(index, v)"
228
284
  />
229
285
  </template>
230
286
  <div v-if="props.enableDnd" :class="$style.dropzone">
231
287
  <div>Drop dimensions here</div>
232
288
  </div>
233
- <PlBtnSecondary v-else icon="add" @click="addColumnToGroup(index, firstColumnId)">
289
+ <PlBtnSecondary
290
+ v-else-if="!props.isCompletedGroup(item, index)"
291
+ icon="add"
292
+ @click="addColumnToGroup(index, firstColumnId)"
293
+ >
234
294
  Add filter
235
295
  </PlBtnSecondary>
236
296
  </div>
@@ -239,9 +299,9 @@ function updateFilter(filters: CommonFilter[], idx: number, updatedFilter: Edita
239
299
  <OperandButton
240
300
  v-if="props.enableAddGroupButton || index < getRootGroups().length - 1"
241
301
  :class="$style.buttonWrapper"
242
- :active="model.type"
302
+ :active="props.filters.type"
243
303
  :disabled="index === getRootGroups().length - 1"
244
- :on-select="(v) => (model.type = v)"
304
+ :on-select="changeRootOperand"
245
305
  />
246
306
  </template>
247
307
  </PlElementList>
@@ -263,7 +323,11 @@ function updateFilter(filters: CommonFilter[], idx: number, updatedFilter: Edita
263
323
  @drop="handleDropToNewGroup"
264
324
  @dragover="dragOver"
265
325
  >
266
- <template #item-title>Filter group</template>
326
+ <template #item-title="{ item, index }">
327
+ <slot name="group-title" :item="item" :index="index + getRootGroups().length"
328
+ >Filter group</slot
329
+ >
330
+ </template>
267
331
  <template #item-content>
268
332
  <div v-if="enableDnd" :class="$style.dropzone">
269
333
  <div>Drop dimensions here</div>
@@ -296,6 +360,10 @@ function updateFilter(filters: CommonFilter[], idx: number, updatedFilter: Edita
296
360
  .notCheckbox {
297
361
  margin: 4px 0;
298
362
  }
363
+ .suppressedLabel {
364
+ filter: grayscale(100%);
365
+ pointer-events: none;
366
+ }
299
367
  .dropzone {
300
368
  border-radius: 6px;
301
369
  border: 1.5px dashed var(--color-div-grey);
@@ -18,7 +18,12 @@ export type PlAdvancedFilterColumnId =
18
18
  | CanonicalizedJson<AxisId>
19
19
  | CanonicalizedJson<PTableColumnId>;
20
20
 
21
- export type RequiredMeta = { id: number; isExpanded?: boolean };
21
+ export type RequiredMeta = {
22
+ id: number;
23
+ isExpanded?: boolean;
24
+ isSuppressed?: boolean;
25
+ source?: string;
26
+ };
22
27
 
23
28
  export type FilterLeafContent = Extract<
24
29
  FilterSpecLeaf<PlAdvancedFilterColumnId>,
@@ -162,11 +162,17 @@ const [filterableColumns, visibleFilterableColumns] = useFilterableColumns(
162
162
  () => settings.value.sourceId,
163
163
  () => gridOptions.value.columnDefs ?? null,
164
164
  );
165
- const { gridState, sheetsState, filtersState, searchString } = useTableState(
166
- tableState,
167
- settings,
168
- visibleFilterableColumns,
165
+ const defaultFilters = computed(() =>
166
+ settings.value.sourceId !== null ? settings.value.model?.defaultFilters : undefined,
169
167
  );
168
+ const {
169
+ gridState,
170
+ sheetsState,
171
+ searchString,
172
+ filtersState,
173
+ defaultFiltersState,
174
+ resetDefaultFilters,
175
+ } = useTableState(tableState, settings, visibleFilterableColumns, defaultFilters);
170
176
  const sheetsSettings = computed<PlDataTableSheetsSettings>(() => {
171
177
  const settingsCopy = { ...settings.value };
172
178
  return settingsCopy.sourceId !== null
@@ -371,6 +377,13 @@ watch(
371
377
  return;
372
378
  }
373
379
 
380
+ if (
381
+ settings.model?.fullTableHandle === undefined ||
382
+ settings.model?.visibleTableHandle === undefined
383
+ ) {
384
+ return;
385
+ }
386
+
374
387
  // Data source changed -> show full page loader, clear selection
375
388
  if (settings.sourceId !== oldSettings?.sourceId) {
376
389
  gridApi.updateGridOptions({
@@ -411,7 +424,8 @@ watch(
411
424
  calculateGridOptions({
412
425
  generation,
413
426
  pfDriver: getRawPlatformaInstance().pFrameDriver,
414
- model: settings.model,
427
+ fullTableHandle: settings.model?.fullTableHandle,
428
+ visibleTableHandle: settings.model?.visibleTableHandle,
415
429
  sheets: settings.sheets ?? [],
416
430
  dataRenderedTracker,
417
431
  hiddenColIds: gridState.value.columnVisibility?.hiddenColIds,
@@ -533,9 +547,13 @@ watchEffect(() => {
533
547
  <PlAgGridColumnManager v-if="gridApi && !disableColumnsPanel" :api="gridApi" />
534
548
  <PlTableFiltersV2
535
549
  v-if="!disableFiltersPanel"
536
- v-model="filtersState"
550
+ :filters="filtersState"
551
+ :default-filters="defaultFiltersState"
537
552
  :pframe-handle="'model' in settings ? settings?.model?.fullPframeHandle : undefined"
538
553
  :columns="filterableColumns"
554
+ @updateFilters="(v) => (filtersState = v)"
555
+ @resetDefaultFilters="resetDefaultFilters"
556
+ @updateDefaultFilters="(v) => (defaultFiltersState = v)"
539
557
  />
540
558
  <PlAgCsvExporter v-if="gridApi && showExportButton" :api="gridApi" />
541
559
  <PlAgDataTableSheets v-model="sheetsState" :settings="sheetsSettings">
@@ -3,6 +3,7 @@ import type {
3
3
  PTableColumnId,
4
4
  PTableColumnSpecAxis,
5
5
  PTableColumnSpecColumn,
6
+ PTableHandle,
6
7
  PTableValue,
7
8
  } from "@platforma-sdk/model";
8
9
  import {
@@ -13,7 +14,6 @@ import {
13
14
  type PlDataTableSheet,
14
15
  type PTableVector,
15
16
  type AxisId,
16
- type PlDataTableModel,
17
17
  type PTableColumnSpec,
18
18
  type PTableKey,
19
19
  type PlTableColumnId,
@@ -86,16 +86,18 @@ function columns2rows(
86
86
  export async function calculateGridOptions({
87
87
  generation,
88
88
  pfDriver,
89
- model,
90
89
  sheets,
90
+ fullTableHandle,
91
+ visibleTableHandle,
91
92
  dataRenderedTracker,
92
93
  hiddenColIds,
93
94
  cellButtonAxisParams,
94
95
  }: {
95
- generation: Ref<number>;
96
- pfDriver: PFrameDriver;
97
- model: PlDataTableModel;
98
96
  sheets: PlDataTableSheet[];
97
+ pfDriver: PFrameDriver;
98
+ generation: Ref<number>;
99
+ fullTableHandle: PTableHandle;
100
+ visibleTableHandle: PTableHandle;
99
101
  dataRenderedTracker: DeferredCircular<GridApi<PlAgDataTableV2Row>>;
100
102
  hiddenColIds?: PlTableColumnIdJson[];
101
103
  cellButtonAxisParams?: PlAgCellButtonAxisParams;
@@ -108,8 +110,8 @@ export async function calculateGridOptions({
108
110
 
109
111
  // get specs of the full table
110
112
  const [tableSpecs, visibleTableSpecs] = await Promise.all([
111
- pfDriver.getSpec(model.fullTableHandle),
112
- pfDriver.getSpec(model.visibleTableHandle),
113
+ pfDriver.getSpec(fullTableHandle),
114
+ pfDriver.getSpec(visibleTableHandle),
113
115
  ]);
114
116
 
115
117
  if (stateGeneration !== generation.value) throw new Error("table state generation changed");
@@ -167,7 +169,7 @@ export async function calculateGridOptions({
167
169
  if (stateGeneration !== generation.value) return params.fail();
168
170
  try {
169
171
  if (rowCount === -1) {
170
- const ptShape = await pfDriver.getShape(model.visibleTableHandle);
172
+ const ptShape = await pfDriver.getShape(visibleTableHandle);
171
173
  if (stateGeneration !== generation.value || params.api.isDestroyed())
172
174
  return params.fail();
173
175
  rowCount = ptShape.rows;
@@ -197,7 +199,7 @@ export async function calculateGridOptions({
197
199
  ) {
198
200
  length = Math.min(rowCount, params.request.endRow) - params.request.startRow;
199
201
  if (length > 0) {
200
- const data = await pfDriver.getData(model.visibleTableHandle, requestIndices, {
202
+ const data = await pfDriver.getData(visibleTableHandle, requestIndices, {
201
203
  offset: params.request.startRow,
202
204
  length,
203
205
  });