@platforma-sdk/ui-vue 1.13.18 → 1.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/lib.js +8569 -8356
  3. package/dist/lib.umd.cjs +37 -37
  4. package/dist/src/components/PlTableFilters/PlTableAddFilter.vue.d.ts +20 -0
  5. package/dist/src/components/PlTableFilters/PlTableAddFilter.vue.d.ts.map +1 -0
  6. package/dist/src/components/PlTableFilters/PlTableFilterEntry.vue.d.ts +16 -0
  7. package/dist/src/components/PlTableFilters/PlTableFilterEntry.vue.d.ts.map +1 -0
  8. package/dist/src/components/{PlAgDataTable → PlTableFilters}/PlTableFilters.vue.d.ts +2 -1
  9. package/dist/src/components/PlTableFilters/PlTableFilters.vue.d.ts.map +1 -0
  10. package/dist/src/components/PlTableFilters/filters_logic.d.ts +18 -0
  11. package/dist/src/components/PlTableFilters/filters_logic.d.ts.map +1 -0
  12. package/dist/src/components/PlTableFilters/index.d.ts +2 -0
  13. package/dist/src/components/PlTableFilters/index.d.ts.map +1 -0
  14. package/dist/src/lib.d.ts +2 -2
  15. package/dist/src/lib.d.ts.map +1 -1
  16. package/dist/style.css +1 -1
  17. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  18. package/package.json +3 -3
  19. package/src/components/PlAgDataTable/PlAgDataTable.vue +1 -1
  20. package/src/components/PlAgDataTable/pl-table-filters.scss +98 -0
  21. package/src/components/PlAgGridColumnManager/PlAgGridColumnManager.vue +1 -1
  22. package/src/components/PlTableFilters/PlTableAddFilter.vue +60 -0
  23. package/src/components/PlTableFilters/PlTableFilterEntry.vue +61 -0
  24. package/src/components/PlTableFilters/PlTableFilters.vue +249 -0
  25. package/src/components/PlTableFilters/filters_logic.ts +344 -0
  26. package/src/components/PlTableFilters/index.ts +1 -0
  27. package/src/components/PlTableFilters/pl-table-filters.scss +98 -0
  28. package/src/lib.ts +3 -2
  29. package/dist/src/components/PlAgDataTable/PlTableFilters.vue.d.ts.map +0 -1
  30. package/src/components/PlAgDataTable/PlTableFilters.vue +0 -559
@@ -0,0 +1,344 @@
1
+ import canonicalize from 'canonicalize';
2
+ import type {
3
+ SingleValuePredicateV2,
4
+ PlTableFilterType,
5
+ PlTableFilterNumberType,
6
+ PlTableFilterStringType,
7
+ PlTableFilter,
8
+ PTableColumnSpec,
9
+ PTableColumnId,
10
+ PlTableFiltersStateEntry,
11
+ PlTableFilterColumnId,
12
+ } from '@platforma-sdk/model';
13
+ import * as lodash from 'lodash';
14
+
15
+ export function makeColumnId(column: PTableColumnId | PTableColumnSpec): PlTableFilterColumnId {
16
+ return canonicalize(column.id)!;
17
+ }
18
+
19
+ export function getFilterLabel(type: PlTableFilterType): string {
20
+ switch (type) {
21
+ case 'isNotNA':
22
+ return 'Is not NA';
23
+ case 'isNA':
24
+ return 'Is NA';
25
+ case 'number_equals':
26
+ case 'string_equals':
27
+ return 'Equals';
28
+ case 'number_notEquals':
29
+ case 'string_notEquals':
30
+ return 'Not equals';
31
+ case 'number_greaterThan':
32
+ return 'Greater than';
33
+ case 'number_greaterThanOrEqualTo':
34
+ return 'Greater than or equal to';
35
+ case 'number_lessThan':
36
+ return 'Less than';
37
+ case 'number_lessThanOrEqualTo':
38
+ return 'Less than or equal to';
39
+ case 'number_between':
40
+ return 'Between';
41
+ case 'string_contains':
42
+ return 'Contains';
43
+ case 'string_doesNotContain':
44
+ return 'Does not contain';
45
+ case 'string_matches':
46
+ return 'Matches';
47
+ case 'string_doesNotMatch':
48
+ return 'Does not match';
49
+ case 'string_containsFuzzyMatch':
50
+ return 'Contains fuzzy match';
51
+ default:
52
+ throw Error(`unsupported filter type: ${type satisfies never}`);
53
+ }
54
+ }
55
+
56
+ export const filterTypesNumber: PlTableFilterNumberType[] = [
57
+ 'isNotNA',
58
+ 'isNA',
59
+ 'number_equals',
60
+ 'number_notEquals',
61
+ 'number_greaterThan',
62
+ 'number_greaterThanOrEqualTo',
63
+ 'number_lessThan',
64
+ 'number_lessThanOrEqualTo',
65
+ 'number_between',
66
+ ] as const;
67
+
68
+ export const filterTypesString: PlTableFilterStringType[] = [
69
+ 'isNotNA',
70
+ 'isNA',
71
+ 'string_equals',
72
+ 'string_notEquals',
73
+ 'string_contains',
74
+ 'string_doesNotContain',
75
+ 'string_matches',
76
+ 'string_doesNotMatch',
77
+ 'string_containsFuzzyMatch',
78
+ ] as const;
79
+
80
+ export function getColumnName(column: PTableColumnSpec, index: string | number) {
81
+ return column.spec.annotations?.['pl7.app/label']?.trim() ?? 'Unlabeled ' + column.type + ' ' + index.toString();
82
+ }
83
+
84
+ export function getFilterReference(filter: PlTableFilter): undefined | number | string {
85
+ const type = filter.type;
86
+ switch (type) {
87
+ case 'isNotNA':
88
+ case 'isNA':
89
+ return undefined;
90
+ case 'number_equals':
91
+ case 'number_notEquals':
92
+ case 'number_greaterThan':
93
+ case 'number_greaterThanOrEqualTo':
94
+ case 'number_lessThan':
95
+ case 'number_lessThanOrEqualTo':
96
+ return filter.reference;
97
+ case 'number_between':
98
+ return filter.lowerBound;
99
+ case 'string_equals':
100
+ case 'string_notEquals':
101
+ case 'string_contains':
102
+ case 'string_doesNotContain':
103
+ case 'string_matches':
104
+ case 'string_doesNotMatch':
105
+ case 'string_containsFuzzyMatch':
106
+ return filter.reference;
107
+ default:
108
+ throw Error(`unsupported filter type: ${type satisfies never}`);
109
+ }
110
+ }
111
+
112
+ export function getFilterDefault(type: PlTableFilterType, reference?: undefined | number | string): PlTableFilter {
113
+ switch (type) {
114
+ case 'isNotNA':
115
+ case 'isNA':
116
+ return { type };
117
+ case 'number_equals':
118
+ case 'number_notEquals':
119
+ case 'number_greaterThan':
120
+ case 'number_greaterThanOrEqualTo':
121
+ case 'number_lessThan':
122
+ case 'number_lessThanOrEqualTo':
123
+ return { type, reference: typeof reference === 'number' ? reference : 0 };
124
+ case 'number_between':
125
+ return {
126
+ type,
127
+ lowerBound: typeof reference === 'number' ? reference : 0,
128
+ includeLowerBound: true,
129
+ upperBound: 100,
130
+ includeUpperBound: false,
131
+ };
132
+ case 'string_equals':
133
+ case 'string_notEquals':
134
+ case 'string_contains':
135
+ case 'string_doesNotContain':
136
+ case 'string_matches':
137
+ case 'string_doesNotMatch':
138
+ return { type, reference: typeof reference === 'string' ? reference : '' };
139
+ case 'string_containsFuzzyMatch':
140
+ return {
141
+ type,
142
+ reference: typeof reference === 'string' ? reference : '',
143
+ maxEdits: 2,
144
+ substitutionsOnly: false,
145
+ wildcard: undefined,
146
+ };
147
+ default:
148
+ throw Error(`unsupported filter type: ${type satisfies never}`);
149
+ }
150
+ }
151
+
152
+ export function changeFilterType(filter: PlTableFiltersStateEntry, type: PlTableFilterType): PlTableFiltersStateEntry {
153
+ return {
154
+ columnId: filter.columnId,
155
+ filter: getFilterDefault(type, getFilterReference(filter.filter)),
156
+ disabled: filter.disabled,
157
+ };
158
+ }
159
+
160
+ export function parseNumber(column: PTableColumnSpec, value: string): number {
161
+ const parsed = Number(value);
162
+ if (!Number.isFinite(parsed)) throw Error('Model value is not a number.');
163
+
164
+ const type = column.type === 'column' ? column.spec.valueType : column.spec.type;
165
+ if ((type === 'Int' || type === 'Long') && !Number.isInteger(parsed)) throw Error('Model value is not an integer.');
166
+
167
+ const min = column.spec.annotations?.['pl7.app/min'];
168
+ if (min !== undefined) {
169
+ const minValue = Number(min);
170
+ if (Number.isFinite(minValue) && parsed < Number(min)) {
171
+ throw Error('Model value is too low.');
172
+ }
173
+ }
174
+
175
+ const max = column.spec.annotations?.['pl7.app/max'];
176
+ if (max !== undefined) {
177
+ const maxValue = Number(max);
178
+ if (Number.isFinite(maxValue) && parsed > Number(max)) {
179
+ throw Error('Model value is too high.');
180
+ }
181
+ }
182
+
183
+ return parsed;
184
+ }
185
+
186
+ export function parseString(column: PTableColumnSpec, value: string): string {
187
+ const alphabet = column.spec.domain?.['pl7.app/alphabet'] ?? column.spec.annotations?.['pl7.app/alphabet'];
188
+ if (alphabet === 'nucleotide' && !/^[AaTtGgCcNn]+$/.test(value)) throw Error('Model value is not a nucleotide.');
189
+ if (alphabet === 'aminoacid' && !/^[AaCcDdEeFfGgHhIiKkLlMmNnPpQqRrSsTtVvWwYyXx]+$/.test(value)) throw Error('Model value is not an aminoacid.');
190
+ return value;
191
+ }
192
+
193
+ export function parseRegex(value: string): string {
194
+ try {
195
+ new RegExp(value);
196
+ return value;
197
+ } catch (err: unknown) {
198
+ if (err instanceof SyntaxError) throw Error('Model value is not a regexp.');
199
+ throw err;
200
+ }
201
+ }
202
+
203
+ export function makeWildcardOptions(column: PTableColumnSpec, reference: string) {
204
+ const alphabet = column.spec.domain?.['pl7.app/alphabet'] ?? column.spec.annotations?.['pl7.app/alphabet'];
205
+ if (alphabet === 'nucleotide') {
206
+ return [
207
+ {
208
+ value: 'N',
209
+ text: 'N',
210
+ },
211
+ ];
212
+ }
213
+ if (alphabet === 'aminoacid') {
214
+ return [
215
+ {
216
+ value: 'X',
217
+ text: 'X',
218
+ },
219
+ ];
220
+ }
221
+
222
+ const chars = lodash.uniq(reference);
223
+ chars.sort();
224
+ return chars.map((char) => ({
225
+ value: char,
226
+ text: char,
227
+ }));
228
+ }
229
+
230
+ export function makePredicate(column: PTableColumnSpec, filter: PlTableFilter): SingleValuePredicateV2 {
231
+ const alphabetic =
232
+ (column.type === 'column' ? column.spec.valueType : column.spec.type) === 'String' &&
233
+ (column.spec.domain?.['pl7.app/alphabet'] ?? column.spec.annotations?.['pl7.app/alphabet']) !== undefined;
234
+ const type = filter.type;
235
+ switch (type) {
236
+ case 'isNotNA':
237
+ return {
238
+ operator: 'Not',
239
+ operand: {
240
+ operator: 'IsNA',
241
+ },
242
+ };
243
+ case 'isNA':
244
+ return {
245
+ operator: 'IsNA',
246
+ };
247
+ case 'number_equals':
248
+ return {
249
+ operator: 'Equal',
250
+ reference: filter.reference,
251
+ };
252
+ case 'string_equals':
253
+ return {
254
+ operator: alphabetic ? 'IEqual' : 'Equal',
255
+ reference: filter.reference as string,
256
+ };
257
+ case 'number_notEquals':
258
+ return {
259
+ operator: 'Not',
260
+ operand: {
261
+ operator: 'Equal',
262
+ reference: filter.reference,
263
+ },
264
+ };
265
+ case 'string_notEquals':
266
+ return {
267
+ operator: 'Not',
268
+ operand: {
269
+ operator: alphabetic ? 'IEqual' : 'Equal',
270
+ reference: filter.reference,
271
+ },
272
+ };
273
+ case 'number_greaterThan':
274
+ return {
275
+ operator: 'Greater',
276
+ reference: filter.reference,
277
+ };
278
+ case 'number_greaterThanOrEqualTo':
279
+ return {
280
+ operator: 'GreaterOrEqual',
281
+ reference: filter.reference,
282
+ };
283
+ case 'number_lessThan':
284
+ return {
285
+ operator: 'Less',
286
+ reference: filter.reference,
287
+ };
288
+ case 'number_lessThanOrEqualTo':
289
+ return {
290
+ operator: 'LessOrEqual',
291
+ reference: filter.reference,
292
+ };
293
+ case 'number_between':
294
+ return {
295
+ operator: 'And',
296
+ operands: [
297
+ {
298
+ operator: filter.includeLowerBound ? 'GreaterOrEqual' : 'Greater',
299
+ reference: filter.lowerBound,
300
+ },
301
+ {
302
+ operator: filter.includeUpperBound ? 'LessOrEqual' : 'Less',
303
+ reference: filter.upperBound,
304
+ },
305
+ ],
306
+ };
307
+ case 'string_contains':
308
+ return {
309
+ operator: alphabetic ? 'StringIContains' : 'StringContains',
310
+ substring: filter.reference,
311
+ };
312
+ case 'string_doesNotContain':
313
+ return {
314
+ operator: 'Not',
315
+ operand: {
316
+ operator: alphabetic ? 'StringIContains' : 'StringContains',
317
+ substring: filter.reference,
318
+ },
319
+ };
320
+ case 'string_matches':
321
+ return {
322
+ operator: 'Matches',
323
+ regex: filter.reference,
324
+ };
325
+ case 'string_doesNotMatch':
326
+ return {
327
+ operator: 'Not',
328
+ operand: {
329
+ operator: 'Matches',
330
+ regex: filter.reference,
331
+ },
332
+ };
333
+ case 'string_containsFuzzyMatch':
334
+ return {
335
+ operator: alphabetic ? 'StringIContainsFuzzy' : 'StringContainsFuzzy',
336
+ reference: filter.reference,
337
+ maxEdits: filter.maxEdits,
338
+ substitutionsOnly: filter.substitutionsOnly,
339
+ wildcard: filter.wildcard,
340
+ };
341
+ default:
342
+ throw Error(`unsupported filter type: ${type satisfies never}`);
343
+ }
344
+ }
@@ -0,0 +1 @@
1
+ export { default as PlTableFilters } from './PlTableFilters.vue';
@@ -0,0 +1,98 @@
1
+ .pl-filter-manager {
2
+ $this: &;
3
+
4
+ &__add-btn {
5
+ height: 40px;
6
+ position: sticky;
7
+ bottom: -16px;
8
+ background-color: var(--bg-elevated-01);
9
+ display: flex;
10
+ align-items: center;
11
+ gap: 8px;
12
+ padding-left: 12px;
13
+ padding-right: 12px;
14
+ border-radius: 6px;
15
+ border: 1px dashed var(--border-color-div-grey);
16
+ line-height: 0;
17
+ cursor: pointer;
18
+ }
19
+
20
+ &__add-btn-title {
21
+ flex-grow: 1;
22
+ }
23
+
24
+ &__header {
25
+ height: 40px;
26
+ padding-left: 12px;
27
+ padding-right: 12px;
28
+ cursor: pointer;
29
+ }
30
+
31
+ &__content {
32
+ max-height: 0;
33
+ overflow: hidden;
34
+ transition: all .2s ease-in-out;
35
+ padding-top: 0;
36
+ padding-bottom: 0;
37
+ }
38
+
39
+ &__expand-icon {
40
+ .mask-16 {
41
+ transition: all .15s ease-in-out;
42
+ }
43
+ }
44
+
45
+ &__toggle,
46
+ &__expand-icon,
47
+ &__delete {
48
+ line-height: 0;
49
+ cursor: pointer;
50
+ }
51
+
52
+ &__toggle,
53
+ &__delete {
54
+ .mask-24 {
55
+ background-color: var(--ic-02);
56
+ }
57
+ }
58
+
59
+
60
+ &__filter {
61
+ border-radius: 6px;
62
+ border: 1px solid var(--border-color-div-grey);
63
+ background-color: var(--bg-base-light);
64
+ transition: background-color .15s ease-in-out;
65
+ overflow: auto;
66
+ }
67
+
68
+ &__filter.open {
69
+ background-color: var(--bg-elevated-01);
70
+
71
+ #{$this}__content {
72
+ max-height: 1600px;
73
+ // overflow: auto;
74
+ padding: 24px;
75
+ transition: all .2s ease-in-out;
76
+ }
77
+
78
+ #{$this}__header {
79
+ background: linear-gradient(180deg, #EBFFEB 0%, #FFF 100%);
80
+ }
81
+
82
+ #{$this}__expand-icon {
83
+ .mask-16 {
84
+ transform: rotate(90deg);
85
+ }
86
+ }
87
+ }
88
+
89
+ &__revert-btn {
90
+ padding: 8px 14px;
91
+ border-radius: 6px;
92
+ cursor: pointer;
93
+ }
94
+
95
+ &__revert-btn:hover {
96
+ background-color: var(--btn-sec-hover-grey);
97
+ }
98
+ }
package/src/lib.ts CHANGED
@@ -1,12 +1,11 @@
1
1
  import './assets/ui.scss';
2
2
  import BlockLayout from './components/BlockLayout.vue';
3
3
  import PlAgDataTable from './components/PlAgDataTable/PlAgDataTable.vue';
4
- import PlTableFilters from './components/PlAgDataTable/PlTableFilters.vue';
5
4
  import PlAgOverlayLoading from './components/PlAgDataTable/PlAgOverlayLoading.vue';
6
5
  import PlAgOverlayNoRows from './components/PlAgDataTable/PlAgOverlayNoRows.vue';
7
6
  import ValueOrErrorsComponent from './components/ValueOrErrorsComponent.vue';
8
7
 
9
- export { BlockLayout, PlAgDataTable, PlTableFilters, PlAgOverlayLoading, PlAgOverlayNoRows, ValueOrErrorsComponent };
8
+ export { BlockLayout, PlAgDataTable, PlAgOverlayLoading, PlAgOverlayNoRows, ValueOrErrorsComponent };
10
9
 
11
10
  export * from './components/PlAgCellFile';
12
11
 
@@ -16,6 +15,8 @@ export * from './components/PlAgTextAndButtonCell';
16
15
 
17
16
  export * from './components/PlAgGridColumnManager';
18
17
 
18
+ export * from './components/PlTableFilters';
19
+
19
20
  export * from './defineApp';
20
21
 
21
22
  export * from './createModel';
@@ -1 +0,0 @@
1
- {"version":3,"file":"PlTableFilters.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/PlAgDataTable/PlTableFilters.vue"],"names":[],"mappings":"AAqjBA,OAAO,KAAK,EACV,mBAAmB,EAOnB,gBAAgB,EAEjB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAKhF,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE,QAAQ,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACtC,YAAY,CAAC,EAAE,QAAQ,CAAC,yBAAyB,EAAE,CAAC,CAAC;IACrD,QAAQ,CAAC,EAAE,QAAQ,CAAC,qBAAqB,EAAE,CAAC,CAAC;CAC9C,CAAC;AAgcF,KAAK,iBAAiB,GAAG;IACzB,UAAU,EAAE,mBAAmB,CAAC;CAC/B,GAAG,WAAW,CAAC;;;;;;AAgOhB,wBAOG"}