@platforma-sdk/ui-vue 1.84.10 → 1.84.14

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 (185) hide show
  1. package/.turbo/turbo-build.log +68 -68
  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 +8 -0
  6. package/dist/components/BlockLayout.js.map +1 -1
  7. package/dist/components/BlockLayout.style.js.map +1 -1
  8. package/dist/components/BlockLayout.vue.d.ts.map +1 -1
  9. package/dist/components/BlockLayout.vue2.js +5 -1
  10. package/dist/components/BlockLayout.vue2.js.map +1 -1
  11. package/dist/components/BlockLoader.js.map +1 -1
  12. package/dist/components/BlockLoader.vue.d.ts.map +1 -1
  13. package/dist/components/BlockLoader.vue2.js +2 -0
  14. package/dist/components/BlockLoader.vue2.js.map +1 -1
  15. package/dist/components/LoaderPage.js +4 -1
  16. package/dist/components/LoaderPage.js.map +1 -1
  17. package/dist/components/LoaderPage.vue.d.ts.map +1 -1
  18. package/dist/components/NotFound.js.map +1 -1
  19. package/dist/components/NotFound.vue.d.ts.map +1 -1
  20. package/dist/components/NotFound.vue2.js +11 -5
  21. package/dist/components/NotFound.vue2.js.map +1 -1
  22. package/dist/components/PlAdvancedFilter/FilterEditor.js.map +1 -1
  23. package/dist/components/PlAdvancedFilter/FilterEditor.style.js.map +1 -1
  24. package/dist/components/PlAdvancedFilter/FilterEditor.vue.d.ts.map +1 -1
  25. package/dist/components/PlAdvancedFilter/FilterEditor.vue2.js +26 -2
  26. package/dist/components/PlAdvancedFilter/FilterEditor.vue2.js.map +1 -1
  27. package/dist/components/PlAdvancedFilter/OperandButton.js.map +1 -1
  28. package/dist/components/PlAdvancedFilter/OperandButton.style.js.map +1 -1
  29. package/dist/components/PlAdvancedFilter/OperandButton.vue.d.ts.map +1 -1
  30. package/dist/components/PlAdvancedFilter/OperandButton.vue2.js +2 -1
  31. package/dist/components/PlAdvancedFilter/OperandButton.vue2.js.map +1 -1
  32. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.js.map +1 -1
  33. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.style.js.map +1 -1
  34. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue.d.ts.map +1 -1
  35. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js +70 -61
  36. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js.map +1 -1
  37. package/dist/components/PlAgCellFile/PlAgCellFile.js.map +1 -1
  38. package/dist/components/PlAgCellFile/PlAgCellFile.vue.d.ts.map +1 -1
  39. package/dist/components/PlAgCellFile/PlAgCellFile.vue2.js +5 -1
  40. package/dist/components/PlAgCellFile/PlAgCellFile.vue2.js.map +1 -1
  41. package/dist/components/PlAgCellProgress/PlAgCellProgress.js.map +1 -1
  42. package/dist/components/PlAgCellProgress/PlAgCellProgress.vue.d.ts.map +1 -1
  43. package/dist/components/PlAgCellProgress/PlAgCellProgress.vue2.js +6 -6
  44. package/dist/components/PlAgCellProgress/PlAgCellProgress.vue2.js.map +1 -1
  45. package/dist/components/PlAgCellStatusTag/PlAgCellStatusTag.js.map +1 -1
  46. package/dist/components/PlAgCellStatusTag/PlAgCellStatusTag.vue.d.ts.map +1 -1
  47. package/dist/components/PlAgCellStatusTag/PlAgCellStatusTag.vue2.js +8 -2
  48. package/dist/components/PlAgCellStatusTag/PlAgCellStatusTag.vue2.js.map +1 -1
  49. package/dist/components/PlAgChartHistogramCell/PlAgChartHistogramCell.js.map +1 -1
  50. package/dist/components/PlAgChartHistogramCell/PlAgChartHistogramCell.vue.d.ts.map +1 -1
  51. package/dist/components/PlAgChartHistogramCell/PlAgChartHistogramCell.vue2.js +4 -1
  52. package/dist/components/PlAgChartHistogramCell/PlAgChartHistogramCell.vue2.js.map +1 -1
  53. package/dist/components/PlAgChartStackedBarCell/PlAgChartStackedBarCell.js.map +1 -1
  54. package/dist/components/PlAgChartStackedBarCell/PlAgChartStackedBarCell.vue.d.ts.map +1 -1
  55. package/dist/components/PlAgChartStackedBarCell/PlAgChartStackedBarCell.vue2.js +7 -2
  56. package/dist/components/PlAgChartStackedBarCell/PlAgChartStackedBarCell.vue2.js.map +1 -1
  57. package/dist/components/PlAgColumnHeader/PlAgColumnHeader.js.map +1 -1
  58. package/dist/components/PlAgColumnHeader/PlAgColumnHeader.vue.d.ts.map +1 -1
  59. package/dist/components/PlAgColumnHeader/PlAgColumnHeader.vue2.js +28 -20
  60. package/dist/components/PlAgColumnHeader/PlAgColumnHeader.vue2.js.map +1 -1
  61. package/dist/components/PlAgCsvExporter/PlAgCsvExporter.js.map +1 -1
  62. package/dist/components/PlAgCsvExporter/PlAgCsvExporter.vue.d.ts.map +1 -1
  63. package/dist/components/PlAgCsvExporter/PlAgCsvExporter.vue2.js +1 -0
  64. package/dist/components/PlAgCsvExporter/PlAgCsvExporter.vue2.js.map +1 -1
  65. package/dist/components/PlAgDataTable/PlAgDataTableSheets.js.map +1 -1
  66. package/dist/components/PlAgDataTable/PlAgDataTableSheets.style.js.map +1 -1
  67. package/dist/components/PlAgDataTable/PlAgDataTableSheets.vue.d.ts.map +1 -1
  68. package/dist/components/PlAgDataTable/PlAgDataTableSheets.vue2.js +2 -0
  69. package/dist/components/PlAgDataTable/PlAgDataTableSheets.vue2.js.map +1 -1
  70. package/dist/components/PlAgDataTable/PlAgDataTableV2.js.map +1 -1
  71. package/dist/components/PlAgDataTable/PlAgDataTableV2.style.js.map +1 -1
  72. package/dist/components/PlAgDataTable/PlAgDataTableV2.vue.d.ts.map +1 -1
  73. package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js +5 -1
  74. package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js.map +1 -1
  75. package/dist/components/PlAgDataTable/PlAgOverlayLoading.js.map +1 -1
  76. package/dist/components/PlAgDataTable/PlAgOverlayLoading.vue.d.ts.map +1 -1
  77. package/dist/components/PlAgDataTable/PlAgOverlayLoading.vue2.js +12 -2
  78. package/dist/components/PlAgDataTable/PlAgOverlayLoading.vue2.js.map +1 -1
  79. package/dist/components/PlAgDataTable/PlAgOverlayNoRows.js.map +1 -1
  80. package/dist/components/PlAgDataTable/PlAgOverlayNoRows.vue.d.ts.map +1 -1
  81. package/dist/components/PlAgDataTable/PlAgOverlayNoRows.vue2.js +7 -1
  82. package/dist/components/PlAgDataTable/PlAgOverlayNoRows.vue2.js.map +1 -1
  83. package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.js.map +1 -1
  84. package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.style.js.map +1 -1
  85. package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue.d.ts.map +1 -1
  86. package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue2.js +35 -27
  87. package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue2.js.map +1 -1
  88. package/dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.js.map +1 -1
  89. package/dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.vue.d.ts.map +1 -1
  90. package/dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.vue2.js +12 -7
  91. package/dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.vue2.js.map +1 -1
  92. package/dist/components/PlAgRowNumHeader.js.map +1 -1
  93. package/dist/components/PlAgRowNumHeader.vue.d.ts.map +1 -1
  94. package/dist/components/PlAgRowNumHeader.vue2.js +14 -7
  95. package/dist/components/PlAgRowNumHeader.vue2.js.map +1 -1
  96. package/dist/components/PlAgTextAndButtonCell/PlAgTextAndButtonCell.js.map +1 -1
  97. package/dist/components/PlAgTextAndButtonCell/PlAgTextAndButtonCell.vue.d.ts.map +1 -1
  98. package/dist/components/PlAgTextAndButtonCell/PlAgTextAndButtonCell.vue2.js +8 -1
  99. package/dist/components/PlAgTextAndButtonCell/PlAgTextAndButtonCell.vue2.js.map +1 -1
  100. package/dist/components/PlAnnotations/components/AnnotationsSidebar.js.map +1 -1
  101. package/dist/components/PlAnnotations/components/AnnotationsSidebar.style.js.map +1 -1
  102. package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue.d.ts.map +1 -1
  103. package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue2.js +14 -3
  104. package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue2.js.map +1 -1
  105. package/dist/components/PlAnnotations/components/FilterSidebar.js.map +1 -1
  106. package/dist/components/PlAnnotations/components/FilterSidebar.style.js.map +1 -1
  107. package/dist/components/PlAnnotations/components/FilterSidebar.vue.d.ts.map +1 -1
  108. package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js +11 -2
  109. package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js.map +1 -1
  110. package/dist/components/PlAnnotations/components/PlAnnotations.js.map +1 -1
  111. package/dist/components/PlAnnotations/components/PlAnnotations.style.js.map +1 -1
  112. package/dist/components/PlAnnotations/components/PlAnnotations.vue.d.ts.map +1 -1
  113. package/dist/components/PlAnnotations/components/PlAnnotations.vue2.js +1 -1
  114. package/dist/components/PlAnnotations/components/PlAnnotations.vue2.js.map +1 -1
  115. package/dist/components/PlAnnotations/components/PlAnnotationsModal.js.map +1 -1
  116. package/dist/components/PlAnnotations/components/PlAnnotationsModal.style.js.map +1 -1
  117. package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue.d.ts.map +1 -1
  118. package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue2.js +1 -0
  119. package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue2.js.map +1 -1
  120. package/dist/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.js.map +1 -1
  121. package/dist/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.vue.d.ts.map +1 -1
  122. package/dist/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.vue2.js +16 -2
  123. package/dist/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.vue2.js.map +1 -1
  124. package/dist/components/PlBtnExportArchive/Item.js.map +1 -1
  125. package/dist/components/PlBtnExportArchive/Item.style.js.map +1 -1
  126. package/dist/components/PlBtnExportArchive/Item.vue.d.ts.map +1 -1
  127. package/dist/components/PlBtnExportArchive/Item.vue2.js +12 -2
  128. package/dist/components/PlBtnExportArchive/Item.vue2.js.map +1 -1
  129. package/dist/components/PlBtnExportArchive/PlBtnExportArchive.js.map +1 -1
  130. package/dist/components/PlBtnExportArchive/PlBtnExportArchive.style.js.map +1 -1
  131. package/dist/components/PlBtnExportArchive/PlBtnExportArchive.vue.d.ts.map +1 -1
  132. package/dist/components/PlBtnExportArchive/PlBtnExportArchive.vue2.js +7 -1
  133. package/dist/components/PlBtnExportArchive/PlBtnExportArchive.vue2.js.map +1 -1
  134. package/dist/components/PlBtnExportArchive/Summary.js.map +1 -1
  135. package/dist/components/PlBtnExportArchive/Summary.style.js.map +1 -1
  136. package/dist/components/PlBtnExportArchive/Summary.vue.d.ts.map +1 -1
  137. package/dist/components/PlBtnExportArchive/Summary.vue2.js +11 -2
  138. package/dist/components/PlBtnExportArchive/Summary.vue2.js.map +1 -1
  139. package/dist/components/PlDatasetSelector/PlDatasetSelector.js.map +1 -1
  140. package/dist/components/PlDatasetSelector/PlDatasetSelector.vue.d.ts.map +1 -1
  141. package/dist/components/PlDatasetSelector/PlDatasetSelector.vue2.js +1 -0
  142. package/dist/components/PlDatasetSelector/PlDatasetSelector.vue2.js.map +1 -1
  143. package/dist/components/PlTableFastSearch/PlTableFastSearch.js.map +1 -1
  144. package/dist/components/PlTableFastSearch/PlTableFastSearch.vue.d.ts.map +1 -1
  145. package/dist/components/PlTableFastSearch/PlTableFastSearch.vue2.js +1 -0
  146. package/dist/components/PlTableFastSearch/PlTableFastSearch.vue2.js.map +1 -1
  147. package/dist/components/PlTableFilters/PlTableFiltersV2.js.map +1 -1
  148. package/dist/components/PlTableFilters/PlTableFiltersV2.style.js.map +1 -1
  149. package/dist/components/PlTableFilters/PlTableFiltersV2.vue.d.ts.map +1 -1
  150. package/dist/components/PlTableFilters/PlTableFiltersV2.vue2.js +12 -2
  151. package/dist/components/PlTableFilters/PlTableFiltersV2.vue2.js.map +1 -1
  152. package/package.json +5 -5
  153. package/src/components/BlockLayout.vue +4 -2
  154. package/src/components/BlockLoader.vue +2 -1
  155. package/src/components/LoaderPage.vue +1 -1
  156. package/src/components/NotFound.vue +7 -3
  157. package/src/components/PlAdvancedFilter/FilterEditor.vue +36 -6
  158. package/src/components/PlAdvancedFilter/OperandButton.vue +2 -1
  159. package/src/components/PlAdvancedFilter/PlAdvancedFilter.vue +20 -4
  160. package/src/components/PlAgCellFile/PlAgCellFile.vue +2 -1
  161. package/src/components/PlAgCellProgress/PlAgCellProgress.vue +1 -1
  162. package/src/components/PlAgCellStatusTag/PlAgCellStatusTag.vue +2 -2
  163. package/src/components/PlAgChartHistogramCell/PlAgChartHistogramCell.vue +13 -3
  164. package/src/components/PlAgChartStackedBarCell/PlAgChartStackedBarCell.vue +13 -3
  165. package/src/components/PlAgColumnHeader/PlAgColumnHeader.vue +24 -6
  166. package/src/components/PlAgCsvExporter/PlAgCsvExporter.vue +6 -1
  167. package/src/components/PlAgDataTable/PlAgDataTableSheets.vue +6 -1
  168. package/src/components/PlAgDataTable/PlAgDataTableV2.vue +2 -1
  169. package/src/components/PlAgDataTable/PlAgOverlayLoading.vue +10 -3
  170. package/src/components/PlAgDataTable/PlAgOverlayNoRows.vue +4 -2
  171. package/src/components/PlAgGridColumnManager/PlAgGridColumnManager.vue +18 -5
  172. package/src/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.vue +5 -1
  173. package/src/components/PlAgRowNumHeader.vue +3 -1
  174. package/src/components/PlAgTextAndButtonCell/PlAgTextAndButtonCell.vue +3 -2
  175. package/src/components/PlAnnotations/components/AnnotationsSidebar.vue +13 -4
  176. package/src/components/PlAnnotations/components/FilterSidebar.vue +11 -3
  177. package/src/components/PlAnnotations/components/PlAnnotations.vue +1 -1
  178. package/src/components/PlAnnotations/components/PlAnnotationsModal.vue +1 -0
  179. package/src/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.vue +34 -7
  180. package/src/components/PlBtnExportArchive/Item.vue +22 -6
  181. package/src/components/PlBtnExportArchive/PlBtnExportArchive.vue +18 -3
  182. package/src/components/PlBtnExportArchive/Summary.vue +15 -5
  183. package/src/components/PlDatasetSelector/PlDatasetSelector.vue +1 -0
  184. package/src/components/PlTableFastSearch/PlTableFastSearch.vue +6 -1
  185. package/src/components/PlTableFilters/PlTableFiltersV2.vue +14 -4
@@ -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 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
+ {"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 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 data-testid=\"pl-advanced-filter\">\n <PlElementList\n v-model:items=\"rootFilters\"\n data-testid=\"pl-advanced-filter-groups\"\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 data-testid=\"pl-advanced-filter-group\"\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 data-testid=\"pl-advanced-filter-filter-out\"\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\n v-if=\"props.enableDnd\"\n data-testid=\"pl-advanced-filter-dropzone\"\n :class=\"$style.dropzone\"\n >\n <div>Drop dimensions here</div>\n </div>\n <PlBtnSecondary\n v-else-if=\"!props.isCompletedGroup(item, index)\"\n data-testid=\"pl-advanced-filter-add-filter\"\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 data-testid=\"pl-advanced-filter-group-operands\"\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 data-testid=\"pl-advanced-filter-new-group\"\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\" data-testid=\"pl-advanced-filter-dropzone\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <slot v-else name=\"add-group-buttons\">\n <PlBtnSecondary\n data-testid=\"pl-advanced-filter-add-group\"\n icon=\"add\"\n @click=\"addGroup(firstColumnId)\"\n >\n Add filter\n </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 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
+ {"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 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 data-testid=\"pl-advanced-filter\">\n <PlElementList\n v-model:items=\"rootFilters\"\n data-testid=\"pl-advanced-filter-groups\"\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 data-testid=\"pl-advanced-filter-group\"\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 data-testid=\"pl-advanced-filter-filter-out\"\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\n v-if=\"props.enableDnd\"\n data-testid=\"pl-advanced-filter-dropzone\"\n :class=\"$style.dropzone\"\n >\n <div>Drop dimensions here</div>\n </div>\n <PlBtnSecondary\n v-else-if=\"!props.isCompletedGroup(item, index)\"\n data-testid=\"pl-advanced-filter-add-filter\"\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 data-testid=\"pl-advanced-filter-group-operands\"\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 data-testid=\"pl-advanced-filter-new-group\"\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\" data-testid=\"pl-advanced-filter-dropzone\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <slot v-else name=\"add-group-buttons\">\n <PlBtnSecondary\n data-testid=\"pl-advanced-filter-add-group\"\n icon=\"add\"\n @click=\"addGroup(firstColumnId)\"\n >\n Add filter\n </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":"AAqYA,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;AAGjB,QAAA,MAAM,YAAY,GAAK,CAAC,SAAS,UAAU,EAC1C,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,gBAAgB,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAClE;WAilBO,OAAO,KAAK,EAAE,WAAW,GAAG,mBAAmB;iBA/kB1C,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;MAqjBd,GAAG,CAAC,OAAO,UAAU,SAAS;QAAE,oBAAoB,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,CAAC,GAAG,EAAE,CAAC;YAC1I,CAAC,OAAO,EAAE,EAAE,KAAK,IAAI;WACtB,GAAG;;wBAVS,CAAC,KAAK;;;SAAgB,KAAK,GAAG;;wBAC9B,CAAC,KAAK;;;SAAiB,KAAK,GAAG;;8BACzB,CAAC,KAAK,IAAiB,KAAK,GAAG;;UAUlD,EAAE;EAEL,KACQ,OAAO,KAAK,EAAE,KAAK,GAAG;IAAE,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAA;CAAI,CAAC;wBACpE,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,CAAC,GAAG,EAAE,CAAC"}
1
+ {"version":3,"file":"PlAdvancedFilter.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"names":[],"mappings":"AAqZA,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;AAGjB,QAAA,MAAM,YAAY,GAAK,CAAC,SAAS,UAAU,EAC1C,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,gBAAgB,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAClE;WAimBO,OAAO,KAAK,EAAE,WAAW,GAAG,mBAAmB;iBA/lB1C,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;MAqkBd,GAAG,CAAC,OAAO,UAAU,SAAS;QAAE,oBAAoB,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,CAAC,GAAG,EAAE,CAAC;YAC1I,CAAC,OAAO,EAAE,EAAE,KAAK,IAAI;WACtB,GAAG;;wBAVS,CAAC,KAAK;;;SAAgB,KAAK,GAAG;;wBAC9B,CAAC,KAAK;;;SAAiB,KAAK,GAAG;;8BACzB,CAAC,KAAK,IAAiB,KAAK,GAAG;;UAUlD,EAAE;EAEL,KACQ,OAAO,KAAK,EAAE,KAAK,GAAG;IAAE,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAA;CAAI,CAAC;wBACpE,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,CAAC,GAAG,EAAE,CAAC"}
@@ -6,7 +6,7 @@ import { produce as c } from "immer";
6
6
  import { Fragment as l, computed as u, createBlock as d, createCommentVNode as f, createElementBlock as p, createElementVNode as m, createTextVNode as h, createVNode as g, defineComponent as _, normalizeClass as v, openBlock as y, renderList as b, renderSlot as x, unref as S, withCtx as C } from "vue";
7
7
  import { PlBtnSecondary as w, PlCheckbox as T, PlElementList as E } from "@milaboratories/uikit";
8
8
  //#region src/components/PlAdvancedFilter/PlAdvancedFilter.vue?vue&type=script&setup=true&lang.ts
9
- var D = ["onDrop"], O = /* @__PURE__ */ _({
9
+ var D = { "data-testid": "pl-advanced-filter" }, O = ["onDrop"], k = /* @__PURE__ */ _({
10
10
  __name: "PlAdvancedFilter",
11
11
  props: {
12
12
  filters: {},
@@ -44,25 +44,25 @@ var D = ["onDrop"], O = /* @__PURE__ */ _({
44
44
  getSuggestOptions: {}
45
45
  },
46
46
  setup(n) {
47
- let _ = n, O = (e) => {
47
+ let _ = n, k = (e) => {
48
48
  _.onUpdateFilters(c(_.filters, e));
49
- }, k = u(() => _.options[0]?.id), A = [{
49
+ }, A = u(() => _.options[0]?.id), j = [{
50
50
  id: -1,
51
51
  type: "and",
52
52
  filters: [],
53
53
  isExpanded: !0
54
- }], j = u({
54
+ }], M = u({
55
55
  get: () => _.filters.filters,
56
56
  set: (e) => _.onUpdateFilters({
57
57
  ..._.filters,
58
58
  filters: e
59
59
  })
60
60
  });
61
- function M() {
61
+ function N() {
62
62
  if (_.filters.type !== "or" && _.filters.type !== "and") throw Error("Invalid model structure, expected root to be \"or\" or \"and\" group");
63
63
  return _.filters.filters;
64
64
  }
65
- function N(e, t) {
65
+ function P(e, t) {
66
66
  let n = e.filters[t];
67
67
  if (n.type === "not") {
68
68
  if (n.filter.type !== "and" && n.filter.type !== "or") throw Error("Invalid group structure, expected \"and\" or \"or\" group inside \"not\"");
@@ -71,12 +71,12 @@ var D = ["onDrop"], O = /* @__PURE__ */ _({
71
71
  if (n.type !== "and" && n.type !== "or") throw Error("Invalid group structure, expected \"and\", \"or\" or \"not\" group");
72
72
  return n;
73
73
  }
74
- function P(e) {
74
+ function F(e) {
75
75
  return e.type === "not" ? e.filter : e;
76
76
  }
77
- function F(n, r) {
78
- O((i) => {
79
- N(i, n).filters.push({
77
+ function I(n, r) {
78
+ k((i) => {
79
+ P(i, n).filters.push({
80
80
  ...e[t],
81
81
  column: r,
82
82
  id: a(),
@@ -84,14 +84,14 @@ var D = ["onDrop"], O = /* @__PURE__ */ _({
84
84
  });
85
85
  });
86
86
  }
87
- function I(e, t) {
88
- O((n) => {
89
- let r = N(n, e);
87
+ function L(e, t) {
88
+ k((n) => {
89
+ let r = P(n, e);
90
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
- function L(e) {
94
- O((t) => {
93
+ function R(e) {
94
+ k((t) => {
95
95
  let n = t.filters[e];
96
96
  if (n.type === "not") {
97
97
  if (n.filter.type !== "and" && n.filter.type !== "or") throw Error("Invalid group structure, expected \"and\" or \"or\" group inside \"not\"");
@@ -111,68 +111,69 @@ var D = ["onDrop"], O = /* @__PURE__ */ _({
111
111
  }
112
112
  });
113
113
  }
114
- function R(e) {
115
- O((t) => {
114
+ function z(e) {
115
+ k((t) => {
116
116
  t.filters.push(i(e));
117
117
  });
118
118
  }
119
- function z(e, t, n) {
120
- O((r) => {
121
- N(r, e).filters[t] = n;
119
+ function B(e, t, n) {
120
+ k((r) => {
121
+ P(r, e).filters[t] = n;
122
122
  });
123
123
  }
124
- function B(e, t) {
124
+ function V(e, t) {
125
125
  let n = t.dataTransfer;
126
126
  if (n?.getData("text/plain")) {
127
127
  let t = n.getData("text/plain");
128
- o(t) && F(e, t);
128
+ o(t) && I(e, t);
129
129
  }
130
130
  }
131
- function V(e) {
131
+ function H(e) {
132
132
  let t = e.dataTransfer;
133
133
  if (t?.getData("text/plain")) {
134
134
  let e = t.getData("text/plain");
135
- o(e) && R(e);
135
+ o(e) && z(e);
136
136
  }
137
137
  }
138
- function H(e) {
138
+ function U(e) {
139
139
  e.preventDefault();
140
140
  }
141
- function U(e, t) {
142
- O((e) => {
141
+ function W(e, t) {
142
+ k((e) => {
143
143
  e.filters[t].isExpanded = !e.filters[t].isExpanded;
144
144
  });
145
145
  }
146
- function W(e, t) {
147
- O((e) => {
146
+ function G(e, t) {
147
+ k((e) => {
148
148
  e.filters[t].isSuppressed = !e.filters[t].isSuppressed;
149
149
  });
150
150
  }
151
- function G(e, t) {
152
- O((n) => {
153
- N(n, e).type = t;
151
+ function K(e, t) {
152
+ k((n) => {
153
+ P(n, e).type = t;
154
154
  });
155
155
  }
156
- function K(e) {
157
- O((t) => {
156
+ function q(e) {
157
+ k((t) => {
158
158
  t.type = e;
159
159
  });
160
160
  }
161
- function q(e) {
161
+ function J(e) {
162
162
  if (e.type === "and" || e.type === "or" || e.type === "not") throw Error("Invalid filter structure, expected leaf filter");
163
163
  return e;
164
164
  }
165
- return (e, t) => (y(), p("div", null, [g(S(E), {
166
- items: j.value,
167
- "onUpdate:items": t[0] ||= (e) => j.value = e,
165
+ return (e, t) => (y(), p("div", D, [g(S(E), {
166
+ items: M.value,
167
+ "onUpdate:items": t[0] ||= (e) => M.value = e,
168
+ "data-testid": "pl-advanced-filter-groups",
168
169
  "get-item-key": (e) => e.id,
169
170
  "item-class": e.$style.filterGroup,
170
171
  "item-class-content": e.$style.filterGroupContent,
171
172
  "item-class-title": e.$style.filterGroupTitle,
172
173
  "is-expanded": (e) => e.isExpanded === !0,
173
- "on-expand": U,
174
+ "on-expand": W,
174
175
  "is-toggled": (e) => e.isSuppressed === !0,
175
- "on-toggle": W,
176
+ "on-toggle": G,
176
177
  "is-pinned": (e, t) => _.isPinned?.(e, t) === !0,
177
178
  "is-pinnable": () => !1,
178
179
  "is-removable": (e, t) => _.isRemovable?.(e, t) === !0,
@@ -186,15 +187,17 @@ var D = ["onDrop"], O = /* @__PURE__ */ _({
186
187
  index: r
187
188
  }, () => [t[2] ||= h("Filter group", -1)])]),
188
189
  "item-content": C(({ item: r, index: i }) => [m("div", {
190
+ "data-testid": "pl-advanced-filter-group",
189
191
  class: v([e.$style.groupContent, { [e.$style.suppressedLabel]: r.isSuppressed }]),
190
192
  dropzone: "true",
191
- onDrop: (e) => B(i, e),
192
- onDragover: H
193
+ onDrop: (e) => V(i, e),
194
+ onDragover: U
193
195
  }, [
194
196
  g(S(T), {
195
197
  "model-value": r.type === "not",
198
+ "data-testid": "pl-advanced-filter-filter-out",
196
199
  class: v(e.$style.notCheckbox),
197
- "onUpdate:modelValue": (e) => L(i)
200
+ "onUpdate:modelValue": (e) => R(i)
198
201
  }, {
199
202
  default: C(() => [...t[3] ||= [h(" Filter Out ", -1)]]),
200
203
  _: 1
@@ -203,18 +206,18 @@ var D = ["onDrop"], O = /* @__PURE__ */ _({
203
206
  "class",
204
207
  "onUpdate:modelValue"
205
208
  ]),
206
- (y(!0), p(l, null, b(P(r).filters, (e, t) => (y(), d(s, {
209
+ (y(!0), p(l, null, b(F(r).filters, (e, t) => (y(), d(s, {
207
210
  key: t,
208
- filter: q(P(r).filters[t]),
209
- operand: P(r).type,
211
+ filter: J(F(r).filters[t]),
212
+ operand: F(r).type,
210
213
  "column-options": n.options,
211
214
  "supported-filters": _.supportedFilters,
212
215
  "get-suggest-options": _.getSuggestOptions,
213
216
  "enable-dnd": !!_.enableDnd,
214
- "is-last": t === P(r).filters.length - 1,
215
- onDelete: () => I(i, t),
216
- onUpdateFilter: (e) => z(i, t, e),
217
- onChangeOperand: (e) => G(i, e)
217
+ "is-last": t === F(r).filters.length - 1,
218
+ onDelete: () => L(i, t),
219
+ onUpdateFilter: (e) => B(i, t, e),
220
+ onChangeOperand: (e) => K(i, e)
218
221
  }, null, 8, [
219
222
  "filter",
220
223
  "operand",
@@ -229,22 +232,25 @@ var D = ["onDrop"], O = /* @__PURE__ */ _({
229
232
  ]))), 128)),
230
233
  _.enableDnd ? (y(), p("div", {
231
234
  key: 0,
235
+ "data-testid": "pl-advanced-filter-dropzone",
232
236
  class: v(e.$style.dropzone)
233
237
  }, [...t[4] ||= [m("div", null, "Drop dimensions here", -1)]], 2)) : _.isCompletedGroup(r, i) ? f("", !0) : (y(), d(S(w), {
234
238
  key: 1,
239
+ "data-testid": "pl-advanced-filter-add-filter",
235
240
  icon: "add",
236
- onClick: (e) => F(i, k.value)
241
+ onClick: (e) => I(i, A.value)
237
242
  }, {
238
243
  default: C(() => [...t[5] ||= [h(" Add filter ", -1)]]),
239
244
  _: 1
240
245
  }, 8, ["onClick"]))
241
- ], 42, D)]),
242
- "item-after": C(({ index: t }) => [_.enableAddGroupButton || t < M().length - 1 ? (y(), d(r, {
246
+ ], 42, O)]),
247
+ "item-after": C(({ index: t }) => [_.enableAddGroupButton || t < N().length - 1 ? (y(), d(r, {
243
248
  key: 0,
249
+ "data-testid": "pl-advanced-filter-group-operands",
244
250
  class: v(e.$style.buttonWrapper),
245
251
  active: _.filters.type,
246
- disabled: t === M().length - 1,
247
- "on-select": K
252
+ disabled: t === N().length - 1,
253
+ "on-select": q
248
254
  }, null, 8, [
249
255
  "class",
250
256
  "active",
@@ -265,7 +271,8 @@ var D = ["onDrop"], O = /* @__PURE__ */ _({
265
271
  "disable-toggling"
266
272
  ]), _.enableAddGroupButton ? (y(), d(S(E), {
267
273
  key: 0,
268
- items: A,
274
+ "data-testid": "pl-advanced-filter-new-group",
275
+ items: j,
269
276
  "get-item-key": (e) => e.id,
270
277
  "item-class": e.$style.filterGroup,
271
278
  "item-class-content": e.$style.filterGroupContent,
@@ -276,19 +283,21 @@ var D = ["onDrop"], O = /* @__PURE__ */ _({
276
283
  disableToggling: !0,
277
284
  disablePinning: !0,
278
285
  dropzone: "true",
279
- onDrop: V,
280
- onDragover: H
286
+ onDrop: H,
287
+ onDragover: U
281
288
  }, {
282
289
  "item-title": C(({ item: n, index: r }) => [x(e.$slots, "group-title", {
283
290
  item: n,
284
- index: r + M().length
291
+ index: r + N().length
285
292
  }, () => [t[6] ||= h("Filter group", -1)])]),
286
293
  "item-content": C(() => [n.enableDnd ? (y(), p("div", {
287
294
  key: 0,
295
+ "data-testid": "pl-advanced-filter-dropzone",
288
296
  class: v(e.$style.dropzone)
289
297
  }, [...t[7] ||= [m("div", null, "Drop dimensions here", -1)]], 2)) : x(e.$slots, "add-group-buttons", { key: 1 }, () => [g(S(w), {
298
+ "data-testid": "pl-advanced-filter-add-group",
290
299
  icon: "add",
291
- onClick: t[1] ||= (e) => R(k.value)
300
+ onClick: t[1] ||= (e) => z(A.value)
292
301
  }, {
293
302
  default: C(() => [...t[8] ||= [h(" Add filter ", -1)]]),
294
303
  _: 1
@@ -303,6 +312,6 @@ var D = ["onDrop"], O = /* @__PURE__ */ _({
303
312
  }
304
313
  });
305
314
  //#endregion
306
- export { O as default };
315
+ export { k as default };
307
316
 
308
317
  //# sourceMappingURL=PlAdvancedFilter.vue2.js.map
@@ -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 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
+ {"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 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 data-testid=\"pl-advanced-filter\">\n <PlElementList\n v-model:items=\"rootFilters\"\n data-testid=\"pl-advanced-filter-groups\"\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 data-testid=\"pl-advanced-filter-group\"\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 data-testid=\"pl-advanced-filter-filter-out\"\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\n v-if=\"props.enableDnd\"\n data-testid=\"pl-advanced-filter-dropzone\"\n :class=\"$style.dropzone\"\n >\n <div>Drop dimensions here</div>\n </div>\n <PlBtnSecondary\n v-else-if=\"!props.isCompletedGroup(item, index)\"\n data-testid=\"pl-advanced-filter-add-filter\"\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 data-testid=\"pl-advanced-filter-group-operands\"\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 data-testid=\"pl-advanced-filter-new-group\"\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\" data-testid=\"pl-advanced-filter-dropzone\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <slot v-else name=\"add-group-buttons\">\n <PlBtnSecondary\n data-testid=\"pl-advanced-filter-add-group\"\n icon=\"add\"\n @click=\"addGroup(firstColumnId)\"\n >\n Add filter\n </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":"PlAgCellFile.js","names":[],"sources":["../../../src/components/PlAgCellFile/PlAgCellFile.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { PlFileInput } from \"@milaboratories/uikit\";\nimport type { ICellRendererParams } from \"ag-grid-enterprise\";\nimport type { ImportFileHandle, ImportProgress } from \"@platforma-sdk/model\";\nimport { computed } from \"vue\";\n\nconst props = defineProps<{\n // this component is intended to be used in ag-grid, params are the main object\n // to communicate with the corresponding cell data\n params: ICellRendererParams<unknown, ImportFileHandle> & {\n extensions?: string[];\n progress?: ImportProgress;\n /**\n * The resolveProgress function is an optional input parameter for the component\n * that allows tracking the file upload progress in real-time.\n * By passing resolveProgress, you can ensure that the component\n * displays accurate progress values for each file as they upload.\n * How to use it in AgGrid\n * cellRendererParams: {\n * resolveProgress: (fileHandle: ImportFileHandle | undefined) => {\n * const progresses = app.progresses;\n * if (!fileHandle) return undefined;\n * else return progresses[fileHandle];\n * }\n * }\n */\n resolveProgress?: (v: ImportFileHandle | undefined) => ImportProgress | undefined;\n };\n}>();\n\nconst extensions = computed(() => props.params.extensions);\n\n// extracting cell value and casting it to the type we expect\nconst handle = computed(() => props.params.value as ImportFileHandle | undefined);\n\n/**\n * When value changes in the file input this method forward the value to the ag-grid,\n * which in tern forwards in to the valueSetter in corresponding column.\n * */\nfunction onHandleUpdate(newHandle: ImportFileHandle | undefined) {\n props.params.setValue!(newHandle);\n}\n\nconst currentProgress = computed(() => {\n return props.params.resolveProgress ? props.params.resolveProgress(handle.value) : undefined;\n});\n</script>\n\n<template>\n <div style=\"height: 100%\">\n <PlFileInput\n show-filename-only\n clearable\n cell-style\n file-dialog-title=\"Select any file\"\n :placeholder=\"`Choose file ${extensions ? extensions[0] : ''}`\"\n :extensions=\"extensions\"\n :model-value=\"handle\"\n :progress=\"currentProgress\"\n @update:model-value=\"onHandleUpdate\"\n />\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"PlAgCellFile.js","names":[],"sources":["../../../src/components/PlAgCellFile/PlAgCellFile.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { PlFileInput } from \"@milaboratories/uikit\";\nimport type { ICellRendererParams } from \"ag-grid-enterprise\";\nimport type { ImportFileHandle, ImportProgress } from \"@platforma-sdk/model\";\nimport { computed } from \"vue\";\n\nconst props = defineProps<{\n // this component is intended to be used in ag-grid, params are the main object\n // to communicate with the corresponding cell data\n params: ICellRendererParams<unknown, ImportFileHandle> & {\n extensions?: string[];\n progress?: ImportProgress;\n /**\n * The resolveProgress function is an optional input parameter for the component\n * that allows tracking the file upload progress in real-time.\n * By passing resolveProgress, you can ensure that the component\n * displays accurate progress values for each file as they upload.\n * How to use it in AgGrid\n * cellRendererParams: {\n * resolveProgress: (fileHandle: ImportFileHandle | undefined) => {\n * const progresses = app.progresses;\n * if (!fileHandle) return undefined;\n * else return progresses[fileHandle];\n * }\n * }\n */\n resolveProgress?: (v: ImportFileHandle | undefined) => ImportProgress | undefined;\n };\n}>();\n\nconst extensions = computed(() => props.params.extensions);\n\n// extracting cell value and casting it to the type we expect\nconst handle = computed(() => props.params.value as ImportFileHandle | undefined);\n\n/**\n * When value changes in the file input this method forward the value to the ag-grid,\n * which in tern forwards in to the valueSetter in corresponding column.\n * */\nfunction onHandleUpdate(newHandle: ImportFileHandle | undefined) {\n props.params.setValue!(newHandle);\n}\n\nconst currentProgress = computed(() => {\n return props.params.resolveProgress ? props.params.resolveProgress(handle.value) : undefined;\n});\n</script>\n\n<template>\n <div data-testid=\"pl-ag-cell-file\" style=\"height: 100%\">\n <PlFileInput\n data-testid=\"pl-ag-cell-file-input\"\n show-filename-only\n clearable\n cell-style\n file-dialog-title=\"Select any file\"\n :placeholder=\"`Choose file ${extensions ? extensions[0] : ''}`\"\n :extensions=\"extensions\"\n :model-value=\"handle\"\n :progress=\"currentProgress\"\n @update:model-value=\"onHandleUpdate\"\n />\n </div>\n</template>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"PlAgCellFile.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlAgCellFile/PlAgCellFile.vue"],"names":[],"mappings":"AAmEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG7E,KAAK,WAAW,GAAG;IAGjB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,CAAC,GAAG;QACvD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,QAAQ,CAAC,EAAE,cAAc,CAAC;QAC1B;;;;;;;;;;;;;WAaG;QACH,eAAe,CAAC,EAAE,CAAC,CAAC,EAAE,gBAAgB,GAAG,SAAS,KAAK,cAAc,GAAG,SAAS,CAAC;KACnF,CAAC;CACH,CAAC;AAiFF,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
1
+ {"version":3,"file":"PlAgCellFile.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlAgCellFile/PlAgCellFile.vue"],"names":[],"mappings":"AAoEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG7E,KAAK,WAAW,GAAG;IAGjB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,CAAC,GAAG;QACvD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,QAAQ,CAAC,EAAE,cAAc,CAAC;QAC1B;;;;;;;;;;;;;WAaG;QACH,eAAe,CAAC,EAAE,CAAC,CAAC,EAAE,gBAAgB,GAAG,SAAS,KAAK,cAAc,GAAG,SAAS,CAAC;KACnF,CAAC;CACH,CAAC;AAoFF,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -1,7 +1,10 @@
1
1
  import { computed as e, createElementBlock as t, createVNode as n, defineComponent as r, openBlock as i, unref as a } from "vue";
2
2
  import { PlFileInput as o } from "@milaboratories/uikit";
3
3
  //#region src/components/PlAgCellFile/PlAgCellFile.vue?vue&type=script&setup=true&lang.ts
4
- var s = { style: { height: "100%" } }, c = /* @__PURE__ */ r({
4
+ var s = {
5
+ "data-testid": "pl-ag-cell-file",
6
+ style: { height: "100%" }
7
+ }, c = /* @__PURE__ */ r({
5
8
  __name: "PlAgCellFile",
6
9
  props: { params: {} },
7
10
  setup(r) {
@@ -11,6 +14,7 @@ var s = { style: { height: "100%" } }, c = /* @__PURE__ */ r({
11
14
  }
12
15
  let f = e(() => c.params.resolveProgress ? c.params.resolveProgress(u.value) : void 0);
13
16
  return (e, r) => (i(), t("div", s, [n(a(o), {
17
+ "data-testid": "pl-ag-cell-file-input",
14
18
  "show-filename-only": "",
15
19
  clearable: "",
16
20
  "cell-style": "",
@@ -1 +1 @@
1
- {"version":3,"file":"PlAgCellFile.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/PlAgCellFile/PlAgCellFile.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { PlFileInput } from \"@milaboratories/uikit\";\nimport type { ICellRendererParams } from \"ag-grid-enterprise\";\nimport type { ImportFileHandle, ImportProgress } from \"@platforma-sdk/model\";\nimport { computed } from \"vue\";\n\nconst props = defineProps<{\n // this component is intended to be used in ag-grid, params are the main object\n // to communicate with the corresponding cell data\n params: ICellRendererParams<unknown, ImportFileHandle> & {\n extensions?: string[];\n progress?: ImportProgress;\n /**\n * The resolveProgress function is an optional input parameter for the component\n * that allows tracking the file upload progress in real-time.\n * By passing resolveProgress, you can ensure that the component\n * displays accurate progress values for each file as they upload.\n * How to use it in AgGrid\n * cellRendererParams: {\n * resolveProgress: (fileHandle: ImportFileHandle | undefined) => {\n * const progresses = app.progresses;\n * if (!fileHandle) return undefined;\n * else return progresses[fileHandle];\n * }\n * }\n */\n resolveProgress?: (v: ImportFileHandle | undefined) => ImportProgress | undefined;\n };\n}>();\n\nconst extensions = computed(() => props.params.extensions);\n\n// extracting cell value and casting it to the type we expect\nconst handle = computed(() => props.params.value as ImportFileHandle | undefined);\n\n/**\n * When value changes in the file input this method forward the value to the ag-grid,\n * which in tern forwards in to the valueSetter in corresponding column.\n * */\nfunction onHandleUpdate(newHandle: ImportFileHandle | undefined) {\n props.params.setValue!(newHandle);\n}\n\nconst currentProgress = computed(() => {\n return props.params.resolveProgress ? props.params.resolveProgress(handle.value) : undefined;\n});\n</script>\n\n<template>\n <div style=\"height: 100%\">\n <PlFileInput\n show-filename-only\n clearable\n cell-style\n file-dialog-title=\"Select any file\"\n :placeholder=\"`Choose file ${extensions ? extensions[0] : ''}`\"\n :extensions=\"extensions\"\n :model-value=\"handle\"\n :progress=\"currentProgress\"\n @update:model-value=\"onHandleUpdate\"\n />\n </div>\n</template>\n"],"mappings":";;;;;;;EAMA,IAAM,IAAQ,GAwBR,IAAa,QAAe,EAAM,OAAO,WAAW,EAGpD,IAAS,QAAe,EAAM,OAAO,MAAsC;EAMjF,SAAS,EAAe,GAAyC;AAC/D,KAAM,OAAO,SAAU,EAAU;;EAGnC,IAAM,IAAkB,QACf,EAAM,OAAO,kBAAkB,EAAM,OAAO,gBAAgB,EAAO,MAAM,GAAG,KAAA,EACnF;yBAIA,EAYM,OAZN,GAYM,CAXJ,EAUE,EAAA,EAAA,EAAA;GATA,sBAAA;GACA,WAAA;GACA,cAAA;GACA,qBAAkB;GACjB,aAAW,eAAiB,EAAA,QAAa,EAAA,MAAU,KAAA;GACnD,YAAY,EAAA;GACZ,eAAa,EAAA;GACb,UAAU,EAAA;GACV,uBAAoB"}
1
+ {"version":3,"file":"PlAgCellFile.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/PlAgCellFile/PlAgCellFile.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { PlFileInput } from \"@milaboratories/uikit\";\nimport type { ICellRendererParams } from \"ag-grid-enterprise\";\nimport type { ImportFileHandle, ImportProgress } from \"@platforma-sdk/model\";\nimport { computed } from \"vue\";\n\nconst props = defineProps<{\n // this component is intended to be used in ag-grid, params are the main object\n // to communicate with the corresponding cell data\n params: ICellRendererParams<unknown, ImportFileHandle> & {\n extensions?: string[];\n progress?: ImportProgress;\n /**\n * The resolveProgress function is an optional input parameter for the component\n * that allows tracking the file upload progress in real-time.\n * By passing resolveProgress, you can ensure that the component\n * displays accurate progress values for each file as they upload.\n * How to use it in AgGrid\n * cellRendererParams: {\n * resolveProgress: (fileHandle: ImportFileHandle | undefined) => {\n * const progresses = app.progresses;\n * if (!fileHandle) return undefined;\n * else return progresses[fileHandle];\n * }\n * }\n */\n resolveProgress?: (v: ImportFileHandle | undefined) => ImportProgress | undefined;\n };\n}>();\n\nconst extensions = computed(() => props.params.extensions);\n\n// extracting cell value and casting it to the type we expect\nconst handle = computed(() => props.params.value as ImportFileHandle | undefined);\n\n/**\n * When value changes in the file input this method forward the value to the ag-grid,\n * which in tern forwards in to the valueSetter in corresponding column.\n * */\nfunction onHandleUpdate(newHandle: ImportFileHandle | undefined) {\n props.params.setValue!(newHandle);\n}\n\nconst currentProgress = computed(() => {\n return props.params.resolveProgress ? props.params.resolveProgress(handle.value) : undefined;\n});\n</script>\n\n<template>\n <div data-testid=\"pl-ag-cell-file\" style=\"height: 100%\">\n <PlFileInput\n data-testid=\"pl-ag-cell-file-input\"\n show-filename-only\n clearable\n cell-style\n file-dialog-title=\"Select any file\"\n :placeholder=\"`Choose file ${extensions ? extensions[0] : ''}`\"\n :extensions=\"extensions\"\n :model-value=\"handle\"\n :progress=\"currentProgress\"\n @update:model-value=\"onHandleUpdate\"\n />\n </div>\n</template>\n"],"mappings":";;;;;;;;;;EAMA,IAAM,IAAQ,GAwBR,IAAa,QAAe,EAAM,OAAO,WAAW,EAGpD,IAAS,QAAe,EAAM,OAAO,MAAsC;EAMjF,SAAS,EAAe,GAAyC;AAC/D,KAAM,OAAO,SAAU,EAAU;;EAGnC,IAAM,IAAkB,QACf,EAAM,OAAO,kBAAkB,EAAM,OAAO,gBAAgB,EAAO,MAAM,GAAG,KAAA,EACnF;yBAIA,EAaM,OAbN,GAaM,CAZJ,EAWE,EAAA,EAAA,EAAA;GAVA,eAAY;GACZ,sBAAA;GACA,WAAA;GACA,cAAA;GACA,qBAAkB;GACjB,aAAW,eAAiB,EAAA,QAAa,EAAA,MAAU,KAAA;GACnD,YAAY,EAAA;GACZ,eAAa,EAAA;GACb,UAAU,EAAA;GACV,uBAAoB"}