@platforma-sdk/ui-vue 1.80.10 → 1.80.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +10 -10
- package/.turbo/turbo-formatter$colon$check.log +2 -2
- package/.turbo/turbo-linter$colon$check.log +2 -2
- package/.turbo/turbo-types$colon$check.log +1 -1
- package/CHANGELOG.md +13 -0
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.js.map +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.style.js.map +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue.d.ts.map +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js.map +1 -1
- package/dist/components/PlAnnotations/components/PlAnnotations.vue2.js.map +1 -1
- package/package.json +6 -6
- package/src/components/PlAdvancedFilter/PlAdvancedFilter.vue +3 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
WARN Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
|
|
2
2
|
|
|
3
|
-
> @platforma-sdk/ui-vue@1.80.
|
|
3
|
+
> @platforma-sdk/ui-vue@1.80.13 build /home/runner/_work/platforma/platforma/sdk/ui-vue
|
|
4
4
|
> ts-builder build --target browser-lib
|
|
5
5
|
|
|
6
6
|
Building browser-lib project...
|
|
@@ -16,7 +16,7 @@ Building browser-lib project...
|
|
|
16
16
|
rendering chunks...
|
|
17
17
|
|
|
18
18
|
[vite:dts] Start generate declaration files...
|
|
19
|
-
[vite:dts] Declaration files built in
|
|
19
|
+
[vite:dts] Declaration files built in 5555ms.
|
|
20
20
|
|
|
21
21
|
computing gzip size...
|
|
22
22
|
dist/components/PlAnnotations/components/PlAnnotations.vue?vue&type=style&index=0&lang.css 0.04 kB │ gzip: 0.06 kB
|
|
@@ -123,7 +123,7 @@ dist/components/PlAnnotations/components/FilterSidebar.js
|
|
|
123
123
|
dist/components/PlAnnotations/components/PlAnnotations.js 0.35 kB │ gzip: 0.24 kB │ map: 3.11 kB
|
|
124
124
|
dist/components/PlAgDataTable/PlAgDataTableV2.js 0.35 kB │ gzip: 0.25 kB │ map: 22.36 kB
|
|
125
125
|
dist/plugins/Monetization/UserCabinetCard.js 0.35 kB │ gzip: 0.24 kB │ map: 3.00 kB
|
|
126
|
-
dist/components/PlAdvancedFilter/PlAdvancedFilter.js 0.36 kB │ gzip: 0.24 kB │ map: 13.
|
|
126
|
+
dist/components/PlAdvancedFilter/PlAdvancedFilter.js 0.36 kB │ gzip: 0.24 kB │ map: 13.46 kB
|
|
127
127
|
dist/components/PlAgDataTable/PlAgOverlayNoRows.js 0.36 kB │ gzip: 0.21 kB │ map: 0.74 kB
|
|
128
128
|
dist/components/PlTableFilters/PlTableFiltersV2.js 0.36 kB │ gzip: 0.25 kB │ map: 6.86 kB
|
|
129
129
|
dist/components/PlAgCellStatusTag/PlAgCellStatusTag.js 0.36 kB │ gzip: 0.20 kB │ map: 0.74 kB
|
|
@@ -222,17 +222,17 @@ dist/internal/createAppV2.js
|
|
|
222
222
|
dist/components/PlAgDataTable/sources/table-state-v2.js 5.66 kB │ gzip: 1.82 kB │ map: 19.14 kB
|
|
223
223
|
dist/internal/createAppV3.js 6.19 kB │ gzip: 2.34 kB │ map: 21.40 kB
|
|
224
224
|
dist/components/PlAgDataTable/sources/table-source-v2.js 7.59 kB │ gzip: 2.88 kB │ map: 27.20 kB
|
|
225
|
-
dist/components/PlAdvancedFilter/PlAdvancedFilter.vue_vue_type_script_setup_true_lang.js 8.
|
|
225
|
+
dist/components/PlAdvancedFilter/PlAdvancedFilter.vue_vue_type_script_setup_true_lang.js 8.57 kB │ gzip: 2.60 kB │ map: 18.58 kB
|
|
226
226
|
dist/components/PlAdvancedFilter/FilterEditor.vue_vue_type_script_setup_true_lang.js 10.58 kB │ gzip: 3.14 kB │ map: 24.73 kB
|
|
227
227
|
dist/components/PlAgDataTable/PlAgDataTableV2.vue_vue_type_script_setup_true_lang.js 12.54 kB │ gzip: 3.96 kB │ map: 29.97 kB
|
|
228
228
|
|
|
229
229
|
[33m[33m[PLUGIN_TIMINGS] Warning:[0m Your build spent significant time in plugins. Here is a breakdown:
|
|
230
|
-
- sourcemaps (
|
|
231
|
-
- vite:dts (
|
|
232
|
-
- vite:vue (
|
|
233
|
-
- vite:css (
|
|
234
|
-
- vite:
|
|
230
|
+
- sourcemaps (26%)
|
|
231
|
+
- vite:dts (26%)
|
|
232
|
+
- vite:vue (11%)
|
|
233
|
+
- vite:css-post (11%)
|
|
234
|
+
- vite:build-import-analysis (9%)
|
|
235
235
|
See https://rolldown.rs/options/checks#plugintimings for more details.
|
|
236
236
|
[39m
|
|
237
|
-
[32m✓ built in
|
|
237
|
+
[32m✓ built in 6.47s[39m
|
|
238
238
|
Build completed successfully
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
WARN Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
|
|
2
2
|
|
|
3
|
-
> @platforma-sdk/ui-vue@1.80.
|
|
3
|
+
> @platforma-sdk/ui-vue@1.80.13 formatter:check /home/runner/_work/platforma/platforma/sdk/ui-vue
|
|
4
4
|
> ts-builder formatter --check
|
|
5
5
|
|
|
6
6
|
Checking formatting...
|
|
@@ -8,5 +8,5 @@ Checking formatting...
|
|
|
8
8
|
Checking formatting...
|
|
9
9
|
|
|
10
10
|
All matched files use the correct format.
|
|
11
|
-
Finished in
|
|
11
|
+
Finished in 2850ms on 137 files using 16 threads.
|
|
12
12
|
Format check completed successfully
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
WARN Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
|
|
2
2
|
|
|
3
|
-
> @platforma-sdk/ui-vue@1.80.
|
|
3
|
+
> @platforma-sdk/ui-vue@1.80.13 linter:check /home/runner/_work/platforma/platforma/sdk/ui-vue
|
|
4
4
|
> ts-builder linter --check
|
|
5
5
|
|
|
6
6
|
Linting project...
|
|
7
7
|
↳ oxlint --config /home/runner/_work/platforma/platforma/sdk/ui-vue/.oxlintrc.json --deny-warnings
|
|
8
8
|
Found 0 warnings and 0 errors.
|
|
9
|
-
Finished in
|
|
9
|
+
Finished in 29ms on 120 files with 108 rules using 16 threads.
|
|
10
10
|
Linting completed successfully
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
WARN Issue while reading "/home/runner/_work/platforma/platforma/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
|
|
2
2
|
|
|
3
|
-
> @platforma-sdk/ui-vue@1.80.
|
|
3
|
+
> @platforma-sdk/ui-vue@1.80.13 types:check /home/runner/_work/platforma/platforma/sdk/ui-vue
|
|
4
4
|
> ts-builder type-check --target browser-lib
|
|
5
5
|
|
|
6
6
|
↳ vue-tsc.js --noEmit --project ./tsconfig.json --customConditions ,
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @platforma-sdk/ui-vue
|
|
2
2
|
|
|
3
|
+
## 1.80.13
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 597ca40: PlDataTable: allow the default filter group to be fully cleared, and harden filter merging.
|
|
8
|
+
|
|
9
|
+
- `PlAdvancedFilter`: when the last leaf of a non-removable group (e.g. the pinned default-filters group) is deleted, keep it as an empty group instead of splicing the whole group out. This lets the default-filters group be emptied (previously the last default filter could not be removed); the group's reset still restores the defaults.
|
|
10
|
+
- `createPlDataTableV3.concatFilters`: AND-combine operands that are not `and` groups (a bare leaf, a `not`, or an `or` group) by treating them as single members, instead of assuming every operand has a `.filters` array. Fixes a `TypeError` crash when the persisted filter state is a lone leaf (e.g. a single sheet selection) and a case where an `or` root was incorrectly OR-merged with the defaults.
|
|
11
|
+
|
|
12
|
+
- Updated dependencies [597ca40]
|
|
13
|
+
- @platforma-sdk/model@1.80.13
|
|
14
|
+
- @milaboratories/uikit@2.15.19
|
|
15
|
+
|
|
3
16
|
## 1.80.10
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlAdvancedFilter.js","names":[],"sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends RootFilter\">\nimport { PlBtnSecondary, PlCheckbox, PlElementList } from \"@milaboratories/uikit\";\nimport type { ListOptionBase } from \"@platforma-sdk/model\";\nimport { produce } from \"immer\";\nimport { computed } from \"vue\";\nimport FilterEditor from \"./FilterEditor.vue\";\nimport OperandButton from \"./OperandButton.vue\";\nimport { DEFAULT_FILTER_TYPE, DEFAULT_FILTERS, SUPPORTED_FILTER_TYPES } from \"./constants\";\nimport type {\n CommonFilter,\n EditableFilter,\n NodeFilter,\n Operand,\n PlAdvancedFilterColumnId,\n RootFilter,\n SourceOptionInfo,\n} from \"./types\";\nimport { createNewGroup, getNewId, isValidColumnId } from \"./utils\";\n\nconst props = withDefaults(\n defineProps<{\n filters: T;\n onUpdateFilters: (filters: T) => void;\n /** List of ids of sources (columns, axes) that can be selected in filters */\n options: SourceOptionInfo[];\n /** List of supported filter types */\n supportedFilters?: typeof SUPPORTED_FILTER_TYPES;\n /** If true - new filter can be added by droppind element into filter group; else new column is added by button click */\n enableDnd?: boolean;\n /** If true - \"Add group\" button is shown below the filter groups */\n enableAddGroupButton?: boolean;\n /** If true - eye icon is shown per group to toggle suppression */\n enableToggling?: boolean;\n /** Function to determine if a filter is pinned */\n isPinned?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is removable */\n isRemovable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is draggable */\n isDraggable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a group is complete */\n isCompletedGroup?: (group: NodeFilter, index: number) => boolean;\n /** Loading function for unique values for Equal/InSet filters and fixed axes options. */\n getSuggestOptions: (params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n }) => ListOptionBase<string | number>[] | Promise<ListOptionBase<string | number>[]>;\n }>(),\n {\n supportedFilters: () => SUPPORTED_FILTER_TYPES,\n isCompletedGroup: () => false,\n isPinned: () => false,\n isRemovable: () => true,\n isDraggable: () => true,\n\n getSuggestModel: undefined,\n\n enableDnd: false,\n enableAddGroupButton: false,\n enableToggling: false,\n },\n);\nconst produceFiltersUpdate = (updater: (draft: T) => void) => {\n props.onUpdateFilters(produce(props.filters, updater));\n};\n\nconst firstColumnId = computed(() => props.options[0]?.id);\nconst emptyGroup: NodeFilter[] = [\n {\n id: -1,\n type: \"and\",\n filters: [],\n isExpanded: true,\n },\n];\n\nconst rootFilters = computed({\n get: () => props.filters.filters,\n set: (filters) => props.onUpdateFilters({ ...props.filters, filters: filters }),\n});\n\nfunction getRootGroups() {\n if (props.filters.type !== \"or\" && props.filters.type !== \"and\") {\n throw new Error('Invalid model structure, expected root to be \"or\" or \"and\" group');\n }\n return props.filters.filters;\n}\n\nfunction getDraftGroupContent(\n draft: RootFilter,\n idx: number,\n): Exclude<NodeFilter, { type: \"not\" }> {\n const group = draft.filters[idx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n return group.filter;\n }\n if (group.type !== \"and\" && group.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n return group;\n}\n\nfunction getNotContent<T extends CommonFilter>(item: T): Exclude<T, { type: \"not\" }> {\n return item.type === \"not\"\n ? (item.filter as Exclude<T, { type: \"not\" }>)\n : (item as Exclude<T, { type: \"not\" }>);\n}\n\nfunction addColumnToGroup(groupIdx: number, selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n group.filters.push({\n ...DEFAULT_FILTERS[DEFAULT_FILTER_TYPE],\n column: selectedSourceId,\n id: getNewId(),\n isExpanded: true,\n } as CommonFilter);\n });\n}\n\nfunction removeFilterFromGroup(groupIdx: number, filterIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n if (group.filters.length === 1 && filterIdx === 0) {\n draft.filters.splice(groupIdx, 1);\n } else {\n group.filters.splice(filterIdx, 1);\n }\n });\n}\n\nfunction inverseRootNode(groupIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = draft.filters[groupIdx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n ...group.filter,\n };\n } else {\n const type = draft.filters[groupIdx].type;\n if (type !== \"and\" && type !== \"or\" && type !== \"not\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n id: getNewId(),\n type: \"not\",\n filter: draft.filters[groupIdx],\n };\n }\n });\n}\n\nfunction addGroup(selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters.push(createNewGroup(selectedSourceId));\n });\n}\n\nfunction updateFilter(groupIdx: number, filterIdx: number, updatedFilter: EditableFilter) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, groupIdx).filters[filterIdx] = updatedFilter as CommonFilter;\n });\n}\n\nfunction handleDropToExistingGroup(groupIdx: number, event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addColumnToGroup(groupIdx, draggedId);\n }\n }\n}\n\nfunction handleDropToNewGroup(event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addGroup(draggedId);\n }\n }\n}\n\nfunction dragOver(event: DragEvent) {\n event.preventDefault();\n}\n\nfunction toggleExpand(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isExpanded = !draft.filters[index].isExpanded;\n });\n}\n\nfunction toggleSuppress(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isSuppressed = !draft.filters[index].isSuppressed;\n });\n}\n\nfunction changeGroupOperand(index: number, v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, index).type = v;\n });\n}\n\nfunction changeRootOperand(v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.type = v;\n });\n}\n\nfunction validateFilter<T extends CommonFilter>(item: T): EditableFilter {\n if (item.type === \"and\" || item.type === \"or\" || item.type === \"not\") {\n throw new Error(\"Invalid filter structure, expected leaf filter\");\n }\n\n return item as EditableFilter;\n}\n</script>\n<template>\n <div>\n <PlElementList\n v-model:items=\"rootFilters\"\n :get-item-key=\"(filter) => filter.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"(filter) => filter.isExpanded === true\"\n :on-expand=\"toggleExpand\"\n :is-toggled=\"(item) => item.isSuppressed === true\"\n :on-toggle=\"toggleSuppress\"\n :is-pinned=\"(item, index) => props.isPinned?.(item, index) === true\"\n :is-pinnable=\"() => false\"\n :is-removable=\"(item, index) => props.isRemovable?.(item, index) === true\"\n :is-draggable=\"(item, index) => props.isDraggable?.(item, index) === true\"\n :disable-toggling=\"props.enableToggling !== true\"\n :disable-dragging=\"false\"\n :disable-removing=\"false\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index\">Filter group</slot>\n </template>\n <template #item-content=\"{ item, index }\">\n <div\n :class=\"[$style.groupContent, { [$style.suppressedLabel]: item.isSuppressed }]\"\n dropzone=\"true\"\n @drop=\"(event) => handleDropToExistingGroup(index, event)\"\n @dragover=\"dragOver\"\n >\n <PlCheckbox\n :model-value=\"item.type === 'not'\"\n :class=\"$style.notCheckbox\"\n @update:model-value=\"inverseRootNode(index)\"\n >\n Filter Out\n </PlCheckbox>\n <template v-for=\"(_, filterIdx) in getNotContent(item).filters\" :key=\"filterIdx\">\n <FilterEditor\n :filter=\"validateFilter(getNotContent(item).filters[filterIdx])\"\n :operand=\"getNotContent(item).type\"\n :column-options=\"options\"\n :supported-filters=\"props.supportedFilters\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :enable-dnd=\"Boolean(props.enableDnd)\"\n :is-last=\"filterIdx === getNotContent(item).filters.length - 1\"\n @delete=\"() => removeFilterFromGroup(index, filterIdx)\"\n @update-filter=\"(value) => updateFilter(index, filterIdx, value)\"\n @change-operand=\"(v) => changeGroupOperand(index, v)\"\n />\n </template>\n <div v-if=\"props.enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <PlBtnSecondary\n v-else-if=\"!props.isCompletedGroup(item, index)\"\n icon=\"add\"\n @click=\"addColumnToGroup(index, firstColumnId)\"\n >\n Add filter\n </PlBtnSecondary>\n </div>\n </template>\n <template #item-after=\"{ index }\">\n <OperandButton\n v-if=\"props.enableAddGroupButton || index < getRootGroups().length - 1\"\n :class=\"$style.buttonWrapper\"\n :active=\"props.filters.type\"\n :disabled=\"index === getRootGroups().length - 1\"\n :on-select=\"changeRootOperand\"\n />\n </template>\n </PlElementList>\n\n <!-- Last group - always empty, just for adding new groups -->\n <PlElementList\n v-if=\"props.enableAddGroupButton\"\n :items=\"emptyGroup\"\n :get-item-key=\"(group) => group.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"() => true\"\n :disableDragging=\"true\"\n :disableRemoving=\"true\"\n :disableToggling=\"true\"\n :disablePinning=\"true\"\n dropzone=\"true\"\n @drop=\"handleDropToNewGroup\"\n @dragover=\"dragOver\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index + getRootGroups().length\"\n >Filter group</slot\n >\n </template>\n <template #item-content>\n <div v-if=\"enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <slot v-else name=\"add-group-buttons\">\n <PlBtnSecondary icon=\"add\" @click=\"addGroup(firstColumnId)\"> Add filter </PlBtnSecondary>\n </slot>\n </template>\n </PlElementList>\n </div>\n</template>\n<style module>\n.filterGroup {\n background: var(--bg-base-light);\n}\n.filterGroup:hover {\n background: rgba(99, 224, 36, 0.12);\n}\n.filterGroupTitle {\n background: none;\n}\n.filterGroupContent {\n padding: 4px 24px 24px 24px;\n}\n.groupContent {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.notCheckbox {\n margin: 4px 0;\n}\n.suppressedLabel {\n filter: grayscale(100%);\n pointer-events: none;\n}\n.dropzone {\n border-radius: 6px;\n border: 1.5px dashed var(--color-div-grey);\n color: var(--txt-03);\n font-family: Manrope;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n height: 40px;\n cursor: default;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.buttonWrapper {\n margin-top: 8px;\n height: 56px;\n display: flex;\n align-items: center;\n}\n:global(.sortable-chosen) .buttonWrapper {\n visibility: hidden;\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"PlAdvancedFilter.js","names":[],"sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends RootFilter\">\nimport { PlBtnSecondary, PlCheckbox, PlElementList } from \"@milaboratories/uikit\";\nimport type { ListOptionBase } from \"@platforma-sdk/model\";\nimport { produce } from \"immer\";\nimport { computed } from \"vue\";\nimport FilterEditor from \"./FilterEditor.vue\";\nimport OperandButton from \"./OperandButton.vue\";\nimport { DEFAULT_FILTER_TYPE, DEFAULT_FILTERS, SUPPORTED_FILTER_TYPES } from \"./constants\";\nimport type {\n CommonFilter,\n EditableFilter,\n NodeFilter,\n Operand,\n PlAdvancedFilterColumnId,\n RootFilter,\n SourceOptionInfo,\n} from \"./types\";\nimport { createNewGroup, getNewId, isValidColumnId } from \"./utils\";\n\nconst props = withDefaults(\n defineProps<{\n filters: T;\n onUpdateFilters: (filters: T) => void;\n /** List of ids of sources (columns, axes) that can be selected in filters */\n options: SourceOptionInfo[];\n /** List of supported filter types */\n supportedFilters?: typeof SUPPORTED_FILTER_TYPES;\n /** If true - new filter can be added by droppind element into filter group; else new column is added by button click */\n enableDnd?: boolean;\n /** If true - \"Add group\" button is shown below the filter groups */\n enableAddGroupButton?: boolean;\n /** If true - eye icon is shown per group to toggle suppression */\n enableToggling?: boolean;\n /** Function to determine if a filter is pinned */\n isPinned?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is removable */\n isRemovable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is draggable */\n isDraggable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a group is complete */\n isCompletedGroup?: (group: NodeFilter, index: number) => boolean;\n /** Loading function for unique values for Equal/InSet filters and fixed axes options. */\n getSuggestOptions: (params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n }) => ListOptionBase<string | number>[] | Promise<ListOptionBase<string | number>[]>;\n }>(),\n {\n supportedFilters: () => SUPPORTED_FILTER_TYPES,\n isCompletedGroup: () => false,\n isPinned: () => false,\n isRemovable: () => true,\n isDraggable: () => true,\n\n getSuggestModel: undefined,\n\n enableDnd: false,\n enableAddGroupButton: false,\n enableToggling: false,\n },\n);\nconst produceFiltersUpdate = (updater: (draft: T) => void) => {\n props.onUpdateFilters(produce(props.filters, updater));\n};\n\nconst firstColumnId = computed(() => props.options[0]?.id);\nconst emptyGroup: NodeFilter[] = [\n {\n id: -1,\n type: \"and\",\n filters: [],\n isExpanded: true,\n },\n];\n\nconst rootFilters = computed({\n get: () => props.filters.filters,\n set: (filters) => props.onUpdateFilters({ ...props.filters, filters: filters }),\n});\n\nfunction getRootGroups() {\n if (props.filters.type !== \"or\" && props.filters.type !== \"and\") {\n throw new Error('Invalid model structure, expected root to be \"or\" or \"and\" group');\n }\n return props.filters.filters;\n}\n\nfunction getDraftGroupContent(\n draft: RootFilter,\n idx: number,\n): Exclude<NodeFilter, { type: \"not\" }> {\n const group = draft.filters[idx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n return group.filter;\n }\n if (group.type !== \"and\" && group.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n return group;\n}\n\nfunction getNotContent<T extends CommonFilter>(item: T): Exclude<T, { type: \"not\" }> {\n return item.type === \"not\"\n ? (item.filter as Exclude<T, { type: \"not\" }>)\n : (item as Exclude<T, { type: \"not\" }>);\n}\n\nfunction addColumnToGroup(groupIdx: number, selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n group.filters.push({\n ...DEFAULT_FILTERS[DEFAULT_FILTER_TYPE],\n column: selectedSourceId,\n id: getNewId(),\n isExpanded: true,\n } as CommonFilter);\n });\n}\n\nfunction removeFilterFromGroup(groupIdx: number, filterIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n const removingLastLeaf = group.filters.length === 1 && filterIdx === 0;\n\n if (removingLastLeaf && props.isRemovable(draft.filters[groupIdx], groupIdx)) {\n draft.filters.splice(groupIdx, 1);\n } else {\n group.filters.splice(filterIdx, 1);\n }\n });\n}\n\nfunction inverseRootNode(groupIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = draft.filters[groupIdx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n ...group.filter,\n };\n } else {\n const type = draft.filters[groupIdx].type;\n if (type !== \"and\" && type !== \"or\" && type !== \"not\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n id: getNewId(),\n type: \"not\",\n filter: draft.filters[groupIdx],\n };\n }\n });\n}\n\nfunction addGroup(selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters.push(createNewGroup(selectedSourceId));\n });\n}\n\nfunction updateFilter(groupIdx: number, filterIdx: number, updatedFilter: EditableFilter) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, groupIdx).filters[filterIdx] = updatedFilter as CommonFilter;\n });\n}\n\nfunction handleDropToExistingGroup(groupIdx: number, event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addColumnToGroup(groupIdx, draggedId);\n }\n }\n}\n\nfunction handleDropToNewGroup(event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addGroup(draggedId);\n }\n }\n}\n\nfunction dragOver(event: DragEvent) {\n event.preventDefault();\n}\n\nfunction toggleExpand(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isExpanded = !draft.filters[index].isExpanded;\n });\n}\n\nfunction toggleSuppress(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isSuppressed = !draft.filters[index].isSuppressed;\n });\n}\n\nfunction changeGroupOperand(index: number, v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, index).type = v;\n });\n}\n\nfunction changeRootOperand(v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.type = v;\n });\n}\n\nfunction validateFilter<T extends CommonFilter>(item: T): EditableFilter {\n if (item.type === \"and\" || item.type === \"or\" || item.type === \"not\") {\n throw new Error(\"Invalid filter structure, expected leaf filter\");\n }\n\n return item as EditableFilter;\n}\n</script>\n<template>\n <div>\n <PlElementList\n v-model:items=\"rootFilters\"\n :get-item-key=\"(filter) => filter.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"(filter) => filter.isExpanded === true\"\n :on-expand=\"toggleExpand\"\n :is-toggled=\"(item) => item.isSuppressed === true\"\n :on-toggle=\"toggleSuppress\"\n :is-pinned=\"(item, index) => props.isPinned?.(item, index) === true\"\n :is-pinnable=\"() => false\"\n :is-removable=\"(item, index) => props.isRemovable?.(item, index) === true\"\n :is-draggable=\"(item, index) => props.isDraggable?.(item, index) === true\"\n :disable-toggling=\"props.enableToggling !== true\"\n :disable-dragging=\"false\"\n :disable-removing=\"false\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index\">Filter group</slot>\n </template>\n <template #item-content=\"{ item, index }\">\n <div\n :class=\"[$style.groupContent, { [$style.suppressedLabel]: item.isSuppressed }]\"\n dropzone=\"true\"\n @drop=\"(event) => handleDropToExistingGroup(index, event)\"\n @dragover=\"dragOver\"\n >\n <PlCheckbox\n :model-value=\"item.type === 'not'\"\n :class=\"$style.notCheckbox\"\n @update:model-value=\"inverseRootNode(index)\"\n >\n Filter Out\n </PlCheckbox>\n <template v-for=\"(_, filterIdx) in getNotContent(item).filters\" :key=\"filterIdx\">\n <FilterEditor\n :filter=\"validateFilter(getNotContent(item).filters[filterIdx])\"\n :operand=\"getNotContent(item).type\"\n :column-options=\"options\"\n :supported-filters=\"props.supportedFilters\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :enable-dnd=\"Boolean(props.enableDnd)\"\n :is-last=\"filterIdx === getNotContent(item).filters.length - 1\"\n @delete=\"() => removeFilterFromGroup(index, filterIdx)\"\n @update-filter=\"(value) => updateFilter(index, filterIdx, value)\"\n @change-operand=\"(v) => changeGroupOperand(index, v)\"\n />\n </template>\n <div v-if=\"props.enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <PlBtnSecondary\n v-else-if=\"!props.isCompletedGroup(item, index)\"\n icon=\"add\"\n @click=\"addColumnToGroup(index, firstColumnId)\"\n >\n Add filter\n </PlBtnSecondary>\n </div>\n </template>\n <template #item-after=\"{ index }\">\n <OperandButton\n v-if=\"props.enableAddGroupButton || index < getRootGroups().length - 1\"\n :class=\"$style.buttonWrapper\"\n :active=\"props.filters.type\"\n :disabled=\"index === getRootGroups().length - 1\"\n :on-select=\"changeRootOperand\"\n />\n </template>\n </PlElementList>\n\n <!-- Last group - always empty, just for adding new groups -->\n <PlElementList\n v-if=\"props.enableAddGroupButton\"\n :items=\"emptyGroup\"\n :get-item-key=\"(group) => group.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"() => true\"\n :disableDragging=\"true\"\n :disableRemoving=\"true\"\n :disableToggling=\"true\"\n :disablePinning=\"true\"\n dropzone=\"true\"\n @drop=\"handleDropToNewGroup\"\n @dragover=\"dragOver\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index + getRootGroups().length\"\n >Filter group</slot\n >\n </template>\n <template #item-content>\n <div v-if=\"enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <slot v-else name=\"add-group-buttons\">\n <PlBtnSecondary icon=\"add\" @click=\"addGroup(firstColumnId)\"> Add filter </PlBtnSecondary>\n </slot>\n </template>\n </PlElementList>\n </div>\n</template>\n<style module>\n.filterGroup {\n background: var(--bg-base-light);\n}\n.filterGroup:hover {\n background: rgba(99, 224, 36, 0.12);\n}\n.filterGroupTitle {\n background: none;\n}\n.filterGroupContent {\n padding: 4px 24px 24px 24px;\n}\n.groupContent {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.notCheckbox {\n margin: 4px 0;\n}\n.suppressedLabel {\n filter: grayscale(100%);\n pointer-events: none;\n}\n.dropzone {\n border-radius: 6px;\n border: 1.5px dashed var(--color-div-grey);\n color: var(--txt-03);\n font-family: Manrope;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n height: 40px;\n cursor: default;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.buttonWrapper {\n margin-top: 8px;\n height: 56px;\n display: flex;\n align-items: center;\n}\n:global(.sortable-chosen) .buttonWrapper {\n visibility: hidden;\n}\n</style>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlAdvancedFilter.vue_vue_type_style_index_0_lang.module.js","names":[],"sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends RootFilter\">\nimport { PlBtnSecondary, PlCheckbox, PlElementList } from \"@milaboratories/uikit\";\nimport type { ListOptionBase } from \"@platforma-sdk/model\";\nimport { produce } from \"immer\";\nimport { computed } from \"vue\";\nimport FilterEditor from \"./FilterEditor.vue\";\nimport OperandButton from \"./OperandButton.vue\";\nimport { DEFAULT_FILTER_TYPE, DEFAULT_FILTERS, SUPPORTED_FILTER_TYPES } from \"./constants\";\nimport type {\n CommonFilter,\n EditableFilter,\n NodeFilter,\n Operand,\n PlAdvancedFilterColumnId,\n RootFilter,\n SourceOptionInfo,\n} from \"./types\";\nimport { createNewGroup, getNewId, isValidColumnId } from \"./utils\";\n\nconst props = withDefaults(\n defineProps<{\n filters: T;\n onUpdateFilters: (filters: T) => void;\n /** List of ids of sources (columns, axes) that can be selected in filters */\n options: SourceOptionInfo[];\n /** List of supported filter types */\n supportedFilters?: typeof SUPPORTED_FILTER_TYPES;\n /** If true - new filter can be added by droppind element into filter group; else new column is added by button click */\n enableDnd?: boolean;\n /** If true - \"Add group\" button is shown below the filter groups */\n enableAddGroupButton?: boolean;\n /** If true - eye icon is shown per group to toggle suppression */\n enableToggling?: boolean;\n /** Function to determine if a filter is pinned */\n isPinned?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is removable */\n isRemovable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is draggable */\n isDraggable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a group is complete */\n isCompletedGroup?: (group: NodeFilter, index: number) => boolean;\n /** Loading function for unique values for Equal/InSet filters and fixed axes options. */\n getSuggestOptions: (params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n }) => ListOptionBase<string | number>[] | Promise<ListOptionBase<string | number>[]>;\n }>(),\n {\n supportedFilters: () => SUPPORTED_FILTER_TYPES,\n isCompletedGroup: () => false,\n isPinned: () => false,\n isRemovable: () => true,\n isDraggable: () => true,\n\n getSuggestModel: undefined,\n\n enableDnd: false,\n enableAddGroupButton: false,\n enableToggling: false,\n },\n);\nconst produceFiltersUpdate = (updater: (draft: T) => void) => {\n props.onUpdateFilters(produce(props.filters, updater));\n};\n\nconst firstColumnId = computed(() => props.options[0]?.id);\nconst emptyGroup: NodeFilter[] = [\n {\n id: -1,\n type: \"and\",\n filters: [],\n isExpanded: true,\n },\n];\n\nconst rootFilters = computed({\n get: () => props.filters.filters,\n set: (filters) => props.onUpdateFilters({ ...props.filters, filters: filters }),\n});\n\nfunction getRootGroups() {\n if (props.filters.type !== \"or\" && props.filters.type !== \"and\") {\n throw new Error('Invalid model structure, expected root to be \"or\" or \"and\" group');\n }\n return props.filters.filters;\n}\n\nfunction getDraftGroupContent(\n draft: RootFilter,\n idx: number,\n): Exclude<NodeFilter, { type: \"not\" }> {\n const group = draft.filters[idx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n return group.filter;\n }\n if (group.type !== \"and\" && group.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n return group;\n}\n\nfunction getNotContent<T extends CommonFilter>(item: T): Exclude<T, { type: \"not\" }> {\n return item.type === \"not\"\n ? (item.filter as Exclude<T, { type: \"not\" }>)\n : (item as Exclude<T, { type: \"not\" }>);\n}\n\nfunction addColumnToGroup(groupIdx: number, selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n group.filters.push({\n ...DEFAULT_FILTERS[DEFAULT_FILTER_TYPE],\n column: selectedSourceId,\n id: getNewId(),\n isExpanded: true,\n } as CommonFilter);\n });\n}\n\nfunction removeFilterFromGroup(groupIdx: number, filterIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n if (group.filters.length === 1 && filterIdx === 0) {\n draft.filters.splice(groupIdx, 1);\n } else {\n group.filters.splice(filterIdx, 1);\n }\n });\n}\n\nfunction inverseRootNode(groupIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = draft.filters[groupIdx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n ...group.filter,\n };\n } else {\n const type = draft.filters[groupIdx].type;\n if (type !== \"and\" && type !== \"or\" && type !== \"not\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n id: getNewId(),\n type: \"not\",\n filter: draft.filters[groupIdx],\n };\n }\n });\n}\n\nfunction addGroup(selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters.push(createNewGroup(selectedSourceId));\n });\n}\n\nfunction updateFilter(groupIdx: number, filterIdx: number, updatedFilter: EditableFilter) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, groupIdx).filters[filterIdx] = updatedFilter as CommonFilter;\n });\n}\n\nfunction handleDropToExistingGroup(groupIdx: number, event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addColumnToGroup(groupIdx, draggedId);\n }\n }\n}\n\nfunction handleDropToNewGroup(event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addGroup(draggedId);\n }\n }\n}\n\nfunction dragOver(event: DragEvent) {\n event.preventDefault();\n}\n\nfunction toggleExpand(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isExpanded = !draft.filters[index].isExpanded;\n });\n}\n\nfunction toggleSuppress(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isSuppressed = !draft.filters[index].isSuppressed;\n });\n}\n\nfunction changeGroupOperand(index: number, v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, index).type = v;\n });\n}\n\nfunction changeRootOperand(v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.type = v;\n });\n}\n\nfunction validateFilter<T extends CommonFilter>(item: T): EditableFilter {\n if (item.type === \"and\" || item.type === \"or\" || item.type === \"not\") {\n throw new Error(\"Invalid filter structure, expected leaf filter\");\n }\n\n return item as EditableFilter;\n}\n</script>\n<template>\n <div>\n <PlElementList\n v-model:items=\"rootFilters\"\n :get-item-key=\"(filter) => filter.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"(filter) => filter.isExpanded === true\"\n :on-expand=\"toggleExpand\"\n :is-toggled=\"(item) => item.isSuppressed === true\"\n :on-toggle=\"toggleSuppress\"\n :is-pinned=\"(item, index) => props.isPinned?.(item, index) === true\"\n :is-pinnable=\"() => false\"\n :is-removable=\"(item, index) => props.isRemovable?.(item, index) === true\"\n :is-draggable=\"(item, index) => props.isDraggable?.(item, index) === true\"\n :disable-toggling=\"props.enableToggling !== true\"\n :disable-dragging=\"false\"\n :disable-removing=\"false\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index\">Filter group</slot>\n </template>\n <template #item-content=\"{ item, index }\">\n <div\n :class=\"[$style.groupContent, { [$style.suppressedLabel]: item.isSuppressed }]\"\n dropzone=\"true\"\n @drop=\"(event) => handleDropToExistingGroup(index, event)\"\n @dragover=\"dragOver\"\n >\n <PlCheckbox\n :model-value=\"item.type === 'not'\"\n :class=\"$style.notCheckbox\"\n @update:model-value=\"inverseRootNode(index)\"\n >\n Filter Out\n </PlCheckbox>\n <template v-for=\"(_, filterIdx) in getNotContent(item).filters\" :key=\"filterIdx\">\n <FilterEditor\n :filter=\"validateFilter(getNotContent(item).filters[filterIdx])\"\n :operand=\"getNotContent(item).type\"\n :column-options=\"options\"\n :supported-filters=\"props.supportedFilters\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :enable-dnd=\"Boolean(props.enableDnd)\"\n :is-last=\"filterIdx === getNotContent(item).filters.length - 1\"\n @delete=\"() => removeFilterFromGroup(index, filterIdx)\"\n @update-filter=\"(value) => updateFilter(index, filterIdx, value)\"\n @change-operand=\"(v) => changeGroupOperand(index, v)\"\n />\n </template>\n <div v-if=\"props.enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <PlBtnSecondary\n v-else-if=\"!props.isCompletedGroup(item, index)\"\n icon=\"add\"\n @click=\"addColumnToGroup(index, firstColumnId)\"\n >\n Add filter\n </PlBtnSecondary>\n </div>\n </template>\n <template #item-after=\"{ index }\">\n <OperandButton\n v-if=\"props.enableAddGroupButton || index < getRootGroups().length - 1\"\n :class=\"$style.buttonWrapper\"\n :active=\"props.filters.type\"\n :disabled=\"index === getRootGroups().length - 1\"\n :on-select=\"changeRootOperand\"\n />\n </template>\n </PlElementList>\n\n <!-- Last group - always empty, just for adding new groups -->\n <PlElementList\n v-if=\"props.enableAddGroupButton\"\n :items=\"emptyGroup\"\n :get-item-key=\"(group) => group.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"() => true\"\n :disableDragging=\"true\"\n :disableRemoving=\"true\"\n :disableToggling=\"true\"\n :disablePinning=\"true\"\n dropzone=\"true\"\n @drop=\"handleDropToNewGroup\"\n @dragover=\"dragOver\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index + getRootGroups().length\"\n >Filter group</slot\n >\n </template>\n <template #item-content>\n <div v-if=\"enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <slot v-else name=\"add-group-buttons\">\n <PlBtnSecondary icon=\"add\" @click=\"addGroup(firstColumnId)\"> Add filter </PlBtnSecondary>\n </slot>\n </template>\n </PlElementList>\n </div>\n</template>\n<style module>\n.filterGroup {\n background: var(--bg-base-light);\n}\n.filterGroup:hover {\n background: rgba(99, 224, 36, 0.12);\n}\n.filterGroupTitle {\n background: none;\n}\n.filterGroupContent {\n padding: 4px 24px 24px 24px;\n}\n.groupContent {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.notCheckbox {\n margin: 4px 0;\n}\n.suppressedLabel {\n filter: grayscale(100%);\n pointer-events: none;\n}\n.dropzone {\n border-radius: 6px;\n border: 1.5px dashed var(--color-div-grey);\n color: var(--txt-03);\n font-family: Manrope;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n height: 40px;\n cursor: default;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.buttonWrapper {\n margin-top: 8px;\n height: 56px;\n display: flex;\n align-items: center;\n}\n:global(.sortable-chosen) .buttonWrapper {\n visibility: hidden;\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"PlAdvancedFilter.vue_vue_type_style_index_0_lang.module.js","names":[],"sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends RootFilter\">\nimport { PlBtnSecondary, PlCheckbox, PlElementList } from \"@milaboratories/uikit\";\nimport type { ListOptionBase } from \"@platforma-sdk/model\";\nimport { produce } from \"immer\";\nimport { computed } from \"vue\";\nimport FilterEditor from \"./FilterEditor.vue\";\nimport OperandButton from \"./OperandButton.vue\";\nimport { DEFAULT_FILTER_TYPE, DEFAULT_FILTERS, SUPPORTED_FILTER_TYPES } from \"./constants\";\nimport type {\n CommonFilter,\n EditableFilter,\n NodeFilter,\n Operand,\n PlAdvancedFilterColumnId,\n RootFilter,\n SourceOptionInfo,\n} from \"./types\";\nimport { createNewGroup, getNewId, isValidColumnId } from \"./utils\";\n\nconst props = withDefaults(\n defineProps<{\n filters: T;\n onUpdateFilters: (filters: T) => void;\n /** List of ids of sources (columns, axes) that can be selected in filters */\n options: SourceOptionInfo[];\n /** List of supported filter types */\n supportedFilters?: typeof SUPPORTED_FILTER_TYPES;\n /** If true - new filter can be added by droppind element into filter group; else new column is added by button click */\n enableDnd?: boolean;\n /** If true - \"Add group\" button is shown below the filter groups */\n enableAddGroupButton?: boolean;\n /** If true - eye icon is shown per group to toggle suppression */\n enableToggling?: boolean;\n /** Function to determine if a filter is pinned */\n isPinned?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is removable */\n isRemovable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is draggable */\n isDraggable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a group is complete */\n isCompletedGroup?: (group: NodeFilter, index: number) => boolean;\n /** Loading function for unique values for Equal/InSet filters and fixed axes options. */\n getSuggestOptions: (params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n }) => ListOptionBase<string | number>[] | Promise<ListOptionBase<string | number>[]>;\n }>(),\n {\n supportedFilters: () => SUPPORTED_FILTER_TYPES,\n isCompletedGroup: () => false,\n isPinned: () => false,\n isRemovable: () => true,\n isDraggable: () => true,\n\n getSuggestModel: undefined,\n\n enableDnd: false,\n enableAddGroupButton: false,\n enableToggling: false,\n },\n);\nconst produceFiltersUpdate = (updater: (draft: T) => void) => {\n props.onUpdateFilters(produce(props.filters, updater));\n};\n\nconst firstColumnId = computed(() => props.options[0]?.id);\nconst emptyGroup: NodeFilter[] = [\n {\n id: -1,\n type: \"and\",\n filters: [],\n isExpanded: true,\n },\n];\n\nconst rootFilters = computed({\n get: () => props.filters.filters,\n set: (filters) => props.onUpdateFilters({ ...props.filters, filters: filters }),\n});\n\nfunction getRootGroups() {\n if (props.filters.type !== \"or\" && props.filters.type !== \"and\") {\n throw new Error('Invalid model structure, expected root to be \"or\" or \"and\" group');\n }\n return props.filters.filters;\n}\n\nfunction getDraftGroupContent(\n draft: RootFilter,\n idx: number,\n): Exclude<NodeFilter, { type: \"not\" }> {\n const group = draft.filters[idx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n return group.filter;\n }\n if (group.type !== \"and\" && group.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n return group;\n}\n\nfunction getNotContent<T extends CommonFilter>(item: T): Exclude<T, { type: \"not\" }> {\n return item.type === \"not\"\n ? (item.filter as Exclude<T, { type: \"not\" }>)\n : (item as Exclude<T, { type: \"not\" }>);\n}\n\nfunction addColumnToGroup(groupIdx: number, selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n group.filters.push({\n ...DEFAULT_FILTERS[DEFAULT_FILTER_TYPE],\n column: selectedSourceId,\n id: getNewId(),\n isExpanded: true,\n } as CommonFilter);\n });\n}\n\nfunction removeFilterFromGroup(groupIdx: number, filterIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n const removingLastLeaf = group.filters.length === 1 && filterIdx === 0;\n\n if (removingLastLeaf && props.isRemovable(draft.filters[groupIdx], groupIdx)) {\n draft.filters.splice(groupIdx, 1);\n } else {\n group.filters.splice(filterIdx, 1);\n }\n });\n}\n\nfunction inverseRootNode(groupIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = draft.filters[groupIdx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n ...group.filter,\n };\n } else {\n const type = draft.filters[groupIdx].type;\n if (type !== \"and\" && type !== \"or\" && type !== \"not\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n id: getNewId(),\n type: \"not\",\n filter: draft.filters[groupIdx],\n };\n }\n });\n}\n\nfunction addGroup(selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters.push(createNewGroup(selectedSourceId));\n });\n}\n\nfunction updateFilter(groupIdx: number, filterIdx: number, updatedFilter: EditableFilter) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, groupIdx).filters[filterIdx] = updatedFilter as CommonFilter;\n });\n}\n\nfunction handleDropToExistingGroup(groupIdx: number, event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addColumnToGroup(groupIdx, draggedId);\n }\n }\n}\n\nfunction handleDropToNewGroup(event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addGroup(draggedId);\n }\n }\n}\n\nfunction dragOver(event: DragEvent) {\n event.preventDefault();\n}\n\nfunction toggleExpand(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isExpanded = !draft.filters[index].isExpanded;\n });\n}\n\nfunction toggleSuppress(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isSuppressed = !draft.filters[index].isSuppressed;\n });\n}\n\nfunction changeGroupOperand(index: number, v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, index).type = v;\n });\n}\n\nfunction changeRootOperand(v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.type = v;\n });\n}\n\nfunction validateFilter<T extends CommonFilter>(item: T): EditableFilter {\n if (item.type === \"and\" || item.type === \"or\" || item.type === \"not\") {\n throw new Error(\"Invalid filter structure, expected leaf filter\");\n }\n\n return item as EditableFilter;\n}\n</script>\n<template>\n <div>\n <PlElementList\n v-model:items=\"rootFilters\"\n :get-item-key=\"(filter) => filter.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"(filter) => filter.isExpanded === true\"\n :on-expand=\"toggleExpand\"\n :is-toggled=\"(item) => item.isSuppressed === true\"\n :on-toggle=\"toggleSuppress\"\n :is-pinned=\"(item, index) => props.isPinned?.(item, index) === true\"\n :is-pinnable=\"() => false\"\n :is-removable=\"(item, index) => props.isRemovable?.(item, index) === true\"\n :is-draggable=\"(item, index) => props.isDraggable?.(item, index) === true\"\n :disable-toggling=\"props.enableToggling !== true\"\n :disable-dragging=\"false\"\n :disable-removing=\"false\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index\">Filter group</slot>\n </template>\n <template #item-content=\"{ item, index }\">\n <div\n :class=\"[$style.groupContent, { [$style.suppressedLabel]: item.isSuppressed }]\"\n dropzone=\"true\"\n @drop=\"(event) => handleDropToExistingGroup(index, event)\"\n @dragover=\"dragOver\"\n >\n <PlCheckbox\n :model-value=\"item.type === 'not'\"\n :class=\"$style.notCheckbox\"\n @update:model-value=\"inverseRootNode(index)\"\n >\n Filter Out\n </PlCheckbox>\n <template v-for=\"(_, filterIdx) in getNotContent(item).filters\" :key=\"filterIdx\">\n <FilterEditor\n :filter=\"validateFilter(getNotContent(item).filters[filterIdx])\"\n :operand=\"getNotContent(item).type\"\n :column-options=\"options\"\n :supported-filters=\"props.supportedFilters\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :enable-dnd=\"Boolean(props.enableDnd)\"\n :is-last=\"filterIdx === getNotContent(item).filters.length - 1\"\n @delete=\"() => removeFilterFromGroup(index, filterIdx)\"\n @update-filter=\"(value) => updateFilter(index, filterIdx, value)\"\n @change-operand=\"(v) => changeGroupOperand(index, v)\"\n />\n </template>\n <div v-if=\"props.enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <PlBtnSecondary\n v-else-if=\"!props.isCompletedGroup(item, index)\"\n icon=\"add\"\n @click=\"addColumnToGroup(index, firstColumnId)\"\n >\n Add filter\n </PlBtnSecondary>\n </div>\n </template>\n <template #item-after=\"{ index }\">\n <OperandButton\n v-if=\"props.enableAddGroupButton || index < getRootGroups().length - 1\"\n :class=\"$style.buttonWrapper\"\n :active=\"props.filters.type\"\n :disabled=\"index === getRootGroups().length - 1\"\n :on-select=\"changeRootOperand\"\n />\n </template>\n </PlElementList>\n\n <!-- Last group - always empty, just for adding new groups -->\n <PlElementList\n v-if=\"props.enableAddGroupButton\"\n :items=\"emptyGroup\"\n :get-item-key=\"(group) => group.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"() => true\"\n :disableDragging=\"true\"\n :disableRemoving=\"true\"\n :disableToggling=\"true\"\n :disablePinning=\"true\"\n dropzone=\"true\"\n @drop=\"handleDropToNewGroup\"\n @dragover=\"dragOver\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index + getRootGroups().length\"\n >Filter group</slot\n >\n </template>\n <template #item-content>\n <div v-if=\"enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <slot v-else name=\"add-group-buttons\">\n <PlBtnSecondary icon=\"add\" @click=\"addGroup(firstColumnId)\"> Add filter </PlBtnSecondary>\n </slot>\n </template>\n </PlElementList>\n </div>\n</template>\n<style module>\n.filterGroup {\n background: var(--bg-base-light);\n}\n.filterGroup:hover {\n background: rgba(99, 224, 36, 0.12);\n}\n.filterGroupTitle {\n background: none;\n}\n.filterGroupContent {\n padding: 4px 24px 24px 24px;\n}\n.groupContent {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.notCheckbox {\n margin: 4px 0;\n}\n.suppressedLabel {\n filter: grayscale(100%);\n pointer-events: none;\n}\n.dropzone {\n border-radius: 6px;\n border: 1.5px dashed var(--color-div-grey);\n color: var(--txt-03);\n font-family: Manrope;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n height: 40px;\n cursor: default;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.buttonWrapper {\n margin-top: 8px;\n height: 56px;\n display: flex;\n align-items: center;\n}\n:global(.sortable-chosen) .buttonWrapper {\n visibility: hidden;\n}\n</style>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlAdvancedFilter.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PlAdvancedFilter.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"names":[],"mappings":"AAsYA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAK3D,OAAO,EAAwC,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC3F,OAAO,KAAK,EAGV,UAAU,EAEV,wBAAwB,EACxB,UAAU,EACV,gBAAgB,EACjB,MAAM,SAAS,CAAC;yBAGA,CAAC,SAAS,UAAU,EACpC,aAAa,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,EAC9D,YAAY,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,EAC3G,eAAe,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EACjE;WA0jBO,mBAAmB,CAAC;iBAxjBf,CAAC;yBACO,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI;QACrC,6EAA6E;iBACpE,gBAAgB,EAAE;QAC3B,qCAAqC;2BAClB,OAAO,sBAAsB;QAChD,wHAAwH;oBAC5G,OAAO;QACnB,oEAAoE;+BAC7C,OAAO;QAC9B,kEAAkE;yBACjD,OAAO;QACxB,kDAAkD;mBACvC,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO;QACvD,qDAAqD;sBACvC,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO;QAC1D,qDAAqD;sBACvC,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO;QAC1D,mDAAmD;2BAChC,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO;QAChE,yFAAyF;2BACtE,CAAC,MAAM,EAAE;YAC1B,QAAQ,EAAE,wBAAwB,CAAC;YACnC,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,SAAS,EAAE,MAAM,CAAC;YAClB,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC;SAC/B,KAAK,cAAc,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;mBA8hBM,CAAC,4BAA2B;oBACzG,OAAO,KAAK,EAAE,gBAAgB,CAAC,EAAE,CAAC,GAAG,IAAI;WAClD,GAAG;;;;;YArDwB,GAAG;;;;YACF,GAAG;qCACG,GAAG;;UAqDtC,EAAE;EAEL,KACQ,OAAO,KAAK,EAAE,KAAK,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC,OAAO,WAAW,CAAC,CAAA;CAAE;AArkBzE,wBAqkB4E;AAe5E,KAAK,mBAAmB,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG,EAAE,CAAC"}
|
|
@@ -87,7 +87,7 @@ var D = ["onDrop"], O = /* @__PURE__ */ _({
|
|
|
87
87
|
function I(e, t) {
|
|
88
88
|
O((n) => {
|
|
89
89
|
let r = N(n, e);
|
|
90
|
-
r.filters.length === 1 && t === 0 ? n.filters.splice(e, 1) : r.filters.splice(t, 1);
|
|
90
|
+
r.filters.length === 1 && t === 0 && _.isRemovable(n.filters[e], e) ? n.filters.splice(e, 1) : r.filters.splice(t, 1);
|
|
91
91
|
});
|
|
92
92
|
}
|
|
93
93
|
function L(e) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlAdvancedFilter.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends RootFilter\">\nimport { PlBtnSecondary, PlCheckbox, PlElementList } from \"@milaboratories/uikit\";\nimport type { ListOptionBase } from \"@platforma-sdk/model\";\nimport { produce } from \"immer\";\nimport { computed } from \"vue\";\nimport FilterEditor from \"./FilterEditor.vue\";\nimport OperandButton from \"./OperandButton.vue\";\nimport { DEFAULT_FILTER_TYPE, DEFAULT_FILTERS, SUPPORTED_FILTER_TYPES } from \"./constants\";\nimport type {\n CommonFilter,\n EditableFilter,\n NodeFilter,\n Operand,\n PlAdvancedFilterColumnId,\n RootFilter,\n SourceOptionInfo,\n} from \"./types\";\nimport { createNewGroup, getNewId, isValidColumnId } from \"./utils\";\n\nconst props = withDefaults(\n defineProps<{\n filters: T;\n onUpdateFilters: (filters: T) => void;\n /** List of ids of sources (columns, axes) that can be selected in filters */\n options: SourceOptionInfo[];\n /** List of supported filter types */\n supportedFilters?: typeof SUPPORTED_FILTER_TYPES;\n /** If true - new filter can be added by droppind element into filter group; else new column is added by button click */\n enableDnd?: boolean;\n /** If true - \"Add group\" button is shown below the filter groups */\n enableAddGroupButton?: boolean;\n /** If true - eye icon is shown per group to toggle suppression */\n enableToggling?: boolean;\n /** Function to determine if a filter is pinned */\n isPinned?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is removable */\n isRemovable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is draggable */\n isDraggable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a group is complete */\n isCompletedGroup?: (group: NodeFilter, index: number) => boolean;\n /** Loading function for unique values for Equal/InSet filters and fixed axes options. */\n getSuggestOptions: (params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n }) => ListOptionBase<string | number>[] | Promise<ListOptionBase<string | number>[]>;\n }>(),\n {\n supportedFilters: () => SUPPORTED_FILTER_TYPES,\n isCompletedGroup: () => false,\n isPinned: () => false,\n isRemovable: () => true,\n isDraggable: () => true,\n\n getSuggestModel: undefined,\n\n enableDnd: false,\n enableAddGroupButton: false,\n enableToggling: false,\n },\n);\nconst produceFiltersUpdate = (updater: (draft: T) => void) => {\n props.onUpdateFilters(produce(props.filters, updater));\n};\n\nconst firstColumnId = computed(() => props.options[0]?.id);\nconst emptyGroup: NodeFilter[] = [\n {\n id: -1,\n type: \"and\",\n filters: [],\n isExpanded: true,\n },\n];\n\nconst rootFilters = computed({\n get: () => props.filters.filters,\n set: (filters) => props.onUpdateFilters({ ...props.filters, filters: filters }),\n});\n\nfunction getRootGroups() {\n if (props.filters.type !== \"or\" && props.filters.type !== \"and\") {\n throw new Error('Invalid model structure, expected root to be \"or\" or \"and\" group');\n }\n return props.filters.filters;\n}\n\nfunction getDraftGroupContent(\n draft: RootFilter,\n idx: number,\n): Exclude<NodeFilter, { type: \"not\" }> {\n const group = draft.filters[idx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n return group.filter;\n }\n if (group.type !== \"and\" && group.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n return group;\n}\n\nfunction getNotContent<T extends CommonFilter>(item: T): Exclude<T, { type: \"not\" }> {\n return item.type === \"not\"\n ? (item.filter as Exclude<T, { type: \"not\" }>)\n : (item as Exclude<T, { type: \"not\" }>);\n}\n\nfunction addColumnToGroup(groupIdx: number, selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n group.filters.push({\n ...DEFAULT_FILTERS[DEFAULT_FILTER_TYPE],\n column: selectedSourceId,\n id: getNewId(),\n isExpanded: true,\n } as CommonFilter);\n });\n}\n\nfunction removeFilterFromGroup(groupIdx: number, filterIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n if (group.filters.length === 1 && filterIdx === 0) {\n draft.filters.splice(groupIdx, 1);\n } else {\n group.filters.splice(filterIdx, 1);\n }\n });\n}\n\nfunction inverseRootNode(groupIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = draft.filters[groupIdx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n ...group.filter,\n };\n } else {\n const type = draft.filters[groupIdx].type;\n if (type !== \"and\" && type !== \"or\" && type !== \"not\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n id: getNewId(),\n type: \"not\",\n filter: draft.filters[groupIdx],\n };\n }\n });\n}\n\nfunction addGroup(selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters.push(createNewGroup(selectedSourceId));\n });\n}\n\nfunction updateFilter(groupIdx: number, filterIdx: number, updatedFilter: EditableFilter) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, groupIdx).filters[filterIdx] = updatedFilter as CommonFilter;\n });\n}\n\nfunction handleDropToExistingGroup(groupIdx: number, event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addColumnToGroup(groupIdx, draggedId);\n }\n }\n}\n\nfunction handleDropToNewGroup(event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addGroup(draggedId);\n }\n }\n}\n\nfunction dragOver(event: DragEvent) {\n event.preventDefault();\n}\n\nfunction toggleExpand(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isExpanded = !draft.filters[index].isExpanded;\n });\n}\n\nfunction toggleSuppress(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isSuppressed = !draft.filters[index].isSuppressed;\n });\n}\n\nfunction changeGroupOperand(index: number, v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, index).type = v;\n });\n}\n\nfunction changeRootOperand(v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.type = v;\n });\n}\n\nfunction validateFilter<T extends CommonFilter>(item: T): EditableFilter {\n if (item.type === \"and\" || item.type === \"or\" || item.type === \"not\") {\n throw new Error(\"Invalid filter structure, expected leaf filter\");\n }\n\n return item as EditableFilter;\n}\n</script>\n<template>\n <div>\n <PlElementList\n v-model:items=\"rootFilters\"\n :get-item-key=\"(filter) => filter.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"(filter) => filter.isExpanded === true\"\n :on-expand=\"toggleExpand\"\n :is-toggled=\"(item) => item.isSuppressed === true\"\n :on-toggle=\"toggleSuppress\"\n :is-pinned=\"(item, index) => props.isPinned?.(item, index) === true\"\n :is-pinnable=\"() => false\"\n :is-removable=\"(item, index) => props.isRemovable?.(item, index) === true\"\n :is-draggable=\"(item, index) => props.isDraggable?.(item, index) === true\"\n :disable-toggling=\"props.enableToggling !== true\"\n :disable-dragging=\"false\"\n :disable-removing=\"false\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index\">Filter group</slot>\n </template>\n <template #item-content=\"{ item, index }\">\n <div\n :class=\"[$style.groupContent, { [$style.suppressedLabel]: item.isSuppressed }]\"\n dropzone=\"true\"\n @drop=\"(event) => handleDropToExistingGroup(index, event)\"\n @dragover=\"dragOver\"\n >\n <PlCheckbox\n :model-value=\"item.type === 'not'\"\n :class=\"$style.notCheckbox\"\n @update:model-value=\"inverseRootNode(index)\"\n >\n Filter Out\n </PlCheckbox>\n <template v-for=\"(_, filterIdx) in getNotContent(item).filters\" :key=\"filterIdx\">\n <FilterEditor\n :filter=\"validateFilter(getNotContent(item).filters[filterIdx])\"\n :operand=\"getNotContent(item).type\"\n :column-options=\"options\"\n :supported-filters=\"props.supportedFilters\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :enable-dnd=\"Boolean(props.enableDnd)\"\n :is-last=\"filterIdx === getNotContent(item).filters.length - 1\"\n @delete=\"() => removeFilterFromGroup(index, filterIdx)\"\n @update-filter=\"(value) => updateFilter(index, filterIdx, value)\"\n @change-operand=\"(v) => changeGroupOperand(index, v)\"\n />\n </template>\n <div v-if=\"props.enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <PlBtnSecondary\n v-else-if=\"!props.isCompletedGroup(item, index)\"\n icon=\"add\"\n @click=\"addColumnToGroup(index, firstColumnId)\"\n >\n Add filter\n </PlBtnSecondary>\n </div>\n </template>\n <template #item-after=\"{ index }\">\n <OperandButton\n v-if=\"props.enableAddGroupButton || index < getRootGroups().length - 1\"\n :class=\"$style.buttonWrapper\"\n :active=\"props.filters.type\"\n :disabled=\"index === getRootGroups().length - 1\"\n :on-select=\"changeRootOperand\"\n />\n </template>\n </PlElementList>\n\n <!-- Last group - always empty, just for adding new groups -->\n <PlElementList\n v-if=\"props.enableAddGroupButton\"\n :items=\"emptyGroup\"\n :get-item-key=\"(group) => group.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"() => true\"\n :disableDragging=\"true\"\n :disableRemoving=\"true\"\n :disableToggling=\"true\"\n :disablePinning=\"true\"\n dropzone=\"true\"\n @drop=\"handleDropToNewGroup\"\n @dragover=\"dragOver\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index + getRootGroups().length\"\n >Filter group</slot\n >\n </template>\n <template #item-content>\n <div v-if=\"enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <slot v-else name=\"add-group-buttons\">\n <PlBtnSecondary icon=\"add\" @click=\"addGroup(firstColumnId)\"> Add filter </PlBtnSecondary>\n </slot>\n </template>\n </PlElementList>\n </div>\n</template>\n<style module>\n.filterGroup {\n background: var(--bg-base-light);\n}\n.filterGroup:hover {\n background: rgba(99, 224, 36, 0.12);\n}\n.filterGroupTitle {\n background: none;\n}\n.filterGroupContent {\n padding: 4px 24px 24px 24px;\n}\n.groupContent {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.notCheckbox {\n margin: 4px 0;\n}\n.suppressedLabel {\n filter: grayscale(100%);\n pointer-events: none;\n}\n.dropzone {\n border-radius: 6px;\n border: 1.5px dashed var(--color-div-grey);\n color: var(--txt-03);\n font-family: Manrope;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n height: 40px;\n cursor: default;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.buttonWrapper {\n margin-top: 8px;\n height: 56px;\n display: flex;\n align-items: center;\n}\n:global(.sortable-chosen) .buttonWrapper {\n visibility: hidden;\n}\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PlAdvancedFilter.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../src/components/PlAdvancedFilter/PlAdvancedFilter.vue"],"sourcesContent":["<script lang=\"ts\" setup generic=\"T extends RootFilter\">\nimport { PlBtnSecondary, PlCheckbox, PlElementList } from \"@milaboratories/uikit\";\nimport type { ListOptionBase } from \"@platforma-sdk/model\";\nimport { produce } from \"immer\";\nimport { computed } from \"vue\";\nimport FilterEditor from \"./FilterEditor.vue\";\nimport OperandButton from \"./OperandButton.vue\";\nimport { DEFAULT_FILTER_TYPE, DEFAULT_FILTERS, SUPPORTED_FILTER_TYPES } from \"./constants\";\nimport type {\n CommonFilter,\n EditableFilter,\n NodeFilter,\n Operand,\n PlAdvancedFilterColumnId,\n RootFilter,\n SourceOptionInfo,\n} from \"./types\";\nimport { createNewGroup, getNewId, isValidColumnId } from \"./utils\";\n\nconst props = withDefaults(\n defineProps<{\n filters: T;\n onUpdateFilters: (filters: T) => void;\n /** List of ids of sources (columns, axes) that can be selected in filters */\n options: SourceOptionInfo[];\n /** List of supported filter types */\n supportedFilters?: typeof SUPPORTED_FILTER_TYPES;\n /** If true - new filter can be added by droppind element into filter group; else new column is added by button click */\n enableDnd?: boolean;\n /** If true - \"Add group\" button is shown below the filter groups */\n enableAddGroupButton?: boolean;\n /** If true - eye icon is shown per group to toggle suppression */\n enableToggling?: boolean;\n /** Function to determine if a filter is pinned */\n isPinned?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is removable */\n isRemovable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a filter is draggable */\n isDraggable?: (item: NodeFilter, index: number) => boolean;\n /** Function to determine if a group is complete */\n isCompletedGroup?: (group: NodeFilter, index: number) => boolean;\n /** Loading function for unique values for Equal/InSet filters and fixed axes options. */\n getSuggestOptions: (params: {\n columnId: PlAdvancedFilterColumnId;\n axisIdx?: number;\n searchStr: string;\n searchType: \"value\" | \"label\";\n }) => ListOptionBase<string | number>[] | Promise<ListOptionBase<string | number>[]>;\n }>(),\n {\n supportedFilters: () => SUPPORTED_FILTER_TYPES,\n isCompletedGroup: () => false,\n isPinned: () => false,\n isRemovable: () => true,\n isDraggable: () => true,\n\n getSuggestModel: undefined,\n\n enableDnd: false,\n enableAddGroupButton: false,\n enableToggling: false,\n },\n);\nconst produceFiltersUpdate = (updater: (draft: T) => void) => {\n props.onUpdateFilters(produce(props.filters, updater));\n};\n\nconst firstColumnId = computed(() => props.options[0]?.id);\nconst emptyGroup: NodeFilter[] = [\n {\n id: -1,\n type: \"and\",\n filters: [],\n isExpanded: true,\n },\n];\n\nconst rootFilters = computed({\n get: () => props.filters.filters,\n set: (filters) => props.onUpdateFilters({ ...props.filters, filters: filters }),\n});\n\nfunction getRootGroups() {\n if (props.filters.type !== \"or\" && props.filters.type !== \"and\") {\n throw new Error('Invalid model structure, expected root to be \"or\" or \"and\" group');\n }\n return props.filters.filters;\n}\n\nfunction getDraftGroupContent(\n draft: RootFilter,\n idx: number,\n): Exclude<NodeFilter, { type: \"not\" }> {\n const group = draft.filters[idx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n return group.filter;\n }\n if (group.type !== \"and\" && group.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n return group;\n}\n\nfunction getNotContent<T extends CommonFilter>(item: T): Exclude<T, { type: \"not\" }> {\n return item.type === \"not\"\n ? (item.filter as Exclude<T, { type: \"not\" }>)\n : (item as Exclude<T, { type: \"not\" }>);\n}\n\nfunction addColumnToGroup(groupIdx: number, selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n group.filters.push({\n ...DEFAULT_FILTERS[DEFAULT_FILTER_TYPE],\n column: selectedSourceId,\n id: getNewId(),\n isExpanded: true,\n } as CommonFilter);\n });\n}\n\nfunction removeFilterFromGroup(groupIdx: number, filterIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = getDraftGroupContent(draft, groupIdx);\n const removingLastLeaf = group.filters.length === 1 && filterIdx === 0;\n\n if (removingLastLeaf && props.isRemovable(draft.filters[groupIdx], groupIdx)) {\n draft.filters.splice(groupIdx, 1);\n } else {\n group.filters.splice(filterIdx, 1);\n }\n });\n}\n\nfunction inverseRootNode(groupIdx: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n const group = draft.filters[groupIdx];\n if (group.type === \"not\") {\n if (group.filter.type !== \"and\" && group.filter.type !== \"or\") {\n throw new Error('Invalid group structure, expected \"and\" or \"or\" group inside \"not\"');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n ...group.filter,\n };\n } else {\n const type = draft.filters[groupIdx].type;\n if (type !== \"and\" && type !== \"or\" && type !== \"not\") {\n throw new Error('Invalid group structure, expected \"and\", \"or\" or \"not\" group');\n }\n draft.filters[groupIdx] = {\n ...draft.filters[groupIdx],\n id: getNewId(),\n type: \"not\",\n filter: draft.filters[groupIdx],\n };\n }\n });\n}\n\nfunction addGroup(selectedSourceId: PlAdvancedFilterColumnId) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters.push(createNewGroup(selectedSourceId));\n });\n}\n\nfunction updateFilter(groupIdx: number, filterIdx: number, updatedFilter: EditableFilter) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, groupIdx).filters[filterIdx] = updatedFilter as CommonFilter;\n });\n}\n\nfunction handleDropToExistingGroup(groupIdx: number, event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addColumnToGroup(groupIdx, draggedId);\n }\n }\n}\n\nfunction handleDropToNewGroup(event: DragEvent) {\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.getData(\"text/plain\")) {\n const draggedId = dataTransfer.getData(\"text/plain\");\n if (isValidColumnId(draggedId)) {\n addGroup(draggedId);\n }\n }\n}\n\nfunction dragOver(event: DragEvent) {\n event.preventDefault();\n}\n\nfunction toggleExpand(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isExpanded = !draft.filters[index].isExpanded;\n });\n}\n\nfunction toggleSuppress(_: NodeFilter, index: number) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.filters[index].isSuppressed = !draft.filters[index].isSuppressed;\n });\n}\n\nfunction changeGroupOperand(index: number, v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n getDraftGroupContent(draft, index).type = v;\n });\n}\n\nfunction changeRootOperand(v: Operand) {\n produceFiltersUpdate((draft: RootFilter) => {\n draft.type = v;\n });\n}\n\nfunction validateFilter<T extends CommonFilter>(item: T): EditableFilter {\n if (item.type === \"and\" || item.type === \"or\" || item.type === \"not\") {\n throw new Error(\"Invalid filter structure, expected leaf filter\");\n }\n\n return item as EditableFilter;\n}\n</script>\n<template>\n <div>\n <PlElementList\n v-model:items=\"rootFilters\"\n :get-item-key=\"(filter) => filter.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"(filter) => filter.isExpanded === true\"\n :on-expand=\"toggleExpand\"\n :is-toggled=\"(item) => item.isSuppressed === true\"\n :on-toggle=\"toggleSuppress\"\n :is-pinned=\"(item, index) => props.isPinned?.(item, index) === true\"\n :is-pinnable=\"() => false\"\n :is-removable=\"(item, index) => props.isRemovable?.(item, index) === true\"\n :is-draggable=\"(item, index) => props.isDraggable?.(item, index) === true\"\n :disable-toggling=\"props.enableToggling !== true\"\n :disable-dragging=\"false\"\n :disable-removing=\"false\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index\">Filter group</slot>\n </template>\n <template #item-content=\"{ item, index }\">\n <div\n :class=\"[$style.groupContent, { [$style.suppressedLabel]: item.isSuppressed }]\"\n dropzone=\"true\"\n @drop=\"(event) => handleDropToExistingGroup(index, event)\"\n @dragover=\"dragOver\"\n >\n <PlCheckbox\n :model-value=\"item.type === 'not'\"\n :class=\"$style.notCheckbox\"\n @update:model-value=\"inverseRootNode(index)\"\n >\n Filter Out\n </PlCheckbox>\n <template v-for=\"(_, filterIdx) in getNotContent(item).filters\" :key=\"filterIdx\">\n <FilterEditor\n :filter=\"validateFilter(getNotContent(item).filters[filterIdx])\"\n :operand=\"getNotContent(item).type\"\n :column-options=\"options\"\n :supported-filters=\"props.supportedFilters\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :enable-dnd=\"Boolean(props.enableDnd)\"\n :is-last=\"filterIdx === getNotContent(item).filters.length - 1\"\n @delete=\"() => removeFilterFromGroup(index, filterIdx)\"\n @update-filter=\"(value) => updateFilter(index, filterIdx, value)\"\n @change-operand=\"(v) => changeGroupOperand(index, v)\"\n />\n </template>\n <div v-if=\"props.enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <PlBtnSecondary\n v-else-if=\"!props.isCompletedGroup(item, index)\"\n icon=\"add\"\n @click=\"addColumnToGroup(index, firstColumnId)\"\n >\n Add filter\n </PlBtnSecondary>\n </div>\n </template>\n <template #item-after=\"{ index }\">\n <OperandButton\n v-if=\"props.enableAddGroupButton || index < getRootGroups().length - 1\"\n :class=\"$style.buttonWrapper\"\n :active=\"props.filters.type\"\n :disabled=\"index === getRootGroups().length - 1\"\n :on-select=\"changeRootOperand\"\n />\n </template>\n </PlElementList>\n\n <!-- Last group - always empty, just for adding new groups -->\n <PlElementList\n v-if=\"props.enableAddGroupButton\"\n :items=\"emptyGroup\"\n :get-item-key=\"(group) => group.id\"\n :item-class=\"$style.filterGroup\"\n :item-class-content=\"$style.filterGroupContent\"\n :item-class-title=\"$style.filterGroupTitle\"\n :is-expanded=\"() => true\"\n :disableDragging=\"true\"\n :disableRemoving=\"true\"\n :disableToggling=\"true\"\n :disablePinning=\"true\"\n dropzone=\"true\"\n @drop=\"handleDropToNewGroup\"\n @dragover=\"dragOver\"\n >\n <template #item-title=\"{ item, index }\">\n <slot name=\"group-title\" :item=\"item\" :index=\"index + getRootGroups().length\"\n >Filter group</slot\n >\n </template>\n <template #item-content>\n <div v-if=\"enableDnd\" :class=\"$style.dropzone\">\n <div>Drop dimensions here</div>\n </div>\n <slot v-else name=\"add-group-buttons\">\n <PlBtnSecondary icon=\"add\" @click=\"addGroup(firstColumnId)\"> Add filter </PlBtnSecondary>\n </slot>\n </template>\n </PlElementList>\n </div>\n</template>\n<style module>\n.filterGroup {\n background: var(--bg-base-light);\n}\n.filterGroup:hover {\n background: rgba(99, 224, 36, 0.12);\n}\n.filterGroupTitle {\n background: none;\n}\n.filterGroupContent {\n padding: 4px 24px 24px 24px;\n}\n.groupContent {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.notCheckbox {\n margin: 4px 0;\n}\n.suppressedLabel {\n filter: grayscale(100%);\n pointer-events: none;\n}\n.dropzone {\n border-radius: 6px;\n border: 1.5px dashed var(--color-div-grey);\n color: var(--txt-03);\n font-family: Manrope;\n font-size: 14px;\n font-style: normal;\n font-weight: 500;\n height: 40px;\n cursor: default;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n.buttonWrapper {\n margin-top: 8px;\n height: 56px;\n display: flex;\n align-items: center;\n}\n:global(.sortable-chosen) .buttonWrapper {\n visibility: hidden;\n}\n</style>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlAnnotations.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../../src/components/PlAnnotations/components/PlAnnotations.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { Props as BaseProps } from \"./FilterSidebar.vue\";\nexport type Props = Omit<BaseProps, \"step\" | \"onUpdateStep\"> & {\n annotation: Annotation;\n onUpdateAnnotation: (annotation: Annotation) => void;\n onDeleteSchema?: () => void;\n};\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, effect, shallowRef } from \"vue\";\n\nimport { isNil } from \"@milaboratories/helpers\";\nimport { produce } from \"immer\";\nimport { PlSidebarGroup, useConfirm } from \"@milaboratories/uikit\";\n\nimport type { Annotation, Filter } from \"../types\";\nimport AnnotationsSidebar from \"./AnnotationsSidebar.vue\";\nimport FilterSidebar from \"./FilterSidebar.vue\";\n\nconst props = defineProps<Props>();\n\nconst selectedStepId = shallowRef<undefined | number>(undefined);\n\nconst selectedStep = computed(() => {\n return isNil(selectedStepId.value) || isNil(props.annotation)\n ? undefined\n : props.annotation.steps.find((step) => step.id === selectedStepId.value);\n});\n\neffect(function setDefaultStepId() {\n if (selectedStepId.value === undefined && props.annotation.steps.length > 0) {\n selectedStepId.value = props.annotation.steps[0].id;\n }\n});\n\nconst confirmResetSchema = useConfirm({\n title: \"Reset Schema\",\n message: \"Are you sure you want to reset the schema? This action cannot be undone.\",\n confirmLabel: \"Yes, reset\",\n cancelLabel: \"No, cancel\",\n});\n\nasync function handleDeleteSchema() {\n if (await confirmResetSchema()) {\n selectedStepId.value = undefined;\n props.onDeleteSchema?.();\n }\n}\n\nfunction updateSelectedStepId(id: undefined | number) {\n selectedStepId.value = id;\n}\n\nfunction updateSelectedStep(step: Filter) {\n props.onUpdateAnnotation(\n produce(props.annotation, (draft) => {\n const idx = draft.steps.findIndex((s) => s.id === step.id);\n if (idx !== -1) {\n draft.steps[idx] = step;\n }\n }),\n );\n}\n</script>\n\n<template>\n <PlSidebarGroup>\n <template #item-0>\n <AnnotationsSidebar\n :annotation=\"props.annotation\"\n :selected-step-id=\"selectedStepId\"\n :on-update-annotation=\"props.onUpdateAnnotation\"\n :on-update-selected-step-id=\"updateSelectedStepId\"\n :class=\"$style.sidebarItem\"\n @delete-schema=\"handleDeleteSchema\"\n />\n </template>\n <template #item-1>\n <FilterSidebar\n v-if=\"selectedStep\"\n :step=\"selectedStep\"\n :on-update-step=\"updateSelectedStep\"\n :class=\"$style.sidebarItem\"\n :columns=\"props.columns\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :hasSelectedColumns=\"props.hasSelectedColumns\"\n :getValuesForSelectedColumns=\"props.getValuesForSelectedColumns\"\n />\n </template>\n </PlSidebarGroup>\n</template>\n\n<style module>\n.sidebarItem {\n width: 100%;\n height: 100%;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAoBA,IAAM,IAAQ,GAER,IAAiB,EAA+B,KAAA,EAAU,EAE1D,IAAe,QACZ,EAAM,EAAe,MAAM,IAAI,EAAM,EAAM,WAAU,GACxD,KAAA,IACA,EAAM,WAAW,MAAM,MAAM,MAAS,EAAK,OAAO,EAAe,MAAM,CAC3E;AAEF,IAAO,WAA4B;AACjC,GAAI,EAAe,UAAU,KAAA,KAAa,EAAM,WAAW,MAAM,SAAS,MACxE,EAAe,QAAQ,EAAM,WAAW,MAAM,GAAG;IAEnD;EAEF,IAAM,IAAqB,EAAW;GACpC,OAAO;GACP,SAAS;GACT,cAAc;GACd,aAAa;GACd,CAAC;EAEF,eAAe,IAAqB;AAClC,GAAI,MAAM,GAAoB,KAC5B,EAAe,QAAQ,KAAA,GACvB,EAAM,kBAAkB;;EAI5B,SAAS,EAAqB,GAAwB;AACpD,KAAe,QAAQ;;EAGzB,SAAS,EAAmB,GAAc;AACxC,KAAM,mBACJ,EAAQ,EAAM,aAAa,MAAU;IACnC,IAAM,IAAM,EAAM,MAAM,WAAW,MAAM,EAAE,OAAO,EAAK,GAAG;AAC1D,IAAI,MAAQ,OACV,EAAM,MAAM,KAAO;KAErB,CACH;;yBAKD,EAuBiB,EAAA,EAAA,EAAA,MAAA;GAtBJ,UAAM,QAQb,CAPF,EAOE,GAAA;IANC,YAAY,EAAM;IAClB,oBAAkB,EAAA;IAClB,wBAAsB,EAAM;IAC5B,8BAA4B;IAC5B,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,gBAAe;;;;;;;GAGT,UAAM,
|
|
1
|
+
{"version":3,"file":"PlAnnotations.vue_vue_type_script_setup_true_lang.js","names":["$style"],"sources":["../../../../src/components/PlAnnotations/components/PlAnnotations.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { Props as BaseProps } from \"./FilterSidebar.vue\";\nexport type Props = Omit<BaseProps, \"step\" | \"onUpdateStep\"> & {\n annotation: Annotation;\n onUpdateAnnotation: (annotation: Annotation) => void;\n onDeleteSchema?: () => void;\n};\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, effect, shallowRef } from \"vue\";\n\nimport { isNil } from \"@milaboratories/helpers\";\nimport { produce } from \"immer\";\nimport { PlSidebarGroup, useConfirm } from \"@milaboratories/uikit\";\n\nimport type { Annotation, Filter } from \"../types\";\nimport AnnotationsSidebar from \"./AnnotationsSidebar.vue\";\nimport FilterSidebar from \"./FilterSidebar.vue\";\n\nconst props = defineProps<Props>();\n\nconst selectedStepId = shallowRef<undefined | number>(undefined);\n\nconst selectedStep = computed(() => {\n return isNil(selectedStepId.value) || isNil(props.annotation)\n ? undefined\n : props.annotation.steps.find((step) => step.id === selectedStepId.value);\n});\n\neffect(function setDefaultStepId() {\n if (selectedStepId.value === undefined && props.annotation.steps.length > 0) {\n selectedStepId.value = props.annotation.steps[0].id;\n }\n});\n\nconst confirmResetSchema = useConfirm({\n title: \"Reset Schema\",\n message: \"Are you sure you want to reset the schema? This action cannot be undone.\",\n confirmLabel: \"Yes, reset\",\n cancelLabel: \"No, cancel\",\n});\n\nasync function handleDeleteSchema() {\n if (await confirmResetSchema()) {\n selectedStepId.value = undefined;\n props.onDeleteSchema?.();\n }\n}\n\nfunction updateSelectedStepId(id: undefined | number) {\n selectedStepId.value = id;\n}\n\nfunction updateSelectedStep(step: Filter) {\n props.onUpdateAnnotation(\n produce(props.annotation, (draft) => {\n const idx = draft.steps.findIndex((s) => s.id === step.id);\n if (idx !== -1) {\n draft.steps[idx] = step;\n }\n }),\n );\n}\n</script>\n\n<template>\n <PlSidebarGroup>\n <template #item-0>\n <AnnotationsSidebar\n :annotation=\"props.annotation\"\n :selected-step-id=\"selectedStepId\"\n :on-update-annotation=\"props.onUpdateAnnotation\"\n :on-update-selected-step-id=\"updateSelectedStepId\"\n :class=\"$style.sidebarItem\"\n @delete-schema=\"handleDeleteSchema\"\n />\n </template>\n <template #item-1>\n <FilterSidebar\n v-if=\"selectedStep\"\n :step=\"selectedStep\"\n :on-update-step=\"updateSelectedStep\"\n :class=\"$style.sidebarItem\"\n :columns=\"props.columns\"\n :get-suggest-options=\"props.getSuggestOptions\"\n :hasSelectedColumns=\"props.hasSelectedColumns\"\n :getValuesForSelectedColumns=\"props.getValuesForSelectedColumns\"\n />\n </template>\n </PlSidebarGroup>\n</template>\n\n<style module>\n.sidebarItem {\n width: 100%;\n height: 100%;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAoBA,IAAM,IAAQ,GAER,IAAiB,EAA+B,KAAA,EAAU,EAE1D,IAAe,QACZ,EAAM,EAAe,MAAM,IAAI,EAAM,EAAM,WAAU,GACxD,KAAA,IACA,EAAM,WAAW,MAAM,MAAM,MAAS,EAAK,OAAO,EAAe,MAAM,CAC3E;AAEF,IAAO,WAA4B;AACjC,GAAI,EAAe,UAAU,KAAA,KAAa,EAAM,WAAW,MAAM,SAAS,MACxE,EAAe,QAAQ,EAAM,WAAW,MAAM,GAAG;IAEnD;EAEF,IAAM,IAAqB,EAAW;GACpC,OAAO;GACP,SAAS;GACT,cAAc;GACd,aAAa;GACd,CAAC;EAEF,eAAe,IAAqB;AAClC,GAAI,MAAM,GAAoB,KAC5B,EAAe,QAAQ,KAAA,GACvB,EAAM,kBAAkB;;EAI5B,SAAS,EAAqB,GAAwB;AACpD,KAAe,QAAQ;;EAGzB,SAAS,EAAmB,GAAc;AACxC,KAAM,mBACJ,EAAQ,EAAM,aAAa,MAAU;IACnC,IAAM,IAAM,EAAM,MAAM,WAAW,MAAM,EAAE,OAAO,EAAK,GAAG;AAC1D,IAAI,MAAQ,OACV,EAAM,MAAM,KAAO;KAErB,CACH;;yBAKD,EAuBiB,EAAA,EAAA,EAAA,MAAA;GAtBJ,UAAM,QAQb,CAPF,EAOE,GAAA;IANC,YAAY,EAAM;IAClB,oBAAkB,EAAA;IAClB,wBAAsB,EAAM;IAC5B,8BAA4B;IAC5B,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,gBAAe;;;;;;;GAGT,UAAM,QAiBZ,CAfK,EAAA,SAAA,GAAA,EADR,EASE,GAAA;;IAPC,MAAM,EAAA;IACN,kBAAgB;IAChB,OAAK,EAAEA,EAAAA,OAAO,YAAW;IACzB,SAAS,EAAM;IACf,uBAAqB,EAAM;IAC3B,oBAAoB,EAAM;IAC1B,6BAA6B,EAAM"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platforma-sdk/ui-vue",
|
|
3
|
-
"version": "1.80.
|
|
3
|
+
"version": "1.80.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"vue": "3.5.24",
|
|
28
28
|
"zod": "~3.25.76",
|
|
29
29
|
"@milaboratories/columns-collection-driver": "0.2.3",
|
|
30
|
+
"@milaboratories/pl-model-common": "1.47.3",
|
|
30
31
|
"@milaboratories/pf-spec-driver": "1.4.24",
|
|
31
|
-
"@platforma-sdk/model": "1.80.
|
|
32
|
-
"@milaboratories/uikit": "2.15.
|
|
33
|
-
"@milaboratories/pl-model-common": "1.47.3"
|
|
32
|
+
"@platforma-sdk/model": "1.80.13",
|
|
33
|
+
"@milaboratories/uikit": "2.15.19"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@faker-js/faker": "^9.2.0",
|
|
@@ -47,9 +47,9 @@
|
|
|
47
47
|
"vite": "^8.0.6",
|
|
48
48
|
"vitest": "^4.1.3",
|
|
49
49
|
"@milaboratories/build-configs": "2.0.0",
|
|
50
|
-
"@milaboratories/ts-
|
|
50
|
+
"@milaboratories/ts-builder": "1.6.1",
|
|
51
51
|
"@milaboratories/helpers": "1.14.5",
|
|
52
|
-
"@milaboratories/ts-
|
|
52
|
+
"@milaboratories/ts-configs": "1.3.1"
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
|
55
55
|
"dev": "ts-builder serve --target browser-lib",
|
|
@@ -125,7 +125,9 @@ function addColumnToGroup(groupIdx: number, selectedSourceId: PlAdvancedFilterCo
|
|
|
125
125
|
function removeFilterFromGroup(groupIdx: number, filterIdx: number) {
|
|
126
126
|
produceFiltersUpdate((draft: RootFilter) => {
|
|
127
127
|
const group = getDraftGroupContent(draft, groupIdx);
|
|
128
|
-
|
|
128
|
+
const removingLastLeaf = group.filters.length === 1 && filterIdx === 0;
|
|
129
|
+
|
|
130
|
+
if (removingLastLeaf && props.isRemovable(draft.filters[groupIdx], groupIdx)) {
|
|
129
131
|
draft.filters.splice(groupIdx, 1);
|
|
130
132
|
} else {
|
|
131
133
|
group.filters.splice(filterIdx, 1);
|