@platforma-sdk/ui-vue 1.80.9 → 1.80.13

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 (32) hide show
  1. package/.turbo/turbo-build.log +16 -16
  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 +28 -0
  6. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.js.map +1 -1
  7. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.style.js.map +1 -1
  8. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue.d.ts.map +1 -1
  9. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js +1 -1
  10. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js.map +1 -1
  11. package/dist/components/PlAgCsvExporter/PlAgCsvExporter.js.map +1 -1
  12. package/dist/components/PlAgCsvExporter/PlAgCsvExporter.vue.d.ts +2 -1
  13. package/dist/components/PlAgCsvExporter/PlAgCsvExporter.vue.d.ts.map +1 -1
  14. package/dist/components/PlAgCsvExporter/PlAgCsvExporter.vue2.js +6 -2
  15. package/dist/components/PlAgCsvExporter/PlAgCsvExporter.vue2.js.map +1 -1
  16. package/dist/components/PlAgCsvExporter/export-csv.d.ts +16 -5
  17. package/dist/components/PlAgCsvExporter/export-csv.d.ts.map +1 -1
  18. package/dist/components/PlAgCsvExporter/export-csv.js +48 -39
  19. package/dist/components/PlAgCsvExporter/export-csv.js.map +1 -1
  20. package/dist/components/PlAgDataTable/PlAgDataTableV2.js.map +1 -1
  21. package/dist/components/PlAgDataTable/PlAgDataTableV2.style.js.map +1 -1
  22. package/dist/components/PlAgDataTable/PlAgDataTableV2.vue.d.ts.map +1 -1
  23. package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js +22 -17
  24. package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js.map +1 -1
  25. package/dist/components/PlAgDataTable/sources/table-source-v2.js +1 -1
  26. package/dist/index.js +8 -8
  27. package/dist/lib.js +4 -4
  28. package/package.json +8 -8
  29. package/src/components/PlAdvancedFilter/PlAdvancedFilter.vue +3 -1
  30. package/src/components/PlAgCsvExporter/PlAgCsvExporter.vue +3 -2
  31. package/src/components/PlAgCsvExporter/export-csv.ts +40 -9
  32. package/src/components/PlAgDataTable/PlAgDataTableV2.vue +4 -3
@@ -1,6 +1,6 @@
1
1
   WARN  Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
2
2
 
3
- > @platforma-sdk/ui-vue@1.80.9 build /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.80.13 build /home/runner/_work/platforma/platforma/sdk/ui-vue
4
4
  > ts-builder build --target browser-lib
5
5
 
6
6
  Building browser-lib project...
@@ -16,7 +16,7 @@ Building browser-lib project...
16
16
  rendering chunks...
17
17
 
18
18
  [vite:dts] Start generate declaration files...
19
- [vite:dts] Declaration files built in 4614ms.
19
+ [vite:dts] Declaration files built in 5555ms.
20
20
 
21
21
  computing gzip size...
22
22
  dist/components/PlAnnotations/components/PlAnnotations.vue?vue&type=style&index=0&lang.css 0.04 kB │ gzip: 0.06 kB
@@ -83,7 +83,7 @@ dist/components/PlAgRowNumHeader.js
83
83
  dist/components/PlAgCellFile/PlAgCellFile.js 0.21 kB │ gzip: 0.16 kB │ map: 2.49 kB
84
84
  dist/components/PlAgDataTable/PlAgRowCount.js 0.21 kB │ gzip: 0.17 kB │ map: 1.72 kB
85
85
  dist/plugins/Monetization/EndOfPeriod.vue_vue_type_style_index_0_lang.module.js 0.22 kB │ gzip: 0.18 kB │ map: 0.42 kB
86
- dist/components/PlAgCsvExporter/PlAgCsvExporter.js 0.22 kB │ gzip: 0.16 kB │ map: 1.49 kB
86
+ dist/components/PlAgCsvExporter/PlAgCsvExporter.js 0.22 kB │ gzip: 0.16 kB │ map: 1.59 kB
87
87
  dist/components/PlAnnotations/components/PlAnnotations.vue_vue_type_style_index_0_lang.module.js 0.22 kB │ gzip: 0.18 kB │ map: 0.42 kB
88
88
  dist/components/PlAgCellProgress/PlAgCellProgress.js 0.23 kB │ gzip: 0.16 kB │ map: 0.55 kB
89
89
  dist/components/PlAgColumnHeader/PlAgColumnHeader.js 0.23 kB │ gzip: 0.17 kB │ map: 3.22 kB
@@ -121,9 +121,9 @@ dist/components/PlAdvancedFilter/FilterEditor.js
121
121
  dist/components/PlAdvancedFilter/OperandButton.js 0.35 kB │ gzip: 0.24 kB │ map: 1.31 kB
122
122
  dist/components/PlAnnotations/components/FilterSidebar.js 0.35 kB │ gzip: 0.24 kB │ map: 5.40 kB
123
123
  dist/components/PlAnnotations/components/PlAnnotations.js 0.35 kB │ gzip: 0.24 kB │ map: 3.11 kB
124
- dist/components/PlAgDataTable/PlAgDataTableV2.js 0.35 kB │ gzip: 0.25 kB │ map: 22.33 kB
124
+ dist/components/PlAgDataTable/PlAgDataTableV2.js 0.35 kB │ gzip: 0.25 kB │ map: 22.36 kB
125
125
  dist/plugins/Monetization/UserCabinetCard.js 0.35 kB │ gzip: 0.24 kB │ map: 3.00 kB
126
- dist/components/PlAdvancedFilter/PlAdvancedFilter.js 0.36 kB │ gzip: 0.24 kB │ map: 13.36 kB
126
+ dist/components/PlAdvancedFilter/PlAdvancedFilter.js 0.36 kB │ gzip: 0.24 kB │ map: 13.46 kB
127
127
  dist/components/PlAgDataTable/PlAgOverlayNoRows.js 0.36 kB │ gzip: 0.21 kB │ map: 0.74 kB
128
128
  dist/components/PlTableFilters/PlTableFiltersV2.js 0.36 kB │ gzip: 0.25 kB │ map: 6.86 kB
129
129
  dist/components/PlAgCellStatusTag/PlAgCellStatusTag.js 0.36 kB │ gzip: 0.20 kB │ map: 0.74 kB
@@ -176,7 +176,6 @@ dist/components/PlAgGridColumnManager/useFilteredItems.js
176
176
  dist/lib/util/helpers/dist/objects.js 1.20 kB │ gzip: 0.58 kB │ map: 9.83 kB
177
177
  dist/createModel.js 1.22 kB │ gzip: 0.61 kB │ map: 3.11 kB
178
178
  dist/utils.js 1.26 kB │ gzip: 0.62 kB │ map: 3.40 kB
179
- dist/components/PlAgCsvExporter/PlAgCsvExporter.vue_vue_type_script_setup_true_lang.js 1.28 kB │ gzip: 0.72 kB │ map: 2.05 kB
180
179
  dist/lib/util/helpers/dist/prettyBytes.js 1.29 kB │ gzip: 0.67 kB │ map: 3.79 kB
181
180
  dist/AgGridVue/AgGridTheme.js 1.30 kB │ gzip: 0.59 kB │ map: 2.07 kB
182
181
  dist/components/PlBtnExportArchive/Summary.vue_vue_type_script_setup_true_lang.js 1.31 kB │ gzip: 0.65 kB │ map: 2.35 kB
@@ -184,6 +183,7 @@ dist/components/PlAgDataTable/PlAgRowCount.vue_vue_type_script_setup_true_lang.j
184
183
  dist/internal/UpdateSerializer.js 1.33 kB │ gzip: 0.61 kB │ map: 4.28 kB
185
184
  dist/components/PlAgDataTable/PlAgOverlayLoading.vue_vue_type_script_setup_true_lang.js 1.33 kB │ gzip: 0.76 kB │ map: 2.49 kB
186
185
  dist/components/PlAgDataTable/types.js 1.33 kB │ gzip: 0.53 kB │ map: 7.63 kB
186
+ dist/components/PlAgCsvExporter/PlAgCsvExporter.vue_vue_type_script_setup_true_lang.js 1.34 kB │ gzip: 0.74 kB │ map: 2.16 kB
187
187
  dist/components/PlBtnExportArchive/Item.vue_vue_type_script_setup_true_lang.js 1.36 kB │ gzip: 0.63 kB │ map: 2.58 kB
188
188
  dist/components/PlAgTextAndButtonCell/PlAgTextAndButtonCell.vue_vue_type_script_setup_true_lang.js 1.46 kB │ gzip: 0.77 kB │ map: 3.56 kB
189
189
  dist/internal/createAppModel.js 1.48 kB │ gzip: 0.75 kB │ map: 3.89 kB
@@ -202,11 +202,11 @@ dist/components/PlAgDataTable/PlAgDataTableSheets.vue_vue_type_script_setup_true
202
202
  dist/components/PlDatasetSelector/PlDatasetSelector.vue_vue_type_script_setup_true_lang.js 2.58 kB │ gzip: 1.07 kB │ map: 6.02 kB
203
203
  dist/components/PlAnnotations/components/PlAnnotations.vue_vue_type_script_setup_true_lang.js 2.69 kB │ gzip: 1.12 kB │ map: 4.16 kB
204
204
  dist/lib.js 2.73 kB │ gzip: 0.57 kB │ map: 3.98 kB
205
- dist/components/PlAgCsvExporter/export-csv.js 2.83 kB │ gzip: 1.27 kB │ map: 9.11 kB
206
205
  dist/components/PlAgDataTable/compositions/useGrid.js 2.91 kB │ gzip: 1.29 kB │ map: 6.51 kB
207
206
  dist/components/PlAgColumnHeader/PlAgColumnHeader.vue_vue_type_script_setup_true_lang.js 2.93 kB │ gzip: 1.26 kB │ map: 7.97 kB
208
207
  dist/components/PlAgDataTable/sources/row-number.js 3.01 kB │ gzip: 1.31 kB │ map: 7.47 kB
209
208
  dist/defineApp.js 3.01 kB │ gzip: 1.05 kB │ map: 14.38 kB
209
+ dist/components/PlAgCsvExporter/export-csv.js 3.13 kB │ gzip: 1.39 kB │ map: 10.80 kB
210
210
  dist/plugins/Monetization/LimitCard.vue_vue_type_script_setup_true_lang.js 3.31 kB │ gzip: 1.15 kB │ map: 9.08 kB
211
211
  dist/composition/fileContent.js 3.78 kB │ gzip: 1.45 kB │ map: 12.95 kB
212
212
  dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue_vue_type_script_setup_true_lang.js 3.83 kB │ gzip: 1.64 kB │ map: 6.89 kB
@@ -221,18 +221,18 @@ dist/components/PlBtnExportArchive/PlBtnExportArchive.vue_vue_type_script_setup_
221
221
  dist/internal/createAppV2.js 5.26 kB │ gzip: 1.98 kB │ map: 17.78 kB
222
222
  dist/components/PlAgDataTable/sources/table-state-v2.js 5.66 kB │ gzip: 1.82 kB │ map: 19.14 kB
223
223
  dist/internal/createAppV3.js 6.19 kB │ gzip: 2.34 kB │ map: 21.40 kB
224
- dist/components/PlAgDataTable/sources/table-source-v2.js 7.56 kB │ gzip: 2.88 kB │ map: 27.20 kB
225
- dist/components/PlAdvancedFilter/PlAdvancedFilter.vue_vue_type_script_setup_true_lang.js 8.54 kB │ gzip: 2.59 kB │ map: 18.44 kB
224
+ dist/components/PlAgDataTable/sources/table-source-v2.js 7.59 kB │ gzip: 2.88 kB │ map: 27.20 kB
225
+ dist/components/PlAdvancedFilter/PlAdvancedFilter.vue_vue_type_script_setup_true_lang.js 8.57 kB │ gzip: 2.60 kB │ map: 18.58 kB
226
226
  dist/components/PlAdvancedFilter/FilterEditor.vue_vue_type_script_setup_true_lang.js 10.58 kB │ gzip: 3.14 kB │ map: 24.73 kB
227
- dist/components/PlAgDataTable/PlAgDataTableV2.vue_vue_type_script_setup_true_lang.js 12.48 kB │ gzip: 3.95 kB │ map: 29.92 kB
227
+ dist/components/PlAgDataTable/PlAgDataTableV2.vue_vue_type_script_setup_true_lang.js 12.54 kB │ gzip: 3.96 kB │ map: 29.97 kB
228
228
 
229
229
  [PLUGIN_TIMINGS] Warning: Your build spent significant time in plugins. Here is a breakdown:
230
- - vite:dts (29%)
231
- - sourcemaps (21%)
232
- - vite:vue (15%)
233
- - vite:css (10%)
234
- - vite:css-post (9%)
230
+ - sourcemaps (26%)
231
+ - vite:dts (26%)
232
+ - vite:vue (11%)
233
+ - vite:css-post (11%)
234
+ - vite:build-import-analysis (9%)
235
235
  See https://rolldown.rs/options/checks#plugintimings for more details.
236
236
  
237
- ✓ built in 5.49s
237
+ ✓ built in 6.47s
238
238
  Build completed successfully
@@ -1,6 +1,6 @@
1
1
   WARN  Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
2
2
 
3
- > @platforma-sdk/ui-vue@1.80.9 formatter:check /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.80.13 formatter:check /home/runner/_work/platforma/platforma/sdk/ui-vue
4
4
  > ts-builder formatter --check
5
5
 
6
6
  Checking formatting...
@@ -8,5 +8,5 @@ Checking formatting...
8
8
  Checking formatting...
9
9
 
10
10
  All matched files use the correct format.
11
- Finished in 805ms on 137 files using 16 threads.
11
+ Finished in 2850ms on 137 files using 16 threads.
12
12
  Format check completed successfully
@@ -1,10 +1,10 @@
1
1
   WARN  Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
2
2
 
3
- > @platforma-sdk/ui-vue@1.80.9 linter:check /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.80.13 linter:check /home/runner/_work/platforma/platforma/sdk/ui-vue
4
4
  > ts-builder linter --check
5
5
 
6
6
  Linting project...
7
7
  ↳ oxlint --config /home/runner/_work/platforma/platforma/sdk/ui-vue/.oxlintrc.json --deny-warnings
8
8
  Found 0 warnings and 0 errors.
9
- Finished in 35ms on 120 files with 108 rules using 16 threads.
9
+ Finished in 29ms on 120 files with 108 rules using 16 threads.
10
10
  Linting completed successfully
@@ -1,6 +1,6 @@
1
1
   WARN  Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
2
2
 
3
- > @platforma-sdk/ui-vue@1.80.9 types:check /home/runner/_work/platforma/platforma/sdk/ui-vue
3
+ > @platforma-sdk/ui-vue@1.80.13 types:check /home/runner/_work/platforma/platforma/sdk/ui-vue
4
4
  > ts-builder type-check --target browser-lib
5
5
 
6
6
  ↳ vue-tsc.js --noEmit --project ./tsconfig.json --customConditions ,
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @platforma-sdk/ui-vue
2
2
 
3
+ ## 1.80.13
4
+
5
+ ### Patch Changes
6
+
7
+ - 597ca40: PlDataTable: allow the default filter group to be fully cleared, and harden filter merging.
8
+
9
+ - `PlAdvancedFilter`: when the last leaf of a non-removable group (e.g. the pinned default-filters group) is deleted, keep it as an empty group instead of splicing the whole group out. This lets the default-filters group be emptied (previously the last default filter could not be removed); the group's reset still restores the defaults.
10
+ - `createPlDataTableV3.concatFilters`: AND-combine operands that are not `and` groups (a bare leaf, a `not`, or an `or` group) by treating them as single members, instead of assuming every operand has a `.filters` array. Fixes a `TypeError` crash when the persisted filter state is a lone leaf (e.g. a single sheet selection) and a case where an `or` root was incorrectly OR-merged with the defaults.
11
+
12
+ - Updated dependencies [597ca40]
13
+ - @platforma-sdk/model@1.80.13
14
+ - @milaboratories/uikit@2.15.19
15
+
16
+ ## 1.80.10
17
+
18
+ ### Patch Changes
19
+
20
+ - 4ac0df5: Native table export now uses the disambiguated column labels shown in the table (from the `PlDataTable` `columnsMeta` sidecar) instead of the raw spec `pl7.app/label`. This fixes export failures when exporting a table with many columns whose intrinsic labels collide — the native `exportPTable` path rejects duplicate header names.
21
+
22
+ `exportPTable`/`writePTableToFs` options gain an optional `headerNames` field (aligned 1:1 with `columnIndices`). It is additive and backward compatible: older runtimes ignore it and keep deriving header names from the column spec.
23
+
24
+ - Updated dependencies [4ac0df5]
25
+ - @milaboratories/pl-model-common@1.47.3
26
+ - @milaboratories/columns-collection-driver@0.2.3
27
+ - @milaboratories/pf-spec-driver@1.4.24
28
+ - @platforma-sdk/model@1.80.10
29
+ - @milaboratories/uikit@2.15.18
30
+
3
31
  ## 1.80.9
4
32
 
5
33
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"PlAdvancedFilter.js","names":[],"sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends RootFilter\">\nimport { PlBtnSecondary, PlCheckbox, PlElementList } from \"@milaboratories/uikit\";\nimport type { ListOptionBase } from \"@platforma-sdk/model\";\nimport { produce } from \"immer\";\nimport { computed } from \"vue\";\nimport FilterEditor from \"./FilterEditor.vue\";\nimport OperandButton from \"./OperandButton.vue\";\nimport { DEFAULT_FILTER_TYPE, DEFAULT_FILTERS, SUPPORTED_FILTER_TYPES } from \"./constants\";\nimport type {\n CommonFilter,\n EditableFilter,\n NodeFilter,\n Operand,\n PlAdvancedFilterColumnId,\n RootFilter,\n SourceOptionInfo,\n} from \"./types\";\nimport { createNewGroup, getNewId, isValidColumnId } from \"./utils\";\n\nconst props = withDefaults(\n defineProps<{\n filters: T;\n onUpdateFilters: (filters: T) => void;\n /** List of ids of sources (columns, axes) that can be selected in filters */\n options: SourceOptionInfo[];\n /** List of supported filter types */\n supportedFilters?: typeof SUPPORTED_FILTER_TYPES;\n /** If true - new filter can be added by droppind element into filter group; else new column is added by button click */\n enableDnd?: boolean;\n /** If true - \"Add group\" button is shown below the filter groups */\n enableAddGroupButton?: boolean;\n /** If true - eye icon is shown per group to toggle suppression */\n enableToggling?: boolean;\n /** Function to determine if a filter is pinned */\n isPinned?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is removable */\n isRemovable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is draggable */\n isDraggable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a group is complete */\n isCompletedGroup?: (group: NodeFilter, index: number) => boolean;\n /** Loading function for unique values for Equal/InSet filters and fixed axes options. */\n getSuggestOptions: (params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n }) => ListOptionBase<string | number>[] | Promise<ListOptionBase<string | number>[]>;\n }>(),\n {\n supportedFilters: () => SUPPORTED_FILTER_TYPES,\n isCompletedGroup: () => false,\n isPinned: () => false,\n isRemovable: () => true,\n isDraggable: () => true,\n\n getSuggestModel: undefined,\n\n enableDnd: false,\n enableAddGroupButton: false,\n enableToggling: false,\n },\n);\nconst produceFiltersUpdate = (updater: (draft: T) => void) => {\n props.onUpdateFilters(produce(props.filters, updater));\n};\n\nconst firstColumnId = computed(() => props.options[0]?.id);\nconst emptyGroup: NodeFilter[] = [\n {\n id: -1,\n type: \"and\",\n filters: [],\n isExpanded: true,\n },\n];\n\nconst rootFilters = computed({\n get: () => props.filters.filters,\n set: (filters) => props.onUpdateFilters({ ...props.filters, filters: filters }),\n});\n\nfunction getRootGroups() {\n if (props.filters.type !== \"or\" && props.filters.type !== \"and\") {\n throw new Error('Invalid model structure, expected root to be \"or\" or \"and\" group');\n }\n return props.filters.filters;\n}\n\nfunction getDraftGroupContent(\n draft: RootFilter,\n idx: number,\n): Exclude<NodeFilter, { type: \"not\" }> {\n const group = draft.filters[idx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n return group.filter;\n }\n if (group.type !== \"and\" && group.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n return group;\n}\n\nfunction getNotContent<T extends CommonFilter>(item: T): Exclude<T, { type: \"not\" }> {\n return item.type === \"not\"\n ? (item.filter as Exclude<T, { type: \"not\" }>)\n : (item as Exclude<T, { type: \"not\" }>);\n}\n\nfunction addColumnToGroup(groupIdx: number, selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n group.filters.push({\n ...DEFAULT_FILTERS[DEFAULT_FILTER_TYPE],\n column: selectedSourceId,\n id: getNewId(),\n isExpanded: true,\n } as CommonFilter);\n });\n}\n\nfunction removeFilterFromGroup(groupIdx: number, filterIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n if (group.filters.length === 1 && filterIdx === 0) {\n draft.filters.splice(groupIdx, 1);\n } else {\n group.filters.splice(filterIdx, 1);\n }\n });\n}\n\nfunction inverseRootNode(groupIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = draft.filters[groupIdx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n ...group.filter,\n };\n } else {\n const type = draft.filters[groupIdx].type;\n if (type !== \"and\" && type !== \"or\" && type !== \"not\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n id: getNewId(),\n type: \"not\",\n filter: draft.filters[groupIdx],\n };\n }\n });\n}\n\nfunction addGroup(selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters.push(createNewGroup(selectedSourceId));\n });\n}\n\nfunction updateFilter(groupIdx: number, filterIdx: number, updatedFilter: EditableFilter) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, groupIdx).filters[filterIdx] = updatedFilter as CommonFilter;\n });\n}\n\nfunction handleDropToExistingGroup(groupIdx: number, event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addColumnToGroup(groupIdx, draggedId);\n }\n }\n}\n\nfunction handleDropToNewGroup(event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addGroup(draggedId);\n }\n }\n}\n\nfunction dragOver(event: DragEvent) {\n event.preventDefault();\n}\n\nfunction toggleExpand(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isExpanded = !draft.filters[index].isExpanded;\n });\n}\n\nfunction toggleSuppress(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isSuppressed = !draft.filters[index].isSuppressed;\n });\n}\n\nfunction changeGroupOperand(index: number, v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, index).type = v;\n });\n}\n\nfunction changeRootOperand(v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.type = v;\n });\n}\n\nfunction validateFilter<T extends CommonFilter>(item: T): EditableFilter {\n if (item.type === \"and\" || item.type === \"or\" || item.type === \"not\") {\n throw new Error(\"Invalid filter structure, expected leaf filter\");\n }\n\n return item as EditableFilter;\n}\n</script>\n<template>\n <div>\n <PlElementList\n v-model:items=\"rootFilters\"\n :get-item-key=\"(filter) => filter.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"(filter) => filter.isExpanded === true\"\n :on-expand=\"toggleExpand\"\n :is-toggled=\"(item) => item.isSuppressed === true\"\n :on-toggle=\"toggleSuppress\"\n :is-pinned=\"(item, index) => props.isPinned?.(item, index) === true\"\n :is-pinnable=\"() => false\"\n :is-removable=\"(item, index) => props.isRemovable?.(item, index) === true\"\n :is-draggable=\"(item, index) => props.isDraggable?.(item, index) === true\"\n :disable-toggling=\"props.enableToggling !== true\"\n :disable-dragging=\"false\"\n :disable-removing=\"false\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index\">Filter group</slot>\n </template>\n <template #item-content=\"{ item, index }\">\n <div\n :class=\"[$style.groupContent, { [$style.suppressedLabel]: item.isSuppressed }]\"\n dropzone=\"true\"\n @drop=\"(event) => handleDropToExistingGroup(index, event)\"\n @dragover=\"dragOver\"\n >\n <PlCheckbox\n :model-value=\"item.type === 'not'\"\n :class=\"$style.notCheckbox\"\n @update:model-value=\"inverseRootNode(index)\"\n >\n Filter Out\n </PlCheckbox>\n <template v-for=\"(_, filterIdx) in getNotContent(item).filters\" :key=\"filterIdx\">\n <FilterEditor\n :filter=\"validateFilter(getNotContent(item).filters[filterIdx])\"\n :operand=\"getNotContent(item).type\"\n :column-options=\"options\"\n :supported-filters=\"props.supportedFilters\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :enable-dnd=\"Boolean(props.enableDnd)\"\n :is-last=\"filterIdx === getNotContent(item).filters.length - 1\"\n @delete=\"() => removeFilterFromGroup(index, filterIdx)\"\n @update-filter=\"(value) => updateFilter(index, filterIdx, value)\"\n @change-operand=\"(v) => changeGroupOperand(index, v)\"\n />\n </template>\n <div v-if=\"props.enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <PlBtnSecondary\n v-else-if=\"!props.isCompletedGroup(item, index)\"\n icon=\"add\"\n @click=\"addColumnToGroup(index, firstColumnId)\"\n >\n Add filter\n </PlBtnSecondary>\n </div>\n </template>\n <template #item-after=\"{ index }\">\n <OperandButton\n v-if=\"props.enableAddGroupButton || index < getRootGroups().length - 1\"\n :class=\"$style.buttonWrapper\"\n :active=\"props.filters.type\"\n :disabled=\"index === getRootGroups().length - 1\"\n :on-select=\"changeRootOperand\"\n />\n </template>\n </PlElementList>\n\n <!-- Last group - always empty, just for adding new groups -->\n <PlElementList\n v-if=\"props.enableAddGroupButton\"\n :items=\"emptyGroup\"\n :get-item-key=\"(group) => group.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"() => true\"\n :disableDragging=\"true\"\n :disableRemoving=\"true\"\n :disableToggling=\"true\"\n :disablePinning=\"true\"\n dropzone=\"true\"\n @drop=\"handleDropToNewGroup\"\n @dragover=\"dragOver\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index + getRootGroups().length\"\n >Filter group</slot\n >\n </template>\n <template #item-content>\n <div v-if=\"enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <slot v-else name=\"add-group-buttons\">\n <PlBtnSecondary icon=\"add\" @click=\"addGroup(firstColumnId)\"> Add filter </PlBtnSecondary>\n </slot>\n </template>\n </PlElementList>\n </div>\n</template>\n<style module>\n.filterGroup {\n background: var(--bg-base-light);\n}\n.filterGroup:hover {\n background: rgba(99, 224, 36, 0.12);\n}\n.filterGroupTitle {\n background: none;\n}\n.filterGroupContent {\n padding: 4px 24px 24px 24px;\n}\n.groupContent {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.notCheckbox {\n margin: 4px 0;\n}\n.suppressedLabel {\n filter: grayscale(100%);\n pointer-events: none;\n}\n.dropzone {\n border-radius: 6px;\n border: 1.5px dashed var(--color-div-grey);\n color: var(--txt-03);\n font-family: Manrope;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n height: 40px;\n cursor: default;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.buttonWrapper {\n margin-top: 8px;\n height: 56px;\n display: flex;\n align-items: center;\n}\n:global(.sortable-chosen) .buttonWrapper {\n visibility: hidden;\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"PlAdvancedFilter.js","names":[],"sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends RootFilter\">\nimport { PlBtnSecondary, PlCheckbox, PlElementList } from \"@milaboratories/uikit\";\nimport type { ListOptionBase } from \"@platforma-sdk/model\";\nimport { produce } from \"immer\";\nimport { computed } from \"vue\";\nimport FilterEditor from \"./FilterEditor.vue\";\nimport OperandButton from \"./OperandButton.vue\";\nimport { DEFAULT_FILTER_TYPE, DEFAULT_FILTERS, SUPPORTED_FILTER_TYPES } from \"./constants\";\nimport type {\n CommonFilter,\n EditableFilter,\n NodeFilter,\n Operand,\n PlAdvancedFilterColumnId,\n RootFilter,\n SourceOptionInfo,\n} from \"./types\";\nimport { createNewGroup, getNewId, isValidColumnId } from \"./utils\";\n\nconst props = withDefaults(\n defineProps<{\n filters: T;\n onUpdateFilters: (filters: T) => void;\n /** List of ids of sources (columns, axes) that can be selected in filters */\n options: SourceOptionInfo[];\n /** List of supported filter types */\n supportedFilters?: typeof SUPPORTED_FILTER_TYPES;\n /** If true - new filter can be added by droppind element into filter group; else new column is added by button click */\n enableDnd?: boolean;\n /** If true - \"Add group\" button is shown below the filter groups */\n enableAddGroupButton?: boolean;\n /** If true - eye icon is shown per group to toggle suppression */\n enableToggling?: boolean;\n /** Function to determine if a filter is pinned */\n isPinned?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is removable */\n isRemovable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is draggable */\n isDraggable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a group is complete */\n isCompletedGroup?: (group: NodeFilter, index: number) => boolean;\n /** Loading function for unique values for Equal/InSet filters and fixed axes options. */\n getSuggestOptions: (params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n }) => ListOptionBase<string | number>[] | Promise<ListOptionBase<string | number>[]>;\n }>(),\n {\n supportedFilters: () => SUPPORTED_FILTER_TYPES,\n isCompletedGroup: () => false,\n isPinned: () => false,\n isRemovable: () => true,\n isDraggable: () => true,\n\n getSuggestModel: undefined,\n\n enableDnd: false,\n enableAddGroupButton: false,\n enableToggling: false,\n },\n);\nconst produceFiltersUpdate = (updater: (draft: T) => void) => {\n props.onUpdateFilters(produce(props.filters, updater));\n};\n\nconst firstColumnId = computed(() => props.options[0]?.id);\nconst emptyGroup: NodeFilter[] = [\n {\n id: -1,\n type: \"and\",\n filters: [],\n isExpanded: true,\n },\n];\n\nconst rootFilters = computed({\n get: () => props.filters.filters,\n set: (filters) => props.onUpdateFilters({ ...props.filters, filters: filters }),\n});\n\nfunction getRootGroups() {\n if (props.filters.type !== \"or\" && props.filters.type !== \"and\") {\n throw new Error('Invalid model structure, expected root to be \"or\" or \"and\" group');\n }\n return props.filters.filters;\n}\n\nfunction getDraftGroupContent(\n draft: RootFilter,\n idx: number,\n): Exclude<NodeFilter, { type: \"not\" }> {\n const group = draft.filters[idx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n return group.filter;\n }\n if (group.type !== \"and\" && group.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n return group;\n}\n\nfunction getNotContent<T extends CommonFilter>(item: T): Exclude<T, { type: \"not\" }> {\n return item.type === \"not\"\n ? (item.filter as Exclude<T, { type: \"not\" }>)\n : (item as Exclude<T, { type: \"not\" }>);\n}\n\nfunction addColumnToGroup(groupIdx: number, selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n group.filters.push({\n ...DEFAULT_FILTERS[DEFAULT_FILTER_TYPE],\n column: selectedSourceId,\n id: getNewId(),\n isExpanded: true,\n } as CommonFilter);\n });\n}\n\nfunction removeFilterFromGroup(groupIdx: number, filterIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n const removingLastLeaf = group.filters.length === 1 && filterIdx === 0;\n\n if (removingLastLeaf && props.isRemovable(draft.filters[groupIdx], groupIdx)) {\n draft.filters.splice(groupIdx, 1);\n } else {\n group.filters.splice(filterIdx, 1);\n }\n });\n}\n\nfunction inverseRootNode(groupIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = draft.filters[groupIdx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n ...group.filter,\n };\n } else {\n const type = draft.filters[groupIdx].type;\n if (type !== \"and\" && type !== \"or\" && type !== \"not\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n id: getNewId(),\n type: \"not\",\n filter: draft.filters[groupIdx],\n };\n }\n });\n}\n\nfunction addGroup(selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters.push(createNewGroup(selectedSourceId));\n });\n}\n\nfunction updateFilter(groupIdx: number, filterIdx: number, updatedFilter: EditableFilter) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, groupIdx).filters[filterIdx] = updatedFilter as CommonFilter;\n });\n}\n\nfunction handleDropToExistingGroup(groupIdx: number, event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addColumnToGroup(groupIdx, draggedId);\n }\n }\n}\n\nfunction handleDropToNewGroup(event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addGroup(draggedId);\n }\n }\n}\n\nfunction dragOver(event: DragEvent) {\n event.preventDefault();\n}\n\nfunction toggleExpand(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isExpanded = !draft.filters[index].isExpanded;\n });\n}\n\nfunction toggleSuppress(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isSuppressed = !draft.filters[index].isSuppressed;\n });\n}\n\nfunction changeGroupOperand(index: number, v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, index).type = v;\n });\n}\n\nfunction changeRootOperand(v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.type = v;\n });\n}\n\nfunction validateFilter<T extends CommonFilter>(item: T): EditableFilter {\n if (item.type === \"and\" || item.type === \"or\" || item.type === \"not\") {\n throw new Error(\"Invalid filter structure, expected leaf filter\");\n }\n\n return item as EditableFilter;\n}\n</script>\n<template>\n <div>\n <PlElementList\n v-model:items=\"rootFilters\"\n :get-item-key=\"(filter) => filter.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"(filter) => filter.isExpanded === true\"\n :on-expand=\"toggleExpand\"\n :is-toggled=\"(item) => item.isSuppressed === true\"\n :on-toggle=\"toggleSuppress\"\n :is-pinned=\"(item, index) => props.isPinned?.(item, index) === true\"\n :is-pinnable=\"() => false\"\n :is-removable=\"(item, index) => props.isRemovable?.(item, index) === true\"\n :is-draggable=\"(item, index) => props.isDraggable?.(item, index) === true\"\n :disable-toggling=\"props.enableToggling !== true\"\n :disable-dragging=\"false\"\n :disable-removing=\"false\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index\">Filter group</slot>\n </template>\n <template #item-content=\"{ item, index }\">\n <div\n :class=\"[$style.groupContent, { [$style.suppressedLabel]: item.isSuppressed }]\"\n dropzone=\"true\"\n @drop=\"(event) => handleDropToExistingGroup(index, event)\"\n @dragover=\"dragOver\"\n >\n <PlCheckbox\n :model-value=\"item.type === 'not'\"\n :class=\"$style.notCheckbox\"\n @update:model-value=\"inverseRootNode(index)\"\n >\n Filter Out\n </PlCheckbox>\n <template v-for=\"(_, filterIdx) in getNotContent(item).filters\" :key=\"filterIdx\">\n <FilterEditor\n :filter=\"validateFilter(getNotContent(item).filters[filterIdx])\"\n :operand=\"getNotContent(item).type\"\n :column-options=\"options\"\n :supported-filters=\"props.supportedFilters\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :enable-dnd=\"Boolean(props.enableDnd)\"\n :is-last=\"filterIdx === getNotContent(item).filters.length - 1\"\n @delete=\"() => removeFilterFromGroup(index, filterIdx)\"\n @update-filter=\"(value) => updateFilter(index, filterIdx, value)\"\n @change-operand=\"(v) => changeGroupOperand(index, v)\"\n />\n </template>\n <div v-if=\"props.enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <PlBtnSecondary\n v-else-if=\"!props.isCompletedGroup(item, index)\"\n icon=\"add\"\n @click=\"addColumnToGroup(index, firstColumnId)\"\n >\n Add filter\n </PlBtnSecondary>\n </div>\n </template>\n <template #item-after=\"{ index }\">\n <OperandButton\n v-if=\"props.enableAddGroupButton || index < getRootGroups().length - 1\"\n :class=\"$style.buttonWrapper\"\n :active=\"props.filters.type\"\n :disabled=\"index === getRootGroups().length - 1\"\n :on-select=\"changeRootOperand\"\n />\n </template>\n </PlElementList>\n\n <!-- Last group - always empty, just for adding new groups -->\n <PlElementList\n v-if=\"props.enableAddGroupButton\"\n :items=\"emptyGroup\"\n :get-item-key=\"(group) => group.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"() => true\"\n :disableDragging=\"true\"\n :disableRemoving=\"true\"\n :disableToggling=\"true\"\n :disablePinning=\"true\"\n dropzone=\"true\"\n @drop=\"handleDropToNewGroup\"\n @dragover=\"dragOver\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index + getRootGroups().length\"\n >Filter group</slot\n >\n </template>\n <template #item-content>\n <div v-if=\"enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <slot v-else name=\"add-group-buttons\">\n <PlBtnSecondary icon=\"add\" @click=\"addGroup(firstColumnId)\"> Add filter </PlBtnSecondary>\n </slot>\n </template>\n </PlElementList>\n </div>\n</template>\n<style module>\n.filterGroup {\n background: var(--bg-base-light);\n}\n.filterGroup:hover {\n background: rgba(99, 224, 36, 0.12);\n}\n.filterGroupTitle {\n background: none;\n}\n.filterGroupContent {\n padding: 4px 24px 24px 24px;\n}\n.groupContent {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.notCheckbox {\n margin: 4px 0;\n}\n.suppressedLabel {\n filter: grayscale(100%);\n pointer-events: none;\n}\n.dropzone {\n border-radius: 6px;\n border: 1.5px dashed var(--color-div-grey);\n color: var(--txt-03);\n font-family: Manrope;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n height: 40px;\n cursor: default;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.buttonWrapper {\n margin-top: 8px;\n height: 56px;\n display: flex;\n align-items: center;\n}\n:global(.sortable-chosen) .buttonWrapper {\n visibility: hidden;\n}\n</style>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"PlAdvancedFilter.vue_vue_type_style_index_0_lang.module.js","names":[],"sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends RootFilter\">\nimport { PlBtnSecondary, PlCheckbox, PlElementList } from \"@milaboratories/uikit\";\nimport type { ListOptionBase } from \"@platforma-sdk/model\";\nimport { produce } from \"immer\";\nimport { computed } from \"vue\";\nimport FilterEditor from \"./FilterEditor.vue\";\nimport OperandButton from \"./OperandButton.vue\";\nimport { DEFAULT_FILTER_TYPE, DEFAULT_FILTERS, SUPPORTED_FILTER_TYPES } from \"./constants\";\nimport type {\n CommonFilter,\n EditableFilter,\n NodeFilter,\n Operand,\n PlAdvancedFilterColumnId,\n RootFilter,\n SourceOptionInfo,\n} from \"./types\";\nimport { createNewGroup, getNewId, isValidColumnId } from \"./utils\";\n\nconst props = withDefaults(\n defineProps<{\n filters: T;\n onUpdateFilters: (filters: T) => void;\n /** List of ids of sources (columns, axes) that can be selected in filters */\n options: SourceOptionInfo[];\n /** List of supported filter types */\n supportedFilters?: typeof SUPPORTED_FILTER_TYPES;\n /** If true - new filter can be added by droppind element into filter group; else new column is added by button click */\n enableDnd?: boolean;\n /** If true - \"Add group\" button is shown below the filter groups */\n enableAddGroupButton?: boolean;\n /** If true - eye icon is shown per group to toggle suppression */\n enableToggling?: boolean;\n /** Function to determine if a filter is pinned */\n isPinned?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is removable */\n isRemovable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is draggable */\n isDraggable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a group is complete */\n isCompletedGroup?: (group: NodeFilter, index: number) => boolean;\n /** Loading function for unique values for Equal/InSet filters and fixed axes options. */\n getSuggestOptions: (params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n }) => ListOptionBase<string | number>[] | Promise<ListOptionBase<string | number>[]>;\n }>(),\n {\n supportedFilters: () => SUPPORTED_FILTER_TYPES,\n isCompletedGroup: () => false,\n isPinned: () => false,\n isRemovable: () => true,\n isDraggable: () => true,\n\n getSuggestModel: undefined,\n\n enableDnd: false,\n enableAddGroupButton: false,\n enableToggling: false,\n },\n);\nconst produceFiltersUpdate = (updater: (draft: T) => void) => {\n props.onUpdateFilters(produce(props.filters, updater));\n};\n\nconst firstColumnId = computed(() => props.options[0]?.id);\nconst emptyGroup: NodeFilter[] = [\n {\n id: -1,\n type: \"and\",\n filters: [],\n isExpanded: true,\n },\n];\n\nconst rootFilters = computed({\n get: () => props.filters.filters,\n set: (filters) => props.onUpdateFilters({ ...props.filters, filters: filters }),\n});\n\nfunction getRootGroups() {\n if (props.filters.type !== \"or\" && props.filters.type !== \"and\") {\n throw new Error('Invalid model structure, expected root to be \"or\" or \"and\" group');\n }\n return props.filters.filters;\n}\n\nfunction getDraftGroupContent(\n draft: RootFilter,\n idx: number,\n): Exclude<NodeFilter, { type: \"not\" }> {\n const group = draft.filters[idx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n return group.filter;\n }\n if (group.type !== \"and\" && group.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n return group;\n}\n\nfunction getNotContent<T extends CommonFilter>(item: T): Exclude<T, { type: \"not\" }> {\n return item.type === \"not\"\n ? (item.filter as Exclude<T, { type: \"not\" }>)\n : (item as Exclude<T, { type: \"not\" }>);\n}\n\nfunction addColumnToGroup(groupIdx: number, selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n group.filters.push({\n ...DEFAULT_FILTERS[DEFAULT_FILTER_TYPE],\n column: selectedSourceId,\n id: getNewId(),\n isExpanded: true,\n } as CommonFilter);\n });\n}\n\nfunction removeFilterFromGroup(groupIdx: number, filterIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n if (group.filters.length === 1 && filterIdx === 0) {\n draft.filters.splice(groupIdx, 1);\n } else {\n group.filters.splice(filterIdx, 1);\n }\n });\n}\n\nfunction inverseRootNode(groupIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = draft.filters[groupIdx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n ...group.filter,\n };\n } else {\n const type = draft.filters[groupIdx].type;\n if (type !== \"and\" && type !== \"or\" && type !== \"not\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n id: getNewId(),\n type: \"not\",\n filter: draft.filters[groupIdx],\n };\n }\n });\n}\n\nfunction addGroup(selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters.push(createNewGroup(selectedSourceId));\n });\n}\n\nfunction updateFilter(groupIdx: number, filterIdx: number, updatedFilter: EditableFilter) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, groupIdx).filters[filterIdx] = updatedFilter as CommonFilter;\n });\n}\n\nfunction handleDropToExistingGroup(groupIdx: number, event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addColumnToGroup(groupIdx, draggedId);\n }\n }\n}\n\nfunction handleDropToNewGroup(event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addGroup(draggedId);\n }\n }\n}\n\nfunction dragOver(event: DragEvent) {\n event.preventDefault();\n}\n\nfunction toggleExpand(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isExpanded = !draft.filters[index].isExpanded;\n });\n}\n\nfunction toggleSuppress(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isSuppressed = !draft.filters[index].isSuppressed;\n });\n}\n\nfunction changeGroupOperand(index: number, v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, index).type = v;\n });\n}\n\nfunction changeRootOperand(v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.type = v;\n });\n}\n\nfunction validateFilter<T extends CommonFilter>(item: T): EditableFilter {\n if (item.type === \"and\" || item.type === \"or\" || item.type === \"not\") {\n throw new Error(\"Invalid filter structure, expected leaf filter\");\n }\n\n return item as EditableFilter;\n}\n</script>\n<template>\n <div>\n <PlElementList\n v-model:items=\"rootFilters\"\n :get-item-key=\"(filter) => filter.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"(filter) => filter.isExpanded === true\"\n :on-expand=\"toggleExpand\"\n :is-toggled=\"(item) => item.isSuppressed === true\"\n :on-toggle=\"toggleSuppress\"\n :is-pinned=\"(item, index) => props.isPinned?.(item, index) === true\"\n :is-pinnable=\"() => false\"\n :is-removable=\"(item, index) => props.isRemovable?.(item, index) === true\"\n :is-draggable=\"(item, index) => props.isDraggable?.(item, index) === true\"\n :disable-toggling=\"props.enableToggling !== true\"\n :disable-dragging=\"false\"\n :disable-removing=\"false\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index\">Filter group</slot>\n </template>\n <template #item-content=\"{ item, index }\">\n <div\n :class=\"[$style.groupContent, { [$style.suppressedLabel]: item.isSuppressed }]\"\n dropzone=\"true\"\n @drop=\"(event) => handleDropToExistingGroup(index, event)\"\n @dragover=\"dragOver\"\n >\n <PlCheckbox\n :model-value=\"item.type === 'not'\"\n :class=\"$style.notCheckbox\"\n @update:model-value=\"inverseRootNode(index)\"\n >\n Filter Out\n </PlCheckbox>\n <template v-for=\"(_, filterIdx) in getNotContent(item).filters\" :key=\"filterIdx\">\n <FilterEditor\n :filter=\"validateFilter(getNotContent(item).filters[filterIdx])\"\n :operand=\"getNotContent(item).type\"\n :column-options=\"options\"\n :supported-filters=\"props.supportedFilters\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :enable-dnd=\"Boolean(props.enableDnd)\"\n :is-last=\"filterIdx === getNotContent(item).filters.length - 1\"\n @delete=\"() => removeFilterFromGroup(index, filterIdx)\"\n @update-filter=\"(value) => updateFilter(index, filterIdx, value)\"\n @change-operand=\"(v) => changeGroupOperand(index, v)\"\n />\n </template>\n <div v-if=\"props.enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <PlBtnSecondary\n v-else-if=\"!props.isCompletedGroup(item, index)\"\n icon=\"add\"\n @click=\"addColumnToGroup(index, firstColumnId)\"\n >\n Add filter\n </PlBtnSecondary>\n </div>\n </template>\n <template #item-after=\"{ index }\">\n <OperandButton\n v-if=\"props.enableAddGroupButton || index < getRootGroups().length - 1\"\n :class=\"$style.buttonWrapper\"\n :active=\"props.filters.type\"\n :disabled=\"index === getRootGroups().length - 1\"\n :on-select=\"changeRootOperand\"\n />\n </template>\n </PlElementList>\n\n <!-- Last group - always empty, just for adding new groups -->\n <PlElementList\n v-if=\"props.enableAddGroupButton\"\n :items=\"emptyGroup\"\n :get-item-key=\"(group) => group.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"() => true\"\n :disableDragging=\"true\"\n :disableRemoving=\"true\"\n :disableToggling=\"true\"\n :disablePinning=\"true\"\n dropzone=\"true\"\n @drop=\"handleDropToNewGroup\"\n @dragover=\"dragOver\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index + getRootGroups().length\"\n >Filter group</slot\n >\n </template>\n <template #item-content>\n <div v-if=\"enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <slot v-else name=\"add-group-buttons\">\n <PlBtnSecondary icon=\"add\" @click=\"addGroup(firstColumnId)\"> Add filter </PlBtnSecondary>\n </slot>\n </template>\n </PlElementList>\n </div>\n</template>\n<style module>\n.filterGroup {\n background: var(--bg-base-light);\n}\n.filterGroup:hover {\n background: rgba(99, 224, 36, 0.12);\n}\n.filterGroupTitle {\n background: none;\n}\n.filterGroupContent {\n padding: 4px 24px 24px 24px;\n}\n.groupContent {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.notCheckbox {\n margin: 4px 0;\n}\n.suppressedLabel {\n filter: grayscale(100%);\n pointer-events: none;\n}\n.dropzone {\n border-radius: 6px;\n border: 1.5px dashed var(--color-div-grey);\n color: var(--txt-03);\n font-family: Manrope;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n height: 40px;\n cursor: default;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.buttonWrapper {\n margin-top: 8px;\n height: 56px;\n display: flex;\n align-items: center;\n}\n:global(.sortable-chosen) .buttonWrapper {\n visibility: hidden;\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"PlAdvancedFilter.vue_vue_type_style_index_0_lang.module.js","names":[],"sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends RootFilter\">\nimport { PlBtnSecondary, PlCheckbox, PlElementList } from \"@milaboratories/uikit\";\nimport type { ListOptionBase } from \"@platforma-sdk/model\";\nimport { produce } from \"immer\";\nimport { computed } from \"vue\";\nimport FilterEditor from \"./FilterEditor.vue\";\nimport OperandButton from \"./OperandButton.vue\";\nimport { DEFAULT_FILTER_TYPE, DEFAULT_FILTERS, SUPPORTED_FILTER_TYPES } from \"./constants\";\nimport type {\n CommonFilter,\n EditableFilter,\n NodeFilter,\n Operand,\n PlAdvancedFilterColumnId,\n RootFilter,\n SourceOptionInfo,\n} from \"./types\";\nimport { createNewGroup, getNewId, isValidColumnId } from \"./utils\";\n\nconst props = withDefaults(\n defineProps<{\n filters: T;\n onUpdateFilters: (filters: T) => void;\n /** List of ids of sources (columns, axes) that can be selected in filters */\n options: SourceOptionInfo[];\n /** List of supported filter types */\n supportedFilters?: typeof SUPPORTED_FILTER_TYPES;\n /** If true - new filter can be added by droppind element into filter group; else new column is added by button click */\n enableDnd?: boolean;\n /** If true - \"Add group\" button is shown below the filter groups */\n enableAddGroupButton?: boolean;\n /** If true - eye icon is shown per group to toggle suppression */\n enableToggling?: boolean;\n /** Function to determine if a filter is pinned */\n isPinned?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is removable */\n isRemovable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is draggable */\n isDraggable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a group is complete */\n isCompletedGroup?: (group: NodeFilter, index: number) => boolean;\n /** Loading function for unique values for Equal/InSet filters and fixed axes options. */\n getSuggestOptions: (params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n }) => ListOptionBase<string | number>[] | Promise<ListOptionBase<string | number>[]>;\n }>(),\n {\n supportedFilters: () => SUPPORTED_FILTER_TYPES,\n isCompletedGroup: () => false,\n isPinned: () => false,\n isRemovable: () => true,\n isDraggable: () => true,\n\n getSuggestModel: undefined,\n\n enableDnd: false,\n enableAddGroupButton: false,\n enableToggling: false,\n },\n);\nconst produceFiltersUpdate = (updater: (draft: T) => void) => {\n props.onUpdateFilters(produce(props.filters, updater));\n};\n\nconst firstColumnId = computed(() => props.options[0]?.id);\nconst emptyGroup: NodeFilter[] = [\n {\n id: -1,\n type: \"and\",\n filters: [],\n isExpanded: true,\n },\n];\n\nconst rootFilters = computed({\n get: () => props.filters.filters,\n set: (filters) => props.onUpdateFilters({ ...props.filters, filters: filters }),\n});\n\nfunction getRootGroups() {\n if (props.filters.type !== \"or\" && props.filters.type !== \"and\") {\n throw new Error('Invalid model structure, expected root to be \"or\" or \"and\" group');\n }\n return props.filters.filters;\n}\n\nfunction getDraftGroupContent(\n draft: RootFilter,\n idx: number,\n): Exclude<NodeFilter, { type: \"not\" }> {\n const group = draft.filters[idx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n return group.filter;\n }\n if (group.type !== \"and\" && group.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n return group;\n}\n\nfunction getNotContent<T extends CommonFilter>(item: T): Exclude<T, { type: \"not\" }> {\n return item.type === \"not\"\n ? (item.filter as Exclude<T, { type: \"not\" }>)\n : (item as Exclude<T, { type: \"not\" }>);\n}\n\nfunction addColumnToGroup(groupIdx: number, selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n group.filters.push({\n ...DEFAULT_FILTERS[DEFAULT_FILTER_TYPE],\n column: selectedSourceId,\n id: getNewId(),\n isExpanded: true,\n } as CommonFilter);\n });\n}\n\nfunction removeFilterFromGroup(groupIdx: number, filterIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n const removingLastLeaf = group.filters.length === 1 && filterIdx === 0;\n\n if (removingLastLeaf && props.isRemovable(draft.filters[groupIdx], groupIdx)) {\n draft.filters.splice(groupIdx, 1);\n } else {\n group.filters.splice(filterIdx, 1);\n }\n });\n}\n\nfunction inverseRootNode(groupIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = draft.filters[groupIdx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n ...group.filter,\n };\n } else {\n const type = draft.filters[groupIdx].type;\n if (type !== \"and\" && type !== \"or\" && type !== \"not\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n id: getNewId(),\n type: \"not\",\n filter: draft.filters[groupIdx],\n };\n }\n });\n}\n\nfunction addGroup(selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters.push(createNewGroup(selectedSourceId));\n });\n}\n\nfunction updateFilter(groupIdx: number, filterIdx: number, updatedFilter: EditableFilter) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, groupIdx).filters[filterIdx] = updatedFilter as CommonFilter;\n });\n}\n\nfunction handleDropToExistingGroup(groupIdx: number, event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addColumnToGroup(groupIdx, draggedId);\n }\n }\n}\n\nfunction handleDropToNewGroup(event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addGroup(draggedId);\n }\n }\n}\n\nfunction dragOver(event: DragEvent) {\n event.preventDefault();\n}\n\nfunction toggleExpand(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isExpanded = !draft.filters[index].isExpanded;\n });\n}\n\nfunction toggleSuppress(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isSuppressed = !draft.filters[index].isSuppressed;\n });\n}\n\nfunction changeGroupOperand(index: number, v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, index).type = v;\n });\n}\n\nfunction changeRootOperand(v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.type = v;\n });\n}\n\nfunction validateFilter<T extends CommonFilter>(item: T): EditableFilter {\n if (item.type === \"and\" || item.type === \"or\" || item.type === \"not\") {\n throw new Error(\"Invalid filter structure, expected leaf filter\");\n }\n\n return item as EditableFilter;\n}\n</script>\n<template>\n <div>\n <PlElementList\n v-model:items=\"rootFilters\"\n :get-item-key=\"(filter) => filter.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"(filter) => filter.isExpanded === true\"\n :on-expand=\"toggleExpand\"\n :is-toggled=\"(item) => item.isSuppressed === true\"\n :on-toggle=\"toggleSuppress\"\n :is-pinned=\"(item, index) => props.isPinned?.(item, index) === true\"\n :is-pinnable=\"() => false\"\n :is-removable=\"(item, index) => props.isRemovable?.(item, index) === true\"\n :is-draggable=\"(item, index) => props.isDraggable?.(item, index) === true\"\n :disable-toggling=\"props.enableToggling !== true\"\n :disable-dragging=\"false\"\n :disable-removing=\"false\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index\">Filter group</slot>\n </template>\n <template #item-content=\"{ item, index }\">\n <div\n :class=\"[$style.groupContent, { [$style.suppressedLabel]: item.isSuppressed }]\"\n dropzone=\"true\"\n @drop=\"(event) => handleDropToExistingGroup(index, event)\"\n @dragover=\"dragOver\"\n >\n <PlCheckbox\n :model-value=\"item.type === 'not'\"\n :class=\"$style.notCheckbox\"\n @update:model-value=\"inverseRootNode(index)\"\n >\n Filter Out\n </PlCheckbox>\n <template v-for=\"(_, filterIdx) in getNotContent(item).filters\" :key=\"filterIdx\">\n <FilterEditor\n :filter=\"validateFilter(getNotContent(item).filters[filterIdx])\"\n :operand=\"getNotContent(item).type\"\n :column-options=\"options\"\n :supported-filters=\"props.supportedFilters\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :enable-dnd=\"Boolean(props.enableDnd)\"\n :is-last=\"filterIdx === getNotContent(item).filters.length - 1\"\n @delete=\"() => removeFilterFromGroup(index, filterIdx)\"\n @update-filter=\"(value) => updateFilter(index, filterIdx, value)\"\n @change-operand=\"(v) => changeGroupOperand(index, v)\"\n />\n </template>\n <div v-if=\"props.enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <PlBtnSecondary\n v-else-if=\"!props.isCompletedGroup(item, index)\"\n icon=\"add\"\n @click=\"addColumnToGroup(index, firstColumnId)\"\n >\n Add filter\n </PlBtnSecondary>\n </div>\n </template>\n <template #item-after=\"{ index }\">\n <OperandButton\n v-if=\"props.enableAddGroupButton || index < getRootGroups().length - 1\"\n :class=\"$style.buttonWrapper\"\n :active=\"props.filters.type\"\n :disabled=\"index === getRootGroups().length - 1\"\n :on-select=\"changeRootOperand\"\n />\n </template>\n </PlElementList>\n\n <!-- Last group - always empty, just for adding new groups -->\n <PlElementList\n v-if=\"props.enableAddGroupButton\"\n :items=\"emptyGroup\"\n :get-item-key=\"(group) => group.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"() => true\"\n :disableDragging=\"true\"\n :disableRemoving=\"true\"\n :disableToggling=\"true\"\n :disablePinning=\"true\"\n dropzone=\"true\"\n @drop=\"handleDropToNewGroup\"\n @dragover=\"dragOver\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index + getRootGroups().length\"\n >Filter group</slot\n >\n </template>\n <template #item-content>\n <div v-if=\"enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <slot v-else name=\"add-group-buttons\">\n <PlBtnSecondary icon=\"add\" @click=\"addGroup(firstColumnId)\"> Add filter </PlBtnSecondary>\n </slot>\n </template>\n </PlElementList>\n </div>\n</template>\n<style module>\n.filterGroup {\n background: var(--bg-base-light);\n}\n.filterGroup:hover {\n background: rgba(99, 224, 36, 0.12);\n}\n.filterGroupTitle {\n background: none;\n}\n.filterGroupContent {\n padding: 4px 24px 24px 24px;\n}\n.groupContent {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.notCheckbox {\n margin: 4px 0;\n}\n.suppressedLabel {\n filter: grayscale(100%);\n pointer-events: none;\n}\n.dropzone {\n border-radius: 6px;\n border: 1.5px dashed var(--color-div-grey);\n color: var(--txt-03);\n font-family: Manrope;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n height: 40px;\n cursor: default;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.buttonWrapper {\n margin-top: 8px;\n height: 56px;\n display: flex;\n align-items: center;\n}\n:global(.sortable-chosen) .buttonWrapper {\n visibility: hidden;\n}\n</style>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"PlAdvancedFilter.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"names":[],"mappings":"AAoYA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAK3D,OAAO,EAAwC,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC3F,OAAO,KAAK,EAGV,UAAU,EAEV,wBAAwB,EACxB,UAAU,EACV,gBAAgB,EACjB,MAAM,SAAS,CAAC;yBAGA,CAAC,SAAS,UAAU,EACpC,aAAa,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,EAC9D,YAAY,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,EAC3G,eAAe,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EACjE;WAwjBO,mBAAmB,CAAC;iBAtjBf,CAAC;yBACO,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI;QACrC,6EAA6E;iBACpE,gBAAgB,EAAE;QAC3B,qCAAqC;2BAClB,OAAO,sBAAsB;QAChD,wHAAwH;oBAC5G,OAAO;QACnB,oEAAoE;+BAC7C,OAAO;QAC9B,kEAAkE;yBACjD,OAAO;QACxB,kDAAkD;mBACvC,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO;QACvD,qDAAqD;sBACvC,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO;QAC1D,qDAAqD;sBACvC,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO;QAC1D,mDAAmD;2BAChC,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO;QAChE,yFAAyF;2BACtE,CAAC,MAAM,EAAE;YAC1B,QAAQ,EAAE,wBAAwB,CAAC;YACnC,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,SAAS,EAAE,MAAM,CAAC;YAClB,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC;SAC/B,KAAK,cAAc,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;mBA4hBM,CAAC,4BAA2B;oBACzG,OAAO,KAAK,EAAE,gBAAgB,CAAC,EAAE,CAAC,GAAG,IAAI;WAClD,GAAG;;;;;YArDwB,GAAG;;;;YACF,GAAG;qCACG,GAAG;;UAqDtC,EAAE;EAEL,KACQ,OAAO,KAAK,EAAE,KAAK,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC,OAAO,WAAW,CAAC,CAAA;CAAE;AAnkBzE,wBAmkB4E;AAe5E,KAAK,mBAAmB,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG,EAAE,CAAC"}
1
+ {"version":3,"file":"PlAdvancedFilter.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"names":[],"mappings":"AAsYA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAK3D,OAAO,EAAwC,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC3F,OAAO,KAAK,EAGV,UAAU,EAEV,wBAAwB,EACxB,UAAU,EACV,gBAAgB,EACjB,MAAM,SAAS,CAAC;yBAGA,CAAC,SAAS,UAAU,EACpC,aAAa,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,EAC9D,YAAY,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,EAC3G,eAAe,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EACjE;WA0jBO,mBAAmB,CAAC;iBAxjBf,CAAC;yBACO,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI;QACrC,6EAA6E;iBACpE,gBAAgB,EAAE;QAC3B,qCAAqC;2BAClB,OAAO,sBAAsB;QAChD,wHAAwH;oBAC5G,OAAO;QACnB,oEAAoE;+BAC7C,OAAO;QAC9B,kEAAkE;yBACjD,OAAO;QACxB,kDAAkD;mBACvC,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO;QACvD,qDAAqD;sBACvC,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO;QAC1D,qDAAqD;sBACvC,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO;QAC1D,mDAAmD;2BAChC,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO;QAChE,yFAAyF;2BACtE,CAAC,MAAM,EAAE;YAC1B,QAAQ,EAAE,wBAAwB,CAAC;YACnC,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,SAAS,EAAE,MAAM,CAAC;YAClB,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC;SAC/B,KAAK,cAAc,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;mBA8hBM,CAAC,4BAA2B;oBACzG,OAAO,KAAK,EAAE,gBAAgB,CAAC,EAAE,CAAC,GAAG,IAAI;WAClD,GAAG;;;;;YArDwB,GAAG;;;;YACF,GAAG;qCACG,GAAG;;UAqDtC,EAAE;EAEL,KACQ,OAAO,KAAK,EAAE,KAAK,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC,OAAO,WAAW,CAAC,CAAA;CAAE;AArkBzE,wBAqkB4E;AAe5E,KAAK,mBAAmB,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG,EAAE,CAAC"}
@@ -87,7 +87,7 @@ var D = ["onDrop"], O = /* @__PURE__ */ _({
87
87
  function I(e, t) {
88
88
  O((n) => {
89
89
  let r = N(n, e);
90
- r.filters.length === 1 && t === 0 ? n.filters.splice(e, 1) : r.filters.splice(t, 1);
90
+ r.filters.length === 1 && t === 0 && _.isRemovable(n.filters[e], e) ? n.filters.splice(e, 1) : r.filters.splice(t, 1);
91
91
  });
92
92
  }
93
93
  function L(e) {
@@ -1 +1 @@
1
- {"version":3,"file":"PlAdvancedFilter.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends RootFilter\">\nimport { PlBtnSecondary, PlCheckbox, PlElementList } from \"@milaboratories/uikit\";\nimport type { ListOptionBase } from \"@platforma-sdk/model\";\nimport { produce } from \"immer\";\nimport { computed } from \"vue\";\nimport FilterEditor from \"./FilterEditor.vue\";\nimport OperandButton from \"./OperandButton.vue\";\nimport { DEFAULT_FILTER_TYPE, DEFAULT_FILTERS, SUPPORTED_FILTER_TYPES } from \"./constants\";\nimport type {\n CommonFilter,\n EditableFilter,\n NodeFilter,\n Operand,\n PlAdvancedFilterColumnId,\n RootFilter,\n SourceOptionInfo,\n} from \"./types\";\nimport { createNewGroup, getNewId, isValidColumnId } from \"./utils\";\n\nconst props = withDefaults(\n defineProps<{\n filters: T;\n onUpdateFilters: (filters: T) => void;\n /** List of ids of sources (columns, axes) that can be selected in filters */\n options: SourceOptionInfo[];\n /** List of supported filter types */\n supportedFilters?: typeof SUPPORTED_FILTER_TYPES;\n /** If true - new filter can be added by droppind element into filter group; else new column is added by button click */\n enableDnd?: boolean;\n /** If true - \"Add group\" button is shown below the filter groups */\n enableAddGroupButton?: boolean;\n /** If true - eye icon is shown per group to toggle suppression */\n enableToggling?: boolean;\n /** Function to determine if a filter is pinned */\n isPinned?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is removable */\n isRemovable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is draggable */\n isDraggable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a group is complete */\n isCompletedGroup?: (group: NodeFilter, index: number) => boolean;\n /** Loading function for unique values for Equal/InSet filters and fixed axes options. */\n getSuggestOptions: (params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n }) => ListOptionBase<string | number>[] | Promise<ListOptionBase<string | number>[]>;\n }>(),\n {\n supportedFilters: () => SUPPORTED_FILTER_TYPES,\n isCompletedGroup: () => false,\n isPinned: () => false,\n isRemovable: () => true,\n isDraggable: () => true,\n\n getSuggestModel: undefined,\n\n enableDnd: false,\n enableAddGroupButton: false,\n enableToggling: false,\n },\n);\nconst produceFiltersUpdate = (updater: (draft: T) => void) => {\n props.onUpdateFilters(produce(props.filters, updater));\n};\n\nconst firstColumnId = computed(() => props.options[0]?.id);\nconst emptyGroup: NodeFilter[] = [\n {\n id: -1,\n type: \"and\",\n filters: [],\n isExpanded: true,\n },\n];\n\nconst rootFilters = computed({\n get: () => props.filters.filters,\n set: (filters) => props.onUpdateFilters({ ...props.filters, filters: filters }),\n});\n\nfunction getRootGroups() {\n if (props.filters.type !== \"or\" && props.filters.type !== \"and\") {\n throw new Error('Invalid model structure, expected root to be \"or\" or \"and\" group');\n }\n return props.filters.filters;\n}\n\nfunction getDraftGroupContent(\n draft: RootFilter,\n idx: number,\n): Exclude<NodeFilter, { type: \"not\" }> {\n const group = draft.filters[idx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n return group.filter;\n }\n if (group.type !== \"and\" && group.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n return group;\n}\n\nfunction getNotContent<T extends CommonFilter>(item: T): Exclude<T, { type: \"not\" }> {\n return item.type === \"not\"\n ? (item.filter as Exclude<T, { type: \"not\" }>)\n : (item as Exclude<T, { type: \"not\" }>);\n}\n\nfunction addColumnToGroup(groupIdx: number, selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n group.filters.push({\n ...DEFAULT_FILTERS[DEFAULT_FILTER_TYPE],\n column: selectedSourceId,\n id: getNewId(),\n isExpanded: true,\n } as CommonFilter);\n });\n}\n\nfunction removeFilterFromGroup(groupIdx: number, filterIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n if (group.filters.length === 1 && filterIdx === 0) {\n draft.filters.splice(groupIdx, 1);\n } else {\n group.filters.splice(filterIdx, 1);\n }\n });\n}\n\nfunction inverseRootNode(groupIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = draft.filters[groupIdx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n ...group.filter,\n };\n } else {\n const type = draft.filters[groupIdx].type;\n if (type !== \"and\" && type !== \"or\" && type !== \"not\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n id: getNewId(),\n type: \"not\",\n filter: draft.filters[groupIdx],\n };\n }\n });\n}\n\nfunction addGroup(selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters.push(createNewGroup(selectedSourceId));\n });\n}\n\nfunction updateFilter(groupIdx: number, filterIdx: number, updatedFilter: EditableFilter) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, groupIdx).filters[filterIdx] = updatedFilter as CommonFilter;\n });\n}\n\nfunction handleDropToExistingGroup(groupIdx: number, event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addColumnToGroup(groupIdx, draggedId);\n }\n }\n}\n\nfunction handleDropToNewGroup(event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addGroup(draggedId);\n }\n }\n}\n\nfunction dragOver(event: DragEvent) {\n event.preventDefault();\n}\n\nfunction toggleExpand(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isExpanded = !draft.filters[index].isExpanded;\n });\n}\n\nfunction toggleSuppress(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isSuppressed = !draft.filters[index].isSuppressed;\n });\n}\n\nfunction changeGroupOperand(index: number, v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, index).type = v;\n });\n}\n\nfunction changeRootOperand(v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.type = v;\n });\n}\n\nfunction validateFilter<T extends CommonFilter>(item: T): EditableFilter {\n if (item.type === \"and\" || item.type === \"or\" || item.type === \"not\") {\n throw new Error(\"Invalid filter structure, expected leaf filter\");\n }\n\n return item as EditableFilter;\n}\n</script>\n<template>\n <div>\n <PlElementList\n v-model:items=\"rootFilters\"\n :get-item-key=\"(filter) => filter.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"(filter) => filter.isExpanded === true\"\n :on-expand=\"toggleExpand\"\n :is-toggled=\"(item) => item.isSuppressed === true\"\n :on-toggle=\"toggleSuppress\"\n :is-pinned=\"(item, index) => props.isPinned?.(item, index) === true\"\n :is-pinnable=\"() => false\"\n :is-removable=\"(item, index) => props.isRemovable?.(item, index) === true\"\n :is-draggable=\"(item, index) => props.isDraggable?.(item, index) === true\"\n :disable-toggling=\"props.enableToggling !== true\"\n :disable-dragging=\"false\"\n :disable-removing=\"false\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index\">Filter group</slot>\n </template>\n <template #item-content=\"{ item, index }\">\n <div\n :class=\"[$style.groupContent, { [$style.suppressedLabel]: item.isSuppressed }]\"\n dropzone=\"true\"\n @drop=\"(event) => handleDropToExistingGroup(index, event)\"\n @dragover=\"dragOver\"\n >\n <PlCheckbox\n :model-value=\"item.type === 'not'\"\n :class=\"$style.notCheckbox\"\n @update:model-value=\"inverseRootNode(index)\"\n >\n Filter Out\n </PlCheckbox>\n <template v-for=\"(_, filterIdx) in getNotContent(item).filters\" :key=\"filterIdx\">\n <FilterEditor\n :filter=\"validateFilter(getNotContent(item).filters[filterIdx])\"\n :operand=\"getNotContent(item).type\"\n :column-options=\"options\"\n :supported-filters=\"props.supportedFilters\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :enable-dnd=\"Boolean(props.enableDnd)\"\n :is-last=\"filterIdx === getNotContent(item).filters.length - 1\"\n @delete=\"() => removeFilterFromGroup(index, filterIdx)\"\n @update-filter=\"(value) => updateFilter(index, filterIdx, value)\"\n @change-operand=\"(v) => changeGroupOperand(index, v)\"\n />\n </template>\n <div v-if=\"props.enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <PlBtnSecondary\n v-else-if=\"!props.isCompletedGroup(item, index)\"\n icon=\"add\"\n @click=\"addColumnToGroup(index, firstColumnId)\"\n >\n Add filter\n </PlBtnSecondary>\n </div>\n </template>\n <template #item-after=\"{ index }\">\n <OperandButton\n v-if=\"props.enableAddGroupButton || index < getRootGroups().length - 1\"\n :class=\"$style.buttonWrapper\"\n :active=\"props.filters.type\"\n :disabled=\"index === getRootGroups().length - 1\"\n :on-select=\"changeRootOperand\"\n />\n </template>\n </PlElementList>\n\n <!-- Last group - always empty, just for adding new groups -->\n <PlElementList\n v-if=\"props.enableAddGroupButton\"\n :items=\"emptyGroup\"\n :get-item-key=\"(group) => group.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"() => true\"\n :disableDragging=\"true\"\n :disableRemoving=\"true\"\n :disableToggling=\"true\"\n :disablePinning=\"true\"\n dropzone=\"true\"\n @drop=\"handleDropToNewGroup\"\n @dragover=\"dragOver\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index + getRootGroups().length\"\n >Filter group</slot\n >\n </template>\n <template #item-content>\n <div v-if=\"enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <slot v-else name=\"add-group-buttons\">\n <PlBtnSecondary icon=\"add\" @click=\"addGroup(firstColumnId)\"> Add filter </PlBtnSecondary>\n </slot>\n </template>\n </PlElementList>\n </div>\n</template>\n<style module>\n.filterGroup {\n background: var(--bg-base-light);\n}\n.filterGroup:hover {\n background: rgba(99, 224, 36, 0.12);\n}\n.filterGroupTitle {\n background: none;\n}\n.filterGroupContent {\n padding: 4px 24px 24px 24px;\n}\n.groupContent {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.notCheckbox {\n margin: 4px 0;\n}\n.suppressedLabel {\n filter: grayscale(100%);\n pointer-events: none;\n}\n.dropzone {\n border-radius: 6px;\n border: 1.5px dashed var(--color-div-grey);\n color: var(--txt-03);\n font-family: Manrope;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n height: 40px;\n cursor: default;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.buttonWrapper {\n margin-top: 8px;\n height: 56px;\n display: flex;\n align-items: center;\n}\n:global(.sortable-chosen) .buttonWrapper {\n visibility: hidden;\n}\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"PlAdvancedFilter.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends RootFilter\">\nimport { PlBtnSecondary, PlCheckbox, PlElementList } from \"@milaboratories/uikit\";\nimport type { ListOptionBase } from \"@platforma-sdk/model\";\nimport { produce } from \"immer\";\nimport { computed } from \"vue\";\nimport FilterEditor from \"./FilterEditor.vue\";\nimport OperandButton from \"./OperandButton.vue\";\nimport { DEFAULT_FILTER_TYPE, DEFAULT_FILTERS, SUPPORTED_FILTER_TYPES } from \"./constants\";\nimport type {\n CommonFilter,\n EditableFilter,\n NodeFilter,\n Operand,\n PlAdvancedFilterColumnId,\n RootFilter,\n SourceOptionInfo,\n} from \"./types\";\nimport { createNewGroup, getNewId, isValidColumnId } from \"./utils\";\n\nconst props = withDefaults(\n defineProps<{\n filters: T;\n onUpdateFilters: (filters: T) => void;\n /** List of ids of sources (columns, axes) that can be selected in filters */\n options: SourceOptionInfo[];\n /** List of supported filter types */\n supportedFilters?: typeof SUPPORTED_FILTER_TYPES;\n /** If true - new filter can be added by droppind element into filter group; else new column is added by button click */\n enableDnd?: boolean;\n /** If true - \"Add group\" button is shown below the filter groups */\n enableAddGroupButton?: boolean;\n /** If true - eye icon is shown per group to toggle suppression */\n enableToggling?: boolean;\n /** Function to determine if a filter is pinned */\n isPinned?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is removable */\n isRemovable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is draggable */\n isDraggable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a group is complete */\n isCompletedGroup?: (group: NodeFilter, index: number) => boolean;\n /** Loading function for unique values for Equal/InSet filters and fixed axes options. */\n getSuggestOptions: (params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n }) => ListOptionBase<string | number>[] | Promise<ListOptionBase<string | number>[]>;\n }>(),\n {\n supportedFilters: () => SUPPORTED_FILTER_TYPES,\n isCompletedGroup: () => false,\n isPinned: () => false,\n isRemovable: () => true,\n isDraggable: () => true,\n\n getSuggestModel: undefined,\n\n enableDnd: false,\n enableAddGroupButton: false,\n enableToggling: false,\n },\n);\nconst produceFiltersUpdate = (updater: (draft: T) => void) => {\n props.onUpdateFilters(produce(props.filters, updater));\n};\n\nconst firstColumnId = computed(() => props.options[0]?.id);\nconst emptyGroup: NodeFilter[] = [\n {\n id: -1,\n type: \"and\",\n filters: [],\n isExpanded: true,\n },\n];\n\nconst rootFilters = computed({\n get: () => props.filters.filters,\n set: (filters) => props.onUpdateFilters({ ...props.filters, filters: filters }),\n});\n\nfunction getRootGroups() {\n if (props.filters.type !== \"or\" && props.filters.type !== \"and\") {\n throw new Error('Invalid model structure, expected root to be \"or\" or \"and\" group');\n }\n return props.filters.filters;\n}\n\nfunction getDraftGroupContent(\n draft: RootFilter,\n idx: number,\n): Exclude<NodeFilter, { type: \"not\" }> {\n const group = draft.filters[idx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n return group.filter;\n }\n if (group.type !== \"and\" && group.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n return group;\n}\n\nfunction getNotContent<T extends CommonFilter>(item: T): Exclude<T, { type: \"not\" }> {\n return item.type === \"not\"\n ? (item.filter as Exclude<T, { type: \"not\" }>)\n : (item as Exclude<T, { type: \"not\" }>);\n}\n\nfunction addColumnToGroup(groupIdx: number, selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n group.filters.push({\n ...DEFAULT_FILTERS[DEFAULT_FILTER_TYPE],\n column: selectedSourceId,\n id: getNewId(),\n isExpanded: true,\n } as CommonFilter);\n });\n}\n\nfunction removeFilterFromGroup(groupIdx: number, filterIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n const removingLastLeaf = group.filters.length === 1 && filterIdx === 0;\n\n if (removingLastLeaf && props.isRemovable(draft.filters[groupIdx], groupIdx)) {\n draft.filters.splice(groupIdx, 1);\n } else {\n group.filters.splice(filterIdx, 1);\n }\n });\n}\n\nfunction inverseRootNode(groupIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = draft.filters[groupIdx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n ...group.filter,\n };\n } else {\n const type = draft.filters[groupIdx].type;\n if (type !== \"and\" && type !== \"or\" && type !== \"not\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n id: getNewId(),\n type: \"not\",\n filter: draft.filters[groupIdx],\n };\n }\n });\n}\n\nfunction addGroup(selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters.push(createNewGroup(selectedSourceId));\n });\n}\n\nfunction updateFilter(groupIdx: number, filterIdx: number, updatedFilter: EditableFilter) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, groupIdx).filters[filterIdx] = updatedFilter as CommonFilter;\n });\n}\n\nfunction handleDropToExistingGroup(groupIdx: number, event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addColumnToGroup(groupIdx, draggedId);\n }\n }\n}\n\nfunction handleDropToNewGroup(event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addGroup(draggedId);\n }\n }\n}\n\nfunction dragOver(event: DragEvent) {\n event.preventDefault();\n}\n\nfunction toggleExpand(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isExpanded = !draft.filters[index].isExpanded;\n });\n}\n\nfunction toggleSuppress(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isSuppressed = !draft.filters[index].isSuppressed;\n });\n}\n\nfunction changeGroupOperand(index: number, v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, index).type = v;\n });\n}\n\nfunction changeRootOperand(v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.type = v;\n });\n}\n\nfunction validateFilter<T extends CommonFilter>(item: T): EditableFilter {\n if (item.type === \"and\" || item.type === \"or\" || item.type === \"not\") {\n throw new Error(\"Invalid filter structure, expected leaf filter\");\n }\n\n return item as EditableFilter;\n}\n</script>\n<template>\n <div>\n <PlElementList\n v-model:items=\"rootFilters\"\n :get-item-key=\"(filter) => filter.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"(filter) => filter.isExpanded === true\"\n :on-expand=\"toggleExpand\"\n :is-toggled=\"(item) => item.isSuppressed === true\"\n :on-toggle=\"toggleSuppress\"\n :is-pinned=\"(item, index) => props.isPinned?.(item, index) === true\"\n :is-pinnable=\"() => false\"\n :is-removable=\"(item, index) => props.isRemovable?.(item, index) === true\"\n :is-draggable=\"(item, index) => props.isDraggable?.(item, index) === true\"\n :disable-toggling=\"props.enableToggling !== true\"\n :disable-dragging=\"false\"\n :disable-removing=\"false\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index\">Filter group</slot>\n </template>\n <template #item-content=\"{ item, index }\">\n <div\n :class=\"[$style.groupContent, { [$style.suppressedLabel]: item.isSuppressed }]\"\n dropzone=\"true\"\n @drop=\"(event) => handleDropToExistingGroup(index, event)\"\n @dragover=\"dragOver\"\n >\n <PlCheckbox\n :model-value=\"item.type === 'not'\"\n :class=\"$style.notCheckbox\"\n @update:model-value=\"inverseRootNode(index)\"\n >\n Filter Out\n </PlCheckbox>\n <template v-for=\"(_, filterIdx) in getNotContent(item).filters\" :key=\"filterIdx\">\n <FilterEditor\n :filter=\"validateFilter(getNotContent(item).filters[filterIdx])\"\n :operand=\"getNotContent(item).type\"\n :column-options=\"options\"\n :supported-filters=\"props.supportedFilters\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :enable-dnd=\"Boolean(props.enableDnd)\"\n :is-last=\"filterIdx === getNotContent(item).filters.length - 1\"\n @delete=\"() => removeFilterFromGroup(index, filterIdx)\"\n @update-filter=\"(value) => updateFilter(index, filterIdx, value)\"\n @change-operand=\"(v) => changeGroupOperand(index, v)\"\n />\n </template>\n <div v-if=\"props.enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <PlBtnSecondary\n v-else-if=\"!props.isCompletedGroup(item, index)\"\n icon=\"add\"\n @click=\"addColumnToGroup(index, firstColumnId)\"\n >\n Add filter\n </PlBtnSecondary>\n </div>\n </template>\n <template #item-after=\"{ index }\">\n <OperandButton\n v-if=\"props.enableAddGroupButton || index < getRootGroups().length - 1\"\n :class=\"$style.buttonWrapper\"\n :active=\"props.filters.type\"\n :disabled=\"index === getRootGroups().length - 1\"\n :on-select=\"changeRootOperand\"\n />\n </template>\n </PlElementList>\n\n <!-- Last group - always empty, just for adding new groups -->\n <PlElementList\n v-if=\"props.enableAddGroupButton\"\n :items=\"emptyGroup\"\n :get-item-key=\"(group) => group.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"() => true\"\n :disableDragging=\"true\"\n :disableRemoving=\"true\"\n :disableToggling=\"true\"\n :disablePinning=\"true\"\n dropzone=\"true\"\n @drop=\"handleDropToNewGroup\"\n @dragover=\"dragOver\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index + getRootGroups().length\"\n >Filter group</slot\n >\n </template>\n <template #item-content>\n <div v-if=\"enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <slot v-else name=\"add-group-buttons\">\n <PlBtnSecondary icon=\"add\" @click=\"addGroup(firstColumnId)\"> Add filter </PlBtnSecondary>\n </slot>\n </template>\n </PlElementList>\n </div>\n</template>\n<style module>\n.filterGroup {\n background: var(--bg-base-light);\n}\n.filterGroup:hover {\n background: rgba(99, 224, 36, 0.12);\n}\n.filterGroupTitle {\n background: none;\n}\n.filterGroupContent {\n padding: 4px 24px 24px 24px;\n}\n.groupContent {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.notCheckbox {\n margin: 4px 0;\n}\n.suppressedLabel {\n filter: grayscale(100%);\n pointer-events: none;\n}\n.dropzone {\n border-radius: 6px;\n border: 1.5px dashed var(--color-div-grey);\n color: var(--txt-03);\n font-family: Manrope;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n height: 40px;\n cursor: default;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.buttonWrapper {\n margin-top: 8px;\n height: 56px;\n display: flex;\n align-items: center;\n}\n:global(.sortable-chosen) .buttonWrapper {\n visibility: hidden;\n}\n</style>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PlAgCsvExporter.js","names":[],"sources":["../../../src/components/PlAgCsvExporter/PlAgCsvExporter.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { GridApi } from \"ag-grid-enterprise\";\nimport type { PTableHandle } from \"@platforma-sdk/model\";\nimport { PlBtnGhost, usePlBlockPageTitleTeleportTarget } from \"@milaboratories/uikit\";\nimport { shallowRef, toRefs } from \"vue\";\nimport { isNil } from \"es-toolkit\";\nimport { exportCsv, isCsvExportAvailable } from \"./export-csv\";\nimport type { ExportOptions } from \"./export-csv\";\n\nconst props = defineProps<{\n api: GridApi;\n tableHandle?: PTableHandle;\n}>();\nconst { api: gridApi } = toRefs(props);\nconst csvExportAvailable = isCsvExportAvailable();\n\nconst exporting = shallowRef(false);\nconst initiateExport = () => {\n const nativeOptions: ExportOptions | undefined = !isNil(props.tableHandle)\n ? { tableHandle: props.tableHandle }\n : undefined;\n\n if (isNil(nativeOptions)) {\n return;\n }\n\n exporting.value = true;\n exportCsv(gridApi.value, nativeOptions).finally(() => (exporting.value = false));\n};\n\nconst teleportTarget = usePlBlockPageTitleTeleportTarget(\"PlAgCsvExporter\");\n</script>\n\n<template>\n <Teleport v-if=\"teleportTarget && csvExportAvailable\" :to=\"teleportTarget\">\n <PlBtnGhost :loading=\"exporting\" icon=\"export\" @click.stop=\"initiateExport\">\n Export\n </PlBtnGhost>\n </Teleport>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"PlAgCsvExporter.js","names":[],"sources":["../../../src/components/PlAgCsvExporter/PlAgCsvExporter.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { GridApi } from \"ag-grid-enterprise\";\nimport type { PTableHandle, PlDataTableColumnsMeta } from \"@platforma-sdk/model\";\nimport { PlBtnGhost, usePlBlockPageTitleTeleportTarget } from \"@milaboratories/uikit\";\nimport { shallowRef, toRefs } from \"vue\";\nimport { isNil } from \"es-toolkit\";\nimport { exportCsv, isCsvExportAvailable } from \"./export-csv\";\nimport type { ExportOptions } from \"./export-csv\";\n\nconst props = defineProps<{\n api: GridApi;\n tableHandle?: PTableHandle;\n columnsMeta?: PlDataTableColumnsMeta;\n}>();\nconst { api: gridApi } = toRefs(props);\nconst csvExportAvailable = isCsvExportAvailable();\n\nconst exporting = shallowRef(false);\nconst initiateExport = () => {\n const nativeOptions: ExportOptions | undefined = !isNil(props.tableHandle)\n ? { tableHandle: props.tableHandle, columnsMeta: props.columnsMeta }\n : undefined;\n\n if (isNil(nativeOptions)) {\n return;\n }\n\n exporting.value = true;\n exportCsv(gridApi.value, nativeOptions).finally(() => (exporting.value = false));\n};\n\nconst teleportTarget = usePlBlockPageTitleTeleportTarget(\"PlAgCsvExporter\");\n</script>\n\n<template>\n <Teleport v-if=\"teleportTarget && csvExportAvailable\" :to=\"teleportTarget\">\n <PlBtnGhost :loading=\"exporting\" icon=\"export\" @click.stop=\"initiateExport\">\n Export\n </PlBtnGhost>\n </Teleport>\n</template>\n"],"mappings":""}
@@ -1,8 +1,9 @@
1
1
  import { GridApi } from 'ag-grid-enterprise';
2
- import { PTableHandle } from '@platforma-sdk/model';
2
+ import { PTableHandle, PlDataTableColumnsMeta } from '@platforma-sdk/model';
3
3
  type __VLS_Props = {
4
4
  api: GridApi;
5
5
  tableHandle?: PTableHandle;
6
+ columnsMeta?: PlDataTableColumnsMeta;
6
7
  };
7
8
  declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
8
9
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"PlAgCsvExporter.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlAgCsvExporter/PlAgCsvExporter.vue"],"names":[],"mappings":"AA0CA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAOzD,KAAK,WAAW,GAAG;IACjB,GAAG,EAAE,OAAO,CAAC;IACb,WAAW,CAAC,EAAE,YAAY,CAAC;CAC5B,CAAC;;AA4FF,wBAMG"}
1
+ {"version":3,"file":"PlAgCsvExporter.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlAgCsvExporter/PlAgCsvExporter.vue"],"names":[],"mappings":"AA2CA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAOjF,KAAK,WAAW,GAAG;IACjB,GAAG,EAAE,OAAO,CAAC;IACb,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,WAAW,CAAC,EAAE,sBAAsB,CAAC;CACtC,CAAC;;AA4FF,wBAMG"}
@@ -7,11 +7,15 @@ var _ = /* @__PURE__ */ s({
7
7
  __name: "PlAgCsvExporter",
8
8
  props: {
9
9
  api: {},
10
- tableHandle: {}
10
+ tableHandle: {},
11
+ columnsMeta: {}
11
12
  },
12
13
  setup(s) {
13
14
  let _ = s, { api: v } = u(_), y = t(), b = l(!1), x = () => {
14
- let t = m(_.tableHandle) ? void 0 : { tableHandle: _.tableHandle };
15
+ let t = m(_.tableHandle) ? void 0 : {
16
+ tableHandle: _.tableHandle,
17
+ columnsMeta: _.columnsMeta
18
+ };
15
19
  m(t) || (b.value = !0, e(v.value, t).finally(() => b.value = !1));
16
20
  }, S = g("PlAgCsvExporter");
17
21
  return (e, t) => d(S) && d(y) ? (c(), r(n, {
@@ -1 +1 @@
1
- {"version":3,"file":"PlAgCsvExporter.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/PlAgCsvExporter/PlAgCsvExporter.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { GridApi } from \"ag-grid-enterprise\";\nimport type { PTableHandle } from \"@platforma-sdk/model\";\nimport { PlBtnGhost, usePlBlockPageTitleTeleportTarget } from \"@milaboratories/uikit\";\nimport { shallowRef, toRefs } from \"vue\";\nimport { isNil } from \"es-toolkit\";\nimport { exportCsv, isCsvExportAvailable } from \"./export-csv\";\nimport type { ExportOptions } from \"./export-csv\";\n\nconst props = defineProps<{\n api: GridApi;\n tableHandle?: PTableHandle;\n}>();\nconst { api: gridApi } = toRefs(props);\nconst csvExportAvailable = isCsvExportAvailable();\n\nconst exporting = shallowRef(false);\nconst initiateExport = () => {\n const nativeOptions: ExportOptions | undefined = !isNil(props.tableHandle)\n ? { tableHandle: props.tableHandle }\n : undefined;\n\n if (isNil(nativeOptions)) {\n return;\n }\n\n exporting.value = true;\n exportCsv(gridApi.value, nativeOptions).finally(() => (exporting.value = false));\n};\n\nconst teleportTarget = usePlBlockPageTitleTeleportTarget(\"PlAgCsvExporter\");\n</script>\n\n<template>\n <Teleport v-if=\"teleportTarget && csvExportAvailable\" :to=\"teleportTarget\">\n <PlBtnGhost :loading=\"exporting\" icon=\"export\" @click.stop=\"initiateExport\">\n Export\n </PlBtnGhost>\n </Teleport>\n</template>\n"],"mappings":";;;;;;;;;;;;EASA,IAAM,IAAQ,GAIR,EAAE,KAAK,MAAY,EAAO,EAAM,EAChC,IAAqB,GAAsB,EAE3C,IAAY,EAAW,GAAM,EAC7B,UAAuB;GAC3B,IAAM,IAA4C,EAAM,EAAM,YAAW,GAErE,KAAA,IADA,EAAE,aAAa,EAAM,aAAY;AAGjC,KAAM,EAAc,KAIxB,EAAU,QAAQ,IAClB,EAAU,EAAQ,OAAO,EAAc,CAAC,cAAe,EAAU,QAAQ,GAAO;KAG5E,IAAiB,EAAkC,kBAAkB;mBAIzD,EAAA,EAAc,IAAI,EAAA,EAAkB,IAAA,GAAA,EAApD,EAIW,GAAA;;GAJ4C,IAAI,EAAA,EAAc;MACvE,EAEa,EAAA,EAAA,EAAA;GAFA,SAAS,EAAA;GAAW,MAAK;GAAU,SAAK,EAAO,GAAc,CAAA,OAAA,CAAA;;oBAE1E,CAAA,GAAA,AAAA,EAAA,OAAA,CAAA,EAF4E,YAE5E,GAAA,CAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"PlAgCsvExporter.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/PlAgCsvExporter/PlAgCsvExporter.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { GridApi } from \"ag-grid-enterprise\";\nimport type { PTableHandle, PlDataTableColumnsMeta } from \"@platforma-sdk/model\";\nimport { PlBtnGhost, usePlBlockPageTitleTeleportTarget } from \"@milaboratories/uikit\";\nimport { shallowRef, toRefs } from \"vue\";\nimport { isNil } from \"es-toolkit\";\nimport { exportCsv, isCsvExportAvailable } from \"./export-csv\";\nimport type { ExportOptions } from \"./export-csv\";\n\nconst props = defineProps<{\n api: GridApi;\n tableHandle?: PTableHandle;\n columnsMeta?: PlDataTableColumnsMeta;\n}>();\nconst { api: gridApi } = toRefs(props);\nconst csvExportAvailable = isCsvExportAvailable();\n\nconst exporting = shallowRef(false);\nconst initiateExport = () => {\n const nativeOptions: ExportOptions | undefined = !isNil(props.tableHandle)\n ? { tableHandle: props.tableHandle, columnsMeta: props.columnsMeta }\n : undefined;\n\n if (isNil(nativeOptions)) {\n return;\n }\n\n exporting.value = true;\n exportCsv(gridApi.value, nativeOptions).finally(() => (exporting.value = false));\n};\n\nconst teleportTarget = usePlBlockPageTitleTeleportTarget(\"PlAgCsvExporter\");\n</script>\n\n<template>\n <Teleport v-if=\"teleportTarget && csvExportAvailable\" :to=\"teleportTarget\">\n <PlBtnGhost :loading=\"exporting\" icon=\"export\" @click.stop=\"initiateExport\">\n Export\n </PlBtnGhost>\n </Teleport>\n</template>\n"],"mappings":";;;;;;;;;;;;;EASA,IAAM,IAAQ,GAKR,EAAE,KAAK,MAAY,EAAO,EAAM,EAChC,IAAqB,GAAsB,EAE3C,IAAY,EAAW,GAAM,EAC7B,UAAuB;GAC3B,IAAM,IAA4C,EAAM,EAAM,YAAW,GAErE,KAAA,IADA;IAAE,aAAa,EAAM;IAAa,aAAa,EAAM;IAAY;AAGjE,KAAM,EAAc,KAIxB,EAAU,QAAQ,IAClB,EAAU,EAAQ,OAAO,EAAc,CAAC,cAAe,EAAU,QAAQ,GAAO;KAG5E,IAAiB,EAAkC,kBAAkB;mBAIzD,EAAA,EAAc,IAAI,EAAA,EAAkB,IAAA,GAAA,EAApD,EAIW,GAAA;;GAJ4C,IAAI,EAAA,EAAc;MACvE,EAEa,EAAA,EAAA,EAAA;GAFA,SAAS,EAAA;GAAW,MAAK;GAAU,SAAK,EAAO,GAAc,CAAA,OAAA,CAAA;;oBAE1E,CAAA,GAAA,AAAA,EAAA,OAAA,CAAA,EAF4E,YAE5E,GAAA,CAAA,CAAA,CAAA"}
@@ -1,10 +1,16 @@
1
1
  import { GridApi } from 'ag-grid-enterprise';
2
- import { PTableHandle, PTableColumnSpec, PFrameSpecDriver, WritePTableToFsResult } from '@platforma-sdk/model';
2
+ import { PTableHandle, PTableColumnSpec, PFrameSpecDriver, PlDataTableColumnsMeta, WritePTableToFsResult } from '@platforma-sdk/model';
3
3
  import { Nil } from '@milaboratories/helpers';
4
4
  /** Options for the native table export. */
5
5
  export interface ExportOptions {
6
6
  tableHandle: PTableHandle;
7
7
  defaultFileName?: string;
8
+ /**
9
+ * Sidecar display metadata for the visible table. Supplies the disambiguated
10
+ * header labels the UI shows — the ones the spec's intrinsic `pl7.app/label`
11
+ * may not carry — so the export reproduces exactly what the user sees.
12
+ */
13
+ columnsMeta?: PlDataTableColumnsMeta;
8
14
  }
9
15
  /**
10
16
  * Table export via the platforma desktop runtime. Prompts for a save
@@ -28,10 +34,15 @@ export declare function exportCsv(gridApi: GridApi, nativeOptions: ExportOptions
28
34
  */
29
35
  export declare function isCsvExportAvailable(): boolean;
30
36
  /**
31
- * Collect unified column indices for visible (non-hidden) columns from the
32
- * ag-grid column defs, remapped onto the provided PTable spec array so the
33
- * indices match the current table handle (ColDef.field indices may be stale
37
+ * Collect `[unified index, header name]` pairs for visible (non-hidden) columns
38
+ * from the ag-grid column defs, remapped onto the provided PTable spec array so
39
+ * the indices match the current table handle (ColDef.field indices may be stale
34
40
  * or diverge from the spec order).
41
+ *
42
+ * The header name is the disambiguated label the UI shows — sidecar override
43
+ * (`columnsMeta`) wins over the spec's intrinsic `pl7.app/label`, falling back
44
+ * to the spec name — so the export reproduces exactly the visible headers and
45
+ * avoids the duplicate-label collisions that break the native export path.
35
46
  */
36
- export declare function collectVisibleColumnIndices(gridApi: GridApi, specs: PTableColumnSpec[], pframeSpec: PFrameSpecDriver): Nil | number[];
47
+ export declare function collectVisibleColumns(gridApi: GridApi, specs: PTableColumnSpec[], pframeSpec: PFrameSpecDriver, columnsMeta: PlDataTableColumnsMeta | undefined): Nil | [number, string][];
37
48
  //# sourceMappingURL=export-csv.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"export-csv.d.ts","sourceRoot":"","sources":["../../../src/components/PlAgCsvExporter/export-csv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,KAAK,EAEV,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAI9C,2CAA2C;AAC3C,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,YAAY,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAkCD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,SAAS,GAAG,qBAAqB,CAAC,CA0D5C;AAUD;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAO9C;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,gBAAgB,EAAE,EACzB,UAAU,EAAE,gBAAgB,GAC3B,GAAG,GAAG,MAAM,EAAE,CAkBhB"}
1
+ {"version":3,"file":"export-csv.d.ts","sourceRoot":"","sources":["../../../src/components/PlAgCsvExporter/export-csv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,KAAK,EAEV,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAK9C,2CAA2C;AAC3C,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,YAAY,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,WAAW,CAAC,EAAE,sBAAsB,CAAC;CACtC;AAkCD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,SAAS,GAAG,qBAAqB,CAAC,CAqE5C;AAUD;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAO9C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,gBAAgB,EAAE,EACzB,UAAU,EAAE,gBAAgB,EAC5B,WAAW,EAAE,sBAAsB,GAAG,SAAS,GAC9C,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAwB1B"}