@platforma-sdk/ui-vue 1.45.37 → 1.45.45
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 +23 -39
- package/.turbo/turbo-type-check.log +1 -1
- package/CHANGELOG.md +19 -0
- package/dist/components/PlAdvancedFilter/{SingleFilter.vue.d.ts → FilterEditor.vue.d.ts} +12 -18
- package/dist/components/PlAdvancedFilter/FilterEditor.vue.js +10 -0
- package/dist/components/PlAdvancedFilter/FilterEditor.vue.js.map +1 -0
- package/dist/components/PlAdvancedFilter/FilterEditor.vue2.js +305 -0
- package/dist/components/PlAdvancedFilter/FilterEditor.vue2.js.map +1 -0
- package/dist/components/PlAdvancedFilter/FilterEditor.vue3.js +33 -0
- package/dist/components/PlAdvancedFilter/FilterEditor.vue3.js.map +1 -0
- package/dist/components/PlAdvancedFilter/OperandButton.vue2.js.map +1 -1
- package/dist/components/PlAdvancedFilter/OperandButton.vue3.js +9 -9
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue.d.ts +35 -16
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js +185 -145
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js.map +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue3.js +13 -9
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue3.js.map +1 -1
- package/dist/components/PlAdvancedFilter/constants.d.ts +4 -4
- package/dist/components/PlAdvancedFilter/constants.js +26 -22
- package/dist/components/PlAdvancedFilter/constants.js.map +1 -1
- package/dist/components/PlAdvancedFilter/index.d.ts +4 -0
- package/dist/components/PlAdvancedFilter/index.js +9 -0
- package/dist/components/PlAdvancedFilter/index.js.map +1 -0
- package/dist/components/PlAdvancedFilter/types.d.ts +30 -34
- package/dist/components/PlAdvancedFilter/utils.d.ts +26 -0
- package/dist/components/PlAdvancedFilter/utils.js +32 -131
- package/dist/components/PlAdvancedFilter/utils.js.map +1 -1
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue2.js +43 -41
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue2.js.map +1 -1
- package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue3.js +2 -2
- package/dist/components/PlAnnotations/components/FilterSidebar.vue.d.ts +14 -2
- package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js +99 -90
- package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js.map +1 -1
- package/dist/components/PlAnnotations/components/FilterSidebar.vue3.js +5 -5
- package/dist/components/PlAnnotations/components/PlAnnotations.vue2.js +32 -30
- package/dist/components/PlAnnotations/components/PlAnnotations.vue2.js.map +1 -1
- package/dist/components/PlAnnotations/components/PlAnnotations.vue3.js +5 -7
- package/dist/components/PlAnnotations/components/PlAnnotations.vue3.js.map +1 -1
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue2.js +26 -22
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue2.js.map +1 -1
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue3.js +7 -9
- package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue3.js.map +1 -1
- package/dist/components/PlAnnotations/components/style.module.css.js +13 -0
- package/dist/components/PlAnnotations/components/style.module.css.js.map +1 -0
- package/dist/components/PlAnnotations/index.d.ts +1 -0
- package/dist/index.js +35 -33
- package/dist/index.js.map +1 -1
- package/package.json +9 -8
- package/src/components/PlAdvancedFilter/{SingleFilter.vue → FilterEditor.vue} +53 -53
- package/src/components/PlAdvancedFilter/OperandButton.vue +1 -1
- package/src/components/PlAdvancedFilter/PlAdvancedFilter.vue +155 -59
- package/src/components/PlAdvancedFilter/constants.ts +17 -11
- package/src/components/PlAdvancedFilter/index.ts +6 -0
- package/src/components/PlAdvancedFilter/types.ts +23 -54
- package/src/components/PlAdvancedFilter/utils.ts +51 -163
- package/src/components/PlAnnotations/components/AnnotationsSidebar.vue +8 -8
- package/src/components/PlAnnotations/components/FilterSidebar.vue +64 -69
- package/src/components/PlAnnotations/components/PlAnnotations.vue +4 -7
- package/src/components/PlAnnotations/components/PlAnnotationsModal.vue +5 -8
- package/src/components/PlAnnotations/components/style.module.css +16 -0
- package/src/components/PlAnnotations/index.ts +2 -0
- package/dist/components/PlAdvancedFilter/SingleFilter.vue.js +0 -10
- package/dist/components/PlAdvancedFilter/SingleFilter.vue.js.map +0 -1
- package/dist/components/PlAdvancedFilter/SingleFilter.vue2.js +0 -306
- package/dist/components/PlAdvancedFilter/SingleFilter.vue2.js.map +0 -1
- package/dist/components/PlAdvancedFilter/SingleFilter.vue3.js +0 -35
- package/dist/components/PlAdvancedFilter/SingleFilter.vue3.js.map +0 -1
- package/dist/components/PlAdvancedFilter/types.js +0 -8
- package/dist/components/PlAdvancedFilter/types.js.map +0 -1
- package/dist/components/PlAnnotations/components/DynamicForm.vue.d.ts +0 -24
- package/dist/components/PlAnnotations/components/DynamicForm.vue.js +0 -10
- package/dist/components/PlAnnotations/components/DynamicForm.vue.js.map +0 -1
- package/dist/components/PlAnnotations/components/DynamicForm.vue2.js +0 -109
- package/dist/components/PlAnnotations/components/DynamicForm.vue2.js.map +0 -1
- package/dist/components/PlAnnotations/components/DynamicForm.vue3.js +0 -9
- package/dist/components/PlAnnotations/components/DynamicForm.vue3.js.map +0 -1
- package/dist/components/PlAnnotations/utils.js +0 -20
- package/dist/components/PlAnnotations/utils.js.map +0 -1
|
@@ -1,59 +1,131 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import
|
|
3
|
-
import { PlBtnSecondary, PlElementList, PlCheckbox, PlIcon16 } from '@milaboratories/uikit';
|
|
4
|
-
import type { PlAdvancedFilterColumnId, CommonFilterSpec, Group, PlAdvancedFilterUI, SourceOptionInfo } from './types';
|
|
5
|
-
import { computed } from 'vue';
|
|
6
|
-
import OperandButton from './OperandButton.vue';
|
|
7
|
-
import { DEFAULT_FILTER_TYPE, DEFAULT_FILTERS } from './constants';
|
|
2
|
+
import { PlBtnSecondary, PlCheckbox, PlElementList } from '@milaboratories/uikit';
|
|
8
3
|
import type { ListOptionBase } from '@platforma-sdk/model';
|
|
9
|
-
import {
|
|
4
|
+
import { computed, toRaw } from 'vue';
|
|
5
|
+
import FilterEditor from './FilterEditor.vue';
|
|
6
|
+
import OperandButton from './OperandButton.vue';
|
|
7
|
+
import { DEFAULT_FILTER_TYPE, DEFAULT_FILTERS, SUPPORTED_FILTER_TYPES } from './constants';
|
|
8
|
+
import type { CommonFilter, EditableFilter, NodeFilter, PlAdvancedFilterColumnId, RootFilter, SourceOptionInfo } from './types';
|
|
9
|
+
import { createNewGroup, getNewId, isValidColumnId } from './utils';
|
|
10
|
+
|
|
11
|
+
const model = defineModel<RootFilter>('filters', { required: true });
|
|
10
12
|
|
|
11
13
|
const props = withDefaults(defineProps<{
|
|
12
14
|
/** List of ids of sources (columns, axes) that can be selected in filters */
|
|
13
15
|
items: SourceOptionInfo[];
|
|
16
|
+
/** List of supported filter types */
|
|
17
|
+
supportedFilters?: typeof SUPPORTED_FILTER_TYPES;
|
|
14
18
|
/** If true - new filter can be added by droppind element into filter group; else new column is added by button click */
|
|
15
19
|
enableDnd?: boolean;
|
|
20
|
+
/** If true - "Add group" button is shown below the filter groups */
|
|
21
|
+
enableAddGroupButton?: boolean;
|
|
16
22
|
/** Loading function for unique values for Equal/InSet filters and fixed axes options. */
|
|
17
|
-
getSuggestOptions: (params: { columnId: PlAdvancedFilterColumnId; searchStr: string; axisIdx?: number }) =>
|
|
18
|
-
|
|
23
|
+
getSuggestOptions: (params: { columnId: PlAdvancedFilterColumnId; searchStr: string; axisIdx?: number }) =>
|
|
24
|
+
ListOptionBase<string | number>[] | Promise<ListOptionBase<string | number>[]>;
|
|
19
25
|
/** Loading function for label of selected value for Equal/InSet filters and fixed axes options. */
|
|
20
|
-
getSuggestModel
|
|
21
|
-
|
|
22
|
-
}>(), {
|
|
26
|
+
getSuggestModel?: (params: { columnId: PlAdvancedFilterColumnId; searchStr: string; axisIdx?: number }) =>
|
|
27
|
+
ListOptionBase<string | number> | Promise<ListOptionBase<string | number>>;
|
|
28
|
+
}>(), {
|
|
29
|
+
supportedFilters: () => SUPPORTED_FILTER_TYPES,
|
|
30
|
+
getSuggestModel: undefined,
|
|
23
31
|
|
|
24
|
-
|
|
25
|
-
|
|
32
|
+
enableDnd: false,
|
|
33
|
+
enableAddGroupButton: false,
|
|
34
|
+
});
|
|
26
35
|
|
|
27
36
|
const firstColumnId = computed(() => props.items[0]?.id);
|
|
28
|
-
const emptyGroup:
|
|
29
|
-
id:
|
|
30
|
-
|
|
31
|
-
operand: 'and',
|
|
37
|
+
const emptyGroup: NodeFilter[] = [{
|
|
38
|
+
id: -1,
|
|
39
|
+
type: 'and',
|
|
32
40
|
filters: [],
|
|
33
|
-
|
|
41
|
+
isExpanded: true,
|
|
34
42
|
}];
|
|
35
43
|
|
|
44
|
+
function getRootGroups() {
|
|
45
|
+
if (model.value.type !== 'or' && model.value.type !== 'and') {
|
|
46
|
+
throw new Error('Invalid model structure, expected root to be "or" or "and" group');
|
|
47
|
+
}
|
|
48
|
+
return model.value.filters;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getRootGroup(idx: number): NodeFilter {
|
|
52
|
+
const groups = getRootGroups();
|
|
53
|
+
const group = groups[idx];
|
|
54
|
+
if (group.type !== 'and' && group.type !== 'or' && group.type !== 'not') {
|
|
55
|
+
throw new Error('Invalid group structure, expected "and", "or" or "not" group');
|
|
56
|
+
}
|
|
57
|
+
return group;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function getRootGroupContent(idx: number): Exclude<NodeFilter, { type: 'not' }> {
|
|
61
|
+
const group = getRootGroup(idx);
|
|
62
|
+
|
|
63
|
+
if (group.type !== 'not') {
|
|
64
|
+
return group;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (group.filter.type !== 'and' && group.filter.type !== 'or') {
|
|
68
|
+
throw new Error('Invalid group structure, expected "and" or "or" group inside "not"');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return group.filter;
|
|
72
|
+
}
|
|
73
|
+
|
|
36
74
|
function addColumnToGroup(groupIdx: number, selectedSourceId: PlAdvancedFilterColumnId) {
|
|
37
|
-
|
|
75
|
+
const group = getRootGroupContent(groupIdx);
|
|
76
|
+
|
|
77
|
+
group.filters.push({
|
|
38
78
|
...DEFAULT_FILTERS[DEFAULT_FILTER_TYPE],
|
|
39
79
|
column: selectedSourceId,
|
|
40
|
-
|
|
80
|
+
id: getNewId(),
|
|
81
|
+
isExpanded: true,
|
|
82
|
+
} as CommonFilter);
|
|
41
83
|
}
|
|
42
84
|
|
|
43
85
|
function removeFilterFromGroup(groupIdx: number, filterIdx: number) {
|
|
44
|
-
|
|
86
|
+
const group = getRootGroupContent(groupIdx);
|
|
87
|
+
|
|
88
|
+
if (group.filters.length === 1 && filterIdx === 0) {
|
|
45
89
|
removeGroup(groupIdx);
|
|
46
90
|
} else {
|
|
47
|
-
|
|
91
|
+
group.filters.splice(filterIdx, 1);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function inverseRootNode(groupIdx: number) {
|
|
95
|
+
const groups = getRootGroups();
|
|
96
|
+
const group = groups[groupIdx];
|
|
97
|
+
if (group.type === 'not') {
|
|
98
|
+
if (group.filter.type !== 'and' && group.filter.type !== 'or') {
|
|
99
|
+
throw new Error('Invalid group structure, expected "and" or "or" group inside "not"');
|
|
100
|
+
}
|
|
101
|
+
groups[groupIdx] = group.filter;
|
|
102
|
+
} else {
|
|
103
|
+
const type = groups[groupIdx].type;
|
|
104
|
+
if (type !== 'and' && type !== 'or' && type !== 'not') {
|
|
105
|
+
throw new Error('Invalid group structure, expected "and", "or" or "not" group');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
groups[groupIdx] = {
|
|
109
|
+
id: getNewId(),
|
|
110
|
+
isExpanded: true,
|
|
111
|
+
type: 'not',
|
|
112
|
+
filter: groups[groupIdx],
|
|
113
|
+
};
|
|
48
114
|
}
|
|
49
115
|
}
|
|
50
116
|
|
|
117
|
+
function getNotContent<T extends CommonFilter>(item: T): Exclude<T, { type: 'not' }> {
|
|
118
|
+
return item.type === 'not' ? item.filter as Exclude<T, { type: 'not' }> : item as Exclude<T, { type: 'not' }>;
|
|
119
|
+
}
|
|
120
|
+
|
|
51
121
|
function removeGroup(groupIdx: number) {
|
|
52
|
-
|
|
122
|
+
const groups = getRootGroups();
|
|
123
|
+
groups.splice(groupIdx, 1);
|
|
53
124
|
}
|
|
54
125
|
function addGroup(selectedSourceId: PlAdvancedFilterColumnId) {
|
|
55
126
|
const newGroup = createNewGroup(selectedSourceId);
|
|
56
|
-
|
|
127
|
+
const groups = getRootGroups();
|
|
128
|
+
groups.push(newGroup);
|
|
57
129
|
}
|
|
58
130
|
|
|
59
131
|
function handleDropToExistingGroup(groupIdx: number, event: DragEvent) {
|
|
@@ -77,70 +149,86 @@ function handleDropToNewGroup(event: DragEvent) {
|
|
|
77
149
|
function dragOver(event: DragEvent) {
|
|
78
150
|
event.preventDefault();
|
|
79
151
|
}
|
|
152
|
+
|
|
153
|
+
function validateFilter<T extends CommonFilter>(item: T): EditableFilter {
|
|
154
|
+
if (item.type === 'and' || item.type === 'or' || item.type === 'not') {
|
|
155
|
+
throw new Error('Invalid filter structure, expected leaf filter');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return item as EditableFilter;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function updateFilter(filters: CommonFilter[], idx: number, updatedFilter: EditableFilter) {
|
|
162
|
+
filters[idx] = toRaw(updatedFilter as CommonFilter);
|
|
163
|
+
}
|
|
80
164
|
</script>
|
|
81
165
|
<template>
|
|
82
166
|
<div>
|
|
83
167
|
<PlElementList
|
|
84
|
-
v-model:items="
|
|
85
|
-
:get-item-key="(
|
|
168
|
+
v-model:items="model.filters"
|
|
169
|
+
:get-item-key="(filter) => filter.id"
|
|
86
170
|
|
|
87
171
|
:item-class="$style.filterGroup"
|
|
88
172
|
:item-class-content="$style.filterGroupContent"
|
|
89
173
|
:item-class-title="$style.filterGroupTitle"
|
|
90
174
|
|
|
91
|
-
:is-expanded="(
|
|
175
|
+
:is-expanded="(filter) => filter.isExpanded === true"
|
|
176
|
+
:on-expand="(group) => { group.isExpanded = !group.isExpanded}"
|
|
92
177
|
|
|
93
178
|
:disableDragging="false"
|
|
94
179
|
:disableRemoving="false"
|
|
95
180
|
:disableToggling="true"
|
|
96
181
|
:disablePinning="true"
|
|
97
|
-
|
|
98
|
-
:on-expand="(group) => { group.expanded = !group.expanded}"
|
|
99
182
|
>
|
|
100
183
|
<template #item-title>
|
|
101
184
|
Filter group
|
|
102
185
|
</template>
|
|
103
186
|
<template #item-content="{ item, index }">
|
|
104
187
|
<div
|
|
105
|
-
:class="$style.groupContent"
|
|
188
|
+
:class="$style.groupContent"
|
|
189
|
+
dropzone="true"
|
|
106
190
|
@drop="(event) => handleDropToExistingGroup(index, event)"
|
|
107
191
|
@dragover="dragOver"
|
|
108
192
|
>
|
|
109
|
-
<PlCheckbox
|
|
110
|
-
<
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
193
|
+
<PlCheckbox :model-value="item.type === 'not'" :class="$style.notCheckbox" @update:model-value="inverseRootNode(index)">NOT</PlCheckbox>
|
|
194
|
+
<template v-for="(_, filterIdx) in getNotContent(item).filters" :key="filterIdx">
|
|
195
|
+
<FilterEditor
|
|
196
|
+
:filter="validateFilter(getNotContent(item).filters[filterIdx])"
|
|
197
|
+
:operand="getNotContent(item).type"
|
|
198
|
+
:column-options="items"
|
|
199
|
+
:supported-filters="props.supportedFilters"
|
|
200
|
+
:get-suggest-model="props.getSuggestModel"
|
|
201
|
+
:get-suggest-options="props.getSuggestOptions"
|
|
202
|
+
:enable-dnd="Boolean(props.enableDnd)"
|
|
203
|
+
:is-last="filterIdx === getNotContent(item).filters.length - 1"
|
|
204
|
+
:on-change-operand="(v) => getNotContent(item).type = v"
|
|
205
|
+
:on-delete="() => removeFilterFromGroup(index, filterIdx)"
|
|
206
|
+
@update:filter="(value) => updateFilter(getNotContent(item).filters, filterIdx, value)"
|
|
207
|
+
/>
|
|
208
|
+
</template>
|
|
209
|
+
<div v-if="props.enableDnd" :class="$style.dropzone">
|
|
124
210
|
<div>Drop dimensions here</div>
|
|
125
211
|
</div>
|
|
126
|
-
<PlBtnSecondary v-else @click="addColumnToGroup(index, firstColumnId)">
|
|
127
|
-
|
|
212
|
+
<PlBtnSecondary v-else icon="add" @click="addColumnToGroup(index, firstColumnId)">
|
|
213
|
+
Add filter
|
|
128
214
|
</PlBtnSecondary>
|
|
129
215
|
</div>
|
|
130
216
|
</template>
|
|
131
217
|
<template #item-after="{ index }">
|
|
132
218
|
<OperandButton
|
|
219
|
+
v-if="props.enableAddGroupButton || index < getRootGroups().length - 1"
|
|
133
220
|
:class="$style.buttonWrapper"
|
|
134
|
-
:active="
|
|
135
|
-
:disabled="index ===
|
|
136
|
-
:on-select="(v) =>
|
|
221
|
+
:active="model.type"
|
|
222
|
+
:disabled="index === getRootGroups().length - 1"
|
|
223
|
+
:on-select="(v) => model.type = v"
|
|
137
224
|
/>
|
|
138
225
|
</template>
|
|
139
226
|
</PlElementList>
|
|
140
227
|
|
|
141
|
-
<!-- Last group - always
|
|
228
|
+
<!-- Last group - always empty, just for adding new groups -->
|
|
142
229
|
<PlElementList
|
|
143
|
-
v-
|
|
230
|
+
v-if="props.enableAddGroupButton"
|
|
231
|
+
:items="emptyGroup"
|
|
144
232
|
:get-item-key="(group) => group.id"
|
|
145
233
|
:item-class="$style.filterGroup"
|
|
146
234
|
:item-class-content="$style.filterGroupContent"
|
|
@@ -157,14 +245,15 @@ function dragOver(event: DragEvent) {
|
|
|
157
245
|
@dragover="dragOver"
|
|
158
246
|
>
|
|
159
247
|
<template #item-title>Filter group</template>
|
|
160
|
-
<template #item-content
|
|
161
|
-
<PlCheckbox v-model="item.not" disabled >NOT</PlCheckbox>
|
|
248
|
+
<template #item-content>
|
|
162
249
|
<div v-if="enableDnd" :class="$style.dropzone">
|
|
163
250
|
<div>Drop dimensions here</div>
|
|
164
251
|
</div>
|
|
165
|
-
<
|
|
166
|
-
<
|
|
167
|
-
|
|
252
|
+
<slot v-else name="add-group-buttons">
|
|
253
|
+
<PlBtnSecondary icon="add" @click="addGroup(firstColumnId)">
|
|
254
|
+
Add filter
|
|
255
|
+
</PlBtnSecondary>
|
|
256
|
+
</slot>
|
|
168
257
|
</template>
|
|
169
258
|
</PlElementList>
|
|
170
259
|
</div>
|
|
@@ -179,11 +268,17 @@ function dragOver(event: DragEvent) {
|
|
|
179
268
|
.filterGroupTitle {
|
|
180
269
|
background: none;
|
|
181
270
|
}
|
|
271
|
+
.filterGroupContent {
|
|
272
|
+
padding: 4px 24px 24px 24px;
|
|
273
|
+
}
|
|
182
274
|
.groupContent {
|
|
183
275
|
display: flex;
|
|
184
276
|
flex-direction: column;
|
|
185
277
|
gap: 12px;
|
|
186
278
|
}
|
|
279
|
+
.notCheckbox {
|
|
280
|
+
margin: 4px 0;
|
|
281
|
+
}
|
|
187
282
|
.dropzone {
|
|
188
283
|
border-radius: 6px;
|
|
189
284
|
border: 1.5px dashed var(--color-div-grey);
|
|
@@ -199,7 +294,8 @@ function dragOver(event: DragEvent) {
|
|
|
199
294
|
align-items: center;
|
|
200
295
|
}
|
|
201
296
|
.buttonWrapper {
|
|
202
|
-
|
|
297
|
+
margin-top: 8px;
|
|
298
|
+
height: 56px;
|
|
203
299
|
display: flex;
|
|
204
300
|
align-items: center;
|
|
205
301
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FilterSpecType } from '@platforma-sdk/model';
|
|
2
|
+
import type { EditableFilter, PlAdvancedFilterColumnId, SupportedFilterTypes } from './types';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
// List of ALL supported filter types in Advanced Filter component
|
|
5
|
+
export const SUPPORTED_FILTER_TYPES = [
|
|
4
6
|
'isNA',
|
|
5
7
|
'isNotNA',
|
|
6
8
|
'greaterThan',
|
|
@@ -17,26 +19,30 @@ export const SUPPORTED_FILTER_TYPES = new Set<SupportedFilterTypes>([
|
|
|
17
19
|
'patternMatchesRegularExpression',
|
|
18
20
|
'inSet',
|
|
19
21
|
'notInSet',
|
|
20
|
-
|
|
22
|
+
'topN',
|
|
23
|
+
'bottomN',
|
|
24
|
+
] satisfies FilterSpecType[];
|
|
21
25
|
|
|
22
|
-
export const DEFAULT_FILTER_TYPE:
|
|
26
|
+
export const DEFAULT_FILTER_TYPE: SupportedFilterTypes = 'isNA';
|
|
23
27
|
|
|
24
28
|
const emptyCommonPart = { column: '' as PlAdvancedFilterColumnId };
|
|
25
|
-
export const DEFAULT_FILTERS: Record<SupportedFilterTypes,
|
|
29
|
+
export const DEFAULT_FILTERS: Record<SupportedFilterTypes, EditableFilter> = {
|
|
26
30
|
isNA: { type: 'isNA', ...emptyCommonPart },
|
|
27
31
|
isNotNA: { type: 'isNotNA', ...emptyCommonPart },
|
|
28
|
-
lessThan: { type: 'lessThan', x:
|
|
29
|
-
lessThanOrEqual: { type: 'lessThanOrEqual', x:
|
|
32
|
+
lessThan: { type: 'lessThan', x: 0, ...emptyCommonPart },
|
|
33
|
+
lessThanOrEqual: { type: 'lessThanOrEqual', x: 0, ...emptyCommonPart },
|
|
30
34
|
patternEquals: { type: 'patternEquals', value: undefined, ...emptyCommonPart },
|
|
31
35
|
patternNotEquals: { type: 'patternNotEquals', value: undefined, ...emptyCommonPart },
|
|
32
|
-
greaterThan: { type: 'greaterThan', x:
|
|
33
|
-
greaterThanOrEqual: { type: 'greaterThanOrEqual', x:
|
|
36
|
+
greaterThan: { type: 'greaterThan', x: 0, ...emptyCommonPart },
|
|
37
|
+
greaterThanOrEqual: { type: 'greaterThanOrEqual', x: 0, ...emptyCommonPart },
|
|
34
38
|
patternContainSubsequence: { type: 'patternContainSubsequence', value: '', ...emptyCommonPart },
|
|
35
39
|
patternNotContainSubsequence: { type: 'patternNotContainSubsequence', value: '', ...emptyCommonPart },
|
|
36
40
|
patternFuzzyContainSubsequence: { type: 'patternFuzzyContainSubsequence', maxEdits: 2, substitutionsOnly: false, wildcard: undefined, value: '', ...emptyCommonPart },
|
|
37
41
|
patternMatchesRegularExpression: { type: 'patternMatchesRegularExpression', value: '', ...emptyCommonPart },
|
|
38
|
-
equal: { type: 'equal', x:
|
|
39
|
-
notEqual: { type: 'notEqual', x:
|
|
42
|
+
equal: { type: 'equal', x: 0, ...emptyCommonPart },
|
|
43
|
+
notEqual: { type: 'notEqual', x: 0, ...emptyCommonPart },
|
|
40
44
|
inSet: { type: 'inSet', value: [], ...emptyCommonPart },
|
|
41
45
|
notInSet: { type: 'notInSet', value: [], ...emptyCommonPart },
|
|
46
|
+
topN: { type: 'topN', n: 10, ...emptyCommonPart },
|
|
47
|
+
bottomN: { type: 'bottomN', n: 10, ...emptyCommonPart },
|
|
42
48
|
};
|
|
@@ -1 +1,7 @@
|
|
|
1
|
+
import { SUPPORTED_FILTER_TYPES } from './constants.ts';
|
|
2
|
+
import type { RootFilter, SourceOptionInfo } from './types.ts';
|
|
3
|
+
|
|
1
4
|
export { default as PlAdvancedFilter } from './PlAdvancedFilter.vue';
|
|
5
|
+
export const PlAdvancedFilterSupportedFilters = SUPPORTED_FILTER_TYPES;
|
|
6
|
+
export type PlAdvancedFilterItem = SourceOptionInfo;
|
|
7
|
+
export type PlAdvancedFilterFilter = RootFilter;
|
|
@@ -1,67 +1,36 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { SUPPORTED_FILTER_TYPES } from './constants';
|
|
3
|
-
import type { CanonicalizedJson } from '@platforma-sdk/model';
|
|
4
|
-
import type { AxisId } from '@platforma-sdk/model';
|
|
1
|
+
import type { AxisId, AxisSpec, CanonicalizedJson, FilterSpec, FilterSpecLeaf, PColumnSpec, SUniversalPColumnId } from '@platforma-sdk/model';
|
|
2
|
+
import type { SUPPORTED_FILTER_TYPES } from './constants';
|
|
5
3
|
|
|
6
|
-
export type
|
|
7
|
-
export type CommonFilterSpec = FilterSpec<FilterSpecLeaf<PlAdvancedFilterColumnId>, { expanded?: boolean }>;
|
|
8
|
-
|
|
9
|
-
// Not supported: topN, bottomN, lessThanColumn, lessThanColumnOrEqual
|
|
10
|
-
// or, and, not - in groups
|
|
11
|
-
export type SupportedFilterTypes = FilterSpecType &
|
|
12
|
-
'isNA' | 'isNotNA' |
|
|
13
|
-
'patternEquals' | 'patternNotEquals' |
|
|
14
|
-
'patternContainSubsequence' | 'patternNotContainSubsequence' |
|
|
15
|
-
'patternMatchesRegularExpression' |
|
|
16
|
-
'patternFuzzyContainSubsequence' |
|
|
17
|
-
'inSet' | 'notInSet' |
|
|
18
|
-
'equal' | 'notEqual' |
|
|
19
|
-
'lessThan' | 'lessThanOrEqual' |
|
|
20
|
-
'greaterThan' | 'greaterThanOrEqual';
|
|
21
|
-
|
|
22
|
-
export type FilterType = SupportedFilterTypes;
|
|
4
|
+
export type Operand = 'or' | 'and';
|
|
23
5
|
|
|
24
|
-
export
|
|
25
|
-
if (!type) {
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
return SUPPORTED_FILTER_TYPES.has(type as SupportedFilterTypes);
|
|
29
|
-
}
|
|
6
|
+
export type PlAdvancedFilterColumnId = SUniversalPColumnId | CanonicalizedJson<AxisId>;
|
|
30
7
|
|
|
31
|
-
export type
|
|
8
|
+
export type FilterLeafContent = Extract<FilterSpecLeaf<PlAdvancedFilterColumnId>, { type: SupportedFilterTypes }>;
|
|
9
|
+
export type CommonFilter = FilterSpec<FilterLeafContent, { id: number; isExpanded?: boolean }>;
|
|
10
|
+
export type FilterLeaf = Exclude<CommonFilter, { type: Operand | 'not' }>;
|
|
11
|
+
export type NodeFilter = Extract<CommonFilter, { type: Operand | 'not' }>;
|
|
12
|
+
export type RootFilter = Omit<Extract<NodeFilter, { type: Operand }>, 'filters'> & { filters: NodeFilter[] };
|
|
32
13
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
};
|
|
14
|
+
// Not supported: less(/greater)ThanColumn, less(/greater)ThanColumnOrEqual
|
|
15
|
+
// or, and, not - in groups
|
|
16
|
+
export type SupportedFilterTypes = typeof SUPPORTED_FILTER_TYPES[number];
|
|
37
17
|
|
|
38
18
|
type RequireFields<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
|
|
39
19
|
type OptionalFields<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
40
20
|
|
|
21
|
+
type NumericalWithOptionalN = 'topN' | 'bottomN';
|
|
41
22
|
type NumericalWithOptionalX = 'lessThan' | 'lessThanOrEqual' | 'greaterThan' | 'greaterThanOrEqual' | 'equal' | 'notEqual';
|
|
42
23
|
type StringWithOptionalValue = 'patternEquals' | 'patternNotEquals';
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
24
|
+
// types from ui with some changed by optionality fields
|
|
25
|
+
type EditedTypes = 'patternFuzzyContainSubsequence' | NumericalWithOptionalX | StringWithOptionalValue | NumericalWithOptionalN;
|
|
26
|
+
export type EditableFilter =
|
|
27
|
+
| Exclude<FilterLeafContent, { type: EditedTypes }>
|
|
28
|
+
| RequireFields<Extract<FilterLeafContent, { type: 'patternFuzzyContainSubsequence' }>, 'maxEdits' | 'substitutionsOnly'>
|
|
29
|
+
| OptionalFields<Extract<FilterLeafContent, { type: NumericalWithOptionalN }>, 'n'>
|
|
30
|
+
| OptionalFields<Extract<FilterLeafContent, { type: NumericalWithOptionalX }>, 'x'>
|
|
31
|
+
| OptionalFields<Extract<FilterLeafContent, { type: StringWithOptionalValue }>, 'value'>
|
|
48
32
|
;
|
|
49
33
|
|
|
50
|
-
export type Group = {
|
|
51
|
-
id: string;
|
|
52
|
-
not: boolean;
|
|
53
|
-
filters: Filter[];
|
|
54
|
-
operand: Operand;
|
|
55
|
-
expanded: boolean;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
export type PlAdvancedFilterUI = {
|
|
59
|
-
groups: Group[];
|
|
60
|
-
operand: Operand;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export type UniqueValuesList = ListOptionBase<string | number>[];
|
|
64
|
-
export type OptionInfo = { error: boolean; label: string; spec: PColumnSpec | AxisSpec };
|
|
65
34
|
export type FixedAxisInfo = {
|
|
66
35
|
idx: number;
|
|
67
36
|
label: string;
|
|
@@ -70,8 +39,8 @@ export type FixedAxisInfo = {
|
|
|
70
39
|
export type SourceOptionInfo = {
|
|
71
40
|
id: PlAdvancedFilterColumnId;
|
|
72
41
|
label: string;
|
|
73
|
-
error: boolean;
|
|
74
42
|
spec: PColumnSpec | AxisSpec;
|
|
75
|
-
|
|
43
|
+
error?: boolean;
|
|
76
44
|
alphabet?: 'nucleotide' | 'aminoacid' | string;
|
|
45
|
+
axesToBeFixed?: FixedAxisInfo[];
|
|
77
46
|
};
|