@itfin/components 1.4.28 → 1.4.30
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/libs/air-datepicker/air-datepicker.js +1 -1
- package/package.json +1 -1
- package/src/components/app/App.vue +3 -6
- package/src/components/checkbox/Checkbox.vue +1 -1
- package/src/components/checkbox/RadioBox.vue +6 -13
- package/src/components/datepicker/DatePickerInline.vue +129 -62
- package/src/components/filter/FilterPanel.vue +37 -16
- package/src/components/icon/components/nomi-chart-funnel.vue +6 -0
- package/src/components/icon/components/nomi-chart-kpi.vue +8 -0
- package/src/components/icon/components/nomi-control-panel.vue +8 -0
- package/src/components/panels/PanelItemEdit.vue +6 -8
- package/src/components/panels/PanelLink.vue +6 -15
- package/src/components/panels/PanelList.vue +7 -3
- package/src/components/panels/helpers.ts +10 -4
- package/src/components/table/Table2.vue +65 -61
- package/src/components/table/TableBody.vue +6 -0
- package/src/components/table/TableGroup.vue +14 -4
- package/src/components/table/TableHeader.vue +12 -7
- package/src/components/table/TableRowToggle.vue +9 -1
- package/src/components/table/TableRows.vue +55 -43
- package/src/components/table/table2.scss +15 -25
- package/src/components/view/View.vue +15 -8
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="itf-filter-panel d-flex flex-column
|
|
2
|
+
<div class="itf-filter-panel d-flex flex-column align-items-start" :class="{'gap-3': !filtersOnly}">
|
|
3
3
|
<div v-if="!filtersOnly" class="d-flex gap-2 justify-content-between w-100">
|
|
4
4
|
<slot name="search">
|
|
5
5
|
<div>
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
class="itf-filter-panel__badge"
|
|
36
36
|
:ref="'item-' + n"
|
|
37
37
|
v-model="filter[facet.name]"
|
|
38
|
-
:is-default="filter[facet.name].isDefault"
|
|
39
|
-
:text="filter[facet.name].label"
|
|
38
|
+
:is-default="filter[facet.name] && filter[facet.name].isDefault"
|
|
39
|
+
:text="filter[facet.name] && filter[facet.name].label"
|
|
40
40
|
:type="facet.type"
|
|
41
41
|
:icon="facet.icon"
|
|
42
42
|
:options="facet.options"
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
</div>
|
|
53
53
|
<slot name="after-filters"></slot>
|
|
54
54
|
</div>
|
|
55
|
-
<div v-if="loading">
|
|
55
|
+
<div v-if="loading && !visibleFilters.length">
|
|
56
56
|
<span class="itf-spinner"></span>
|
|
57
57
|
{{$t('loading')}}
|
|
58
58
|
</div>
|
|
@@ -177,6 +177,8 @@ class FilterPanel extends Vue {
|
|
|
177
177
|
(entries) => {
|
|
178
178
|
entries.forEach(entry => {
|
|
179
179
|
const index = parseInt(entry.target.dataset.index);
|
|
180
|
+
const filter = this.filters[index];
|
|
181
|
+
const value = this.filter[filter.name];
|
|
180
182
|
if (entry.isIntersecting) {
|
|
181
183
|
this.visibleItems.add(index); // Додаємо, якщо елемент у полі зору
|
|
182
184
|
} else {
|
|
@@ -206,7 +208,7 @@ class FilterPanel extends Vue {
|
|
|
206
208
|
|
|
207
209
|
get visibleFilters() {
|
|
208
210
|
if (this.mini) {
|
|
209
|
-
return sortBy(this.filters, (f) => this.filter[f.name].isDefault).filter(f => !f.options?.hidden)
|
|
211
|
+
return sortBy(this.filters, (f) => this.filter[f.name].isDefault).filter(f => !f.options?.hidden);
|
|
210
212
|
}
|
|
211
213
|
return this.filters.filter(f => !f.options?.hidden);
|
|
212
214
|
}
|
|
@@ -233,15 +235,7 @@ class FilterPanel extends Vue {
|
|
|
233
235
|
|
|
234
236
|
this.filters = this.staticFilters ?? [];
|
|
235
237
|
if (this.endpoint) {
|
|
236
|
-
this.
|
|
237
|
-
await this.$try(async () => {
|
|
238
|
-
const payload = this.panel ? this.panel.getPayload() : {};
|
|
239
|
-
const {filters, tableSchema} = await this.$axios.$get(this.endpoint, { params: payload });
|
|
240
|
-
this.filters = filters;
|
|
241
|
-
this.$emit('set-table-schema', tableSchema);
|
|
242
|
-
this.loadFiltersValue();
|
|
243
|
-
});
|
|
244
|
-
this.loading = false;
|
|
238
|
+
this.loadData();
|
|
245
239
|
} else {
|
|
246
240
|
this.loadFiltersValue();
|
|
247
241
|
}
|
|
@@ -250,6 +244,23 @@ class FilterPanel extends Vue {
|
|
|
250
244
|
}
|
|
251
245
|
}
|
|
252
246
|
|
|
247
|
+
async loadData() {
|
|
248
|
+
this.loading = true;
|
|
249
|
+
await this.$try(async () => {
|
|
250
|
+
const payload = this.panel ? this.panel.getPayload() : {};
|
|
251
|
+
const {filters, tableSchema} = await this.$axios.$get(this.endpoint, {
|
|
252
|
+
preventRaceCondition: true,
|
|
253
|
+
params: payload
|
|
254
|
+
});
|
|
255
|
+
this.filters = filters;
|
|
256
|
+
this.loading = false;
|
|
257
|
+
this.$emit('set-table-schema', tableSchema);
|
|
258
|
+
this.loadFiltersValue();
|
|
259
|
+
}, () => {
|
|
260
|
+
this.loading = false;
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
253
264
|
toggleFilters() {
|
|
254
265
|
this.showFilters = !this.showFilters;
|
|
255
266
|
if (this.stateName) {
|
|
@@ -269,7 +280,7 @@ class FilterPanel extends Vue {
|
|
|
269
280
|
filterValue.to = payload.to;
|
|
270
281
|
} else {
|
|
271
282
|
filter[item.name] = payload[item.name] ? this.formatValue(item, { value: payload[item.name] }) : { isDefault: true, ...item.options.defaultValue };
|
|
272
|
-
filterValue[item.name] = payload[item.name]
|
|
283
|
+
filterValue[item.name] = payload[item.name];
|
|
273
284
|
}
|
|
274
285
|
}
|
|
275
286
|
}
|
|
@@ -282,6 +293,7 @@ class FilterPanel extends Vue {
|
|
|
282
293
|
this.filter = filter;
|
|
283
294
|
this.filterValue = filterValue;
|
|
284
295
|
this.$emit('input', this.filterValue);
|
|
296
|
+
this.$emit('loaded', this.filterValue);
|
|
285
297
|
this.initObserver();
|
|
286
298
|
}
|
|
287
299
|
}
|
|
@@ -318,6 +330,7 @@ class FilterPanel extends Vue {
|
|
|
318
330
|
this.panel.setPayload({ ...payload, ...this.filterValue });
|
|
319
331
|
}
|
|
320
332
|
this.$emit('input', this.filterValue);
|
|
333
|
+
this.$emit('change', this.filterValue);
|
|
321
334
|
}
|
|
322
335
|
|
|
323
336
|
get daysList() {
|
|
@@ -363,7 +376,11 @@ class FilterPanel extends Vue {
|
|
|
363
376
|
}
|
|
364
377
|
} else if (facet.type === 'date') {
|
|
365
378
|
const date = DateTime.fromISO(value.value);
|
|
366
|
-
value.label = (date.isValid ?
|
|
379
|
+
value.label = (date.isValid ? date : DateTime.fromISO(facet.options.defaultValue.value ?? DateTime.now().toISO())).toFormat('dd MMM yyyy');
|
|
380
|
+
value.isDefault = facet.options.defaultValue ? value.value === facet.options.defaultValue.value : false;
|
|
381
|
+
} else if (facet.type === 'month') {
|
|
382
|
+
const date = DateTime.fromISO(value.value);
|
|
383
|
+
value.label = capitalizeFirstLetter((date.isValid ? date : DateTime.fromISO(facet.options.defaultValue.value)).toFormat('LLLL yyyy'));
|
|
367
384
|
value.isDefault = facet.options.defaultValue ? value.value === facet.options.defaultValue.value : false;
|
|
368
385
|
} else if (facet.type === 'facets-list') {
|
|
369
386
|
const firstItem = facet.options.items.find(item => item.value === (Array.isArray(value.value) ? value.value[0] : value.value));
|
|
@@ -402,6 +419,10 @@ class FilterPanel extends Vue {
|
|
|
402
419
|
}
|
|
403
420
|
value.hidden = facet.options?.hidden ?? false;
|
|
404
421
|
return value;
|
|
422
|
+
|
|
423
|
+
function capitalizeFirstLetter(string) {
|
|
424
|
+
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
425
|
+
}
|
|
405
426
|
}
|
|
406
427
|
}
|
|
407
428
|
</script>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<template><svg width="24" height="24" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path fill-rule="evenodd" clip-rule="evenodd"
|
|
3
|
+
d="M10.809 11C9.18 11 8 12.334 8 13.81v2.798c0 1.476 1.181 2.81 2.809 2.81H53.19c1.628 0 2.809-1.334 2.809-2.81V13.81c0-1.476-1.181-2.81-2.809-2.81H10.81Zm5.436 11.194c-1.628 0-2.809 1.334-2.809 2.81v2.798c0 1.476 1.181 2.81 2.809 2.81h31.51c1.628 0 2.809-1.334 2.809-2.81v-2.798c0-1.476-1.181-2.81-2.809-2.81h-31.51Zm5.436 11.194c-1.627 0-2.809 1.334-2.809 2.81v2.798c0 1.476 1.182 2.81 2.81 2.81h20.637c1.627 0 2.808-1.334 2.808-2.81v-2.798c0-1.476-1.18-2.81-2.808-2.81H21.68Zm5.436 11.194c-1.627 0-2.808 1.334-2.808 2.81v2.798c0 1.476 1.18 2.81 2.808 2.81h9.765c1.628 0 2.81-1.334 2.81-2.81v-2.798c0-1.476-1.182-2.81-2.81-2.81h-9.764Z"
|
|
4
|
+
fill="currentColor"></path>
|
|
5
|
+
</svg>
|
|
6
|
+
</template>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<template><svg width="24" height="24" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M28.761 40.248h-3.974l-4.324-6.954-1.48 1.06v5.894h-3.5V23.742h3.5v7.553l1.378-1.942 4.471-5.611h3.884l-5.758 7.305 5.803 9.201ZM34.339 31.51h1.151c1.077 0 1.882-.211 2.416-.633.535-.429.802-1.05.802-1.862 0-.82-.226-1.427-.677-1.818-.444-.392-1.144-.587-2.1-.587h-1.592v4.9Zm7.903-2.62c0 1.777-.557 3.135-1.671 4.076-1.106.941-2.683 1.411-4.73 1.411h-1.502v5.871h-3.5V23.742h5.272c2.003 0 3.523.433 4.562 1.298 1.046.858 1.569 2.142 1.569 3.85ZM45.358 40.248V23.742h3.5v16.506h-3.5Z"
|
|
3
|
+
fill="currentColor"></path>
|
|
4
|
+
<path fill-rule="evenodd" clip-rule="evenodd"
|
|
5
|
+
d="M9.29 12.903c0-.855.743-1.548 1.66-1.548h43.133c.916 0 1.66.693 1.66 1.548 0 .855-.744 1.549-1.66 1.549H10.95c-.917 0-1.66-.694-1.66-1.549ZM9.29 51.097c0-.855.743-1.549 1.66-1.549h43.133c.916 0 1.66.694 1.66 1.549s-.744 1.548-1.66 1.548H10.95c-.917 0-1.66-.693-1.66-1.548Z"
|
|
6
|
+
fill="currentColor"></path>
|
|
7
|
+
</svg>
|
|
8
|
+
</template>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<template><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M19 9L9 9" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
3
|
+
<path d="M13 15H5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
4
|
+
<path d="M19 15L17 15" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
5
|
+
<circle cx="15" cy="15" r="2" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
6
|
+
<circle cx="7" cy="9" r="2" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
7
|
+
</svg>
|
|
8
|
+
</template>
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div v-loading="loading" class="px-3 pt-2 h-100
|
|
2
|
+
<div v-loading="loading" class="px-3 pt-2 h-100">
|
|
3
3
|
<itf-form
|
|
4
4
|
ref="editForm"
|
|
5
|
-
class="d-flex flex-column justify-content-between
|
|
5
|
+
class="d-flex flex-column justify-content-between h-100"
|
|
6
6
|
@keydown.native.shift.enter.stop.prevent="onSaveClick"
|
|
7
7
|
@keydown.native.esc.stop.prevent="$emit('cancel')"
|
|
8
8
|
>
|
|
9
9
|
<slot></slot>
|
|
10
10
|
<div class="py-3 justify-content-end d-flex align-items-center sticky-container">
|
|
11
11
|
<div v-if="!hideFooter">
|
|
12
|
-
<itf-button v-tooltip.delay="'Hot key: Esc'" secondary
|
|
13
|
-
<span>{{
|
|
12
|
+
<itf-button v-tooltip.delay="'Hot key: Esc'" secondary :loading="loading" :disabled="loading" @click="$emit('cancel')">
|
|
13
|
+
<span>{{ $t('components.modal.cancel') }}</span>
|
|
14
14
|
</itf-button>
|
|
15
|
-
<itf-button v-tooltip.delay="'Hot key: Shift + Enter'" primary
|
|
16
|
-
<span>{{
|
|
15
|
+
<itf-button v-tooltip.delay="'Hot key: Shift + Enter'" primary :loading="loading" :disabled="loading" @click="onSaveClick">
|
|
16
|
+
<span>{{ $t('components.modal.save') }}</span>
|
|
17
17
|
</itf-button>
|
|
18
18
|
</div>
|
|
19
19
|
</div>
|
|
@@ -51,8 +51,6 @@ import itfButton from '../button/Button.vue';
|
|
|
51
51
|
export default class PanelItemEdit extends Vue {
|
|
52
52
|
@Prop(Boolean) loading;
|
|
53
53
|
@Prop(Boolean) hideFooter;
|
|
54
|
-
@Prop({ type: String, default: function() { return this.$t('components.modal.save') } }) saveBtnText;
|
|
55
|
-
@Prop({ type: String, default: function() { return this.$t('components.modal.cancel') } }) cancelBtnText;
|
|
56
54
|
|
|
57
55
|
onSaveClick() {
|
|
58
56
|
if (this.$refs.editForm && !this.$refs.editForm.doValidation()) {
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
import { Vue, Component, Inject, Prop } from 'vue-property-decorator';
|
|
6
6
|
import { IPanel } from './PanelList.vue';
|
|
7
7
|
import {stackToHash} from "@itfin/components/src/components/panels/helpers";
|
|
8
|
-
import {getRootPanelList} from "@itfin/components/src/components/panels";
|
|
9
8
|
|
|
10
9
|
@Component({
|
|
11
10
|
components: {
|
|
@@ -16,6 +15,7 @@ import {getRootPanelList} from "@itfin/components/src/components/panels";
|
|
|
16
15
|
}
|
|
17
16
|
})
|
|
18
17
|
export default class PanelLink extends Vue {
|
|
18
|
+
@Inject({ default: null }) panelList;
|
|
19
19
|
@Inject({ default: null }) currentPanel;
|
|
20
20
|
|
|
21
21
|
@Prop(Boolean) global: boolean;
|
|
@@ -25,7 +25,6 @@ export default class PanelLink extends Vue {
|
|
|
25
25
|
@Prop() list;
|
|
26
26
|
@Prop({ type: String, default: 'active' }) activeClass: string;
|
|
27
27
|
@Prop(Boolean) append: boolean;
|
|
28
|
-
@Prop(Boolean) replace: boolean;
|
|
29
28
|
|
|
30
29
|
get on() {
|
|
31
30
|
const handlers = {};
|
|
@@ -36,7 +35,7 @@ export default class PanelLink extends Vue {
|
|
|
36
35
|
}
|
|
37
36
|
|
|
38
37
|
get activeList() {
|
|
39
|
-
return this.list ??
|
|
38
|
+
return this.list ?? this.panelList;
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
get isActive() {
|
|
@@ -52,9 +51,6 @@ export default class PanelLink extends Vue {
|
|
|
52
51
|
if (!this.append) {
|
|
53
52
|
stack = stack.splice(0, this.currentPanel?.index + 1);
|
|
54
53
|
}
|
|
55
|
-
if (this.replace) {
|
|
56
|
-
stack = [];
|
|
57
|
-
}
|
|
58
54
|
const hash = stackToHash([
|
|
59
55
|
...stack,
|
|
60
56
|
{
|
|
@@ -66,18 +62,13 @@ export default class PanelLink extends Vue {
|
|
|
66
62
|
}
|
|
67
63
|
|
|
68
64
|
onClick(e) {
|
|
69
|
-
|
|
70
|
-
e.stopPropagation();
|
|
71
|
-
const index = this.replace ? 0 : (this.append ? undefined : this.currentPanel?.index + 1);
|
|
72
|
-
this.$emit('open', {
|
|
73
|
-
panel: this.panel,
|
|
74
|
-
payload: this.payload || {},
|
|
75
|
-
index
|
|
76
|
-
});
|
|
65
|
+
console.info(this.activeList);
|
|
77
66
|
if (!this.activeList) {
|
|
78
67
|
return;
|
|
79
68
|
}
|
|
80
|
-
|
|
69
|
+
e.preventDefault();
|
|
70
|
+
e.stopPropagation();
|
|
71
|
+
this.activeList.openPanel(this.panel, this.payload || {}, this.append ? undefined : this.currentPanel?.index + 1);
|
|
81
72
|
}
|
|
82
73
|
}
|
|
83
74
|
</script>
|
|
@@ -218,6 +218,7 @@ export default class PanelList extends Vue {
|
|
|
218
218
|
@Prop() panels: Record<string, Component>;
|
|
219
219
|
@Prop({ default: () => {} }) searchPanel: (type: string) => boolean;
|
|
220
220
|
@Prop({ type: String, default: 'path' }) routeType: string;
|
|
221
|
+
@Prop({ type: String, default: '' }) routePrefix: string;
|
|
221
222
|
|
|
222
223
|
panelsStack:IPanel[] = [];
|
|
223
224
|
|
|
@@ -228,6 +229,7 @@ export default class PanelList extends Vue {
|
|
|
228
229
|
if (this.firstPanel) {
|
|
229
230
|
this.internalOpenPanel(this.firstPanel.type, this.firstPanel.payload);
|
|
230
231
|
}
|
|
232
|
+
console.info('created');
|
|
231
233
|
this.parsePanelHash(); // щоб панелі змінювались при перезавантаженні
|
|
232
234
|
window.addEventListener('popstate', this.handlePopState); // щоб панелі змінювались при навігації
|
|
233
235
|
}
|
|
@@ -466,9 +468,9 @@ export default class PanelList extends Vue {
|
|
|
466
468
|
}
|
|
467
469
|
|
|
468
470
|
setPanelHash() {
|
|
469
|
-
const hash = stackToHash(this.panelsStack, this.
|
|
471
|
+
const hash = stackToHash(this.panelsStack, this.routePrefix).replace(/^#/, '');
|
|
470
472
|
if (this.routeType === 'path') {
|
|
471
|
-
this.$router.push({ path:
|
|
473
|
+
this.$router.push({ path: hash });
|
|
472
474
|
} else {
|
|
473
475
|
this.$router.push({ hash });
|
|
474
476
|
}
|
|
@@ -478,7 +480,7 @@ export default class PanelList extends Vue {
|
|
|
478
480
|
async parsePanelHash() {
|
|
479
481
|
const hash = this.routeType === 'path' ? location.pathname : location.hash;
|
|
480
482
|
if (hash) {
|
|
481
|
-
const panels = hashToStack(hash, this.
|
|
483
|
+
const panels = hashToStack(hash, this.routePrefix);
|
|
482
484
|
const newStack = [];
|
|
483
485
|
this.panelsStack = [];
|
|
484
486
|
for (const panelIndex in panels) {
|
|
@@ -498,12 +500,14 @@ export default class PanelList extends Vue {
|
|
|
498
500
|
}
|
|
499
501
|
}
|
|
500
502
|
this.panelsStack = newStack;
|
|
503
|
+
console.info('set', newStack);
|
|
501
504
|
this.emitEvent('panels.changed', this.panelsStack);
|
|
502
505
|
this.updateTitle();
|
|
503
506
|
}
|
|
504
507
|
}
|
|
505
508
|
|
|
506
509
|
handlePopState() {
|
|
510
|
+
console.info('handlePopState')
|
|
507
511
|
this.parsePanelHash();
|
|
508
512
|
// виправляє проблему відкритої панелі при натисканні кнопки "назад" до першої панелі
|
|
509
513
|
if (this.panelsStack.length === 2) {
|
|
@@ -10,19 +10,25 @@ export interface IPanel {
|
|
|
10
10
|
const COLLAPSE_SYMBOL = '~'
|
|
11
11
|
const PARAMS_SYMBOL = ';'
|
|
12
12
|
|
|
13
|
-
export function stackToHash(stack: IPanel[]) {
|
|
14
|
-
|
|
13
|
+
export function stackToHash(stack: IPanel[], prefix: string = '') {
|
|
14
|
+
let hash = stack.map(panel => {
|
|
15
15
|
let json = JSON5.stringify(panel.payload || {});
|
|
16
16
|
json = json.substring(1, json.length - 1); // Remove the outer {}
|
|
17
17
|
return `${panel.type}${panel.isCollapsed ? COLLAPSE_SYMBOL : ''}${json ? PARAMS_SYMBOL : ''}${json}`;
|
|
18
18
|
}).join(isPathType() ? '/' : '&');
|
|
19
|
+
if (prefix) {
|
|
20
|
+
hash = `${prefix}/${hash}`;
|
|
21
|
+
}
|
|
19
22
|
return isPathType() ? `/${hash}` : `#${hash}`;
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
|
|
23
|
-
export function hashToStack(hash: string|undefined): IPanel[] {
|
|
26
|
+
export function hashToStack(hash: string|undefined, prefix: string = ''): IPanel[] {
|
|
24
27
|
let stack:IPanel[] = [];
|
|
25
|
-
|
|
28
|
+
let str = hash.replace(isPathType() ? /^\// : /^#/, '');
|
|
29
|
+
if (str && prefix) {
|
|
30
|
+
str = str.replace(new RegExp(`^${prefix}\/?`), '');
|
|
31
|
+
}
|
|
26
32
|
if (str) {
|
|
27
33
|
stack = str.split(isPathType() ? '/' : '&').map(item => {
|
|
28
34
|
if (!item.includes(PARAMS_SYMBOL)) {
|
|
@@ -7,11 +7,9 @@
|
|
|
7
7
|
'permanent-checkboxes': selectedIds.length
|
|
8
8
|
}" :style="{ '--indicator-area-width': `${indicatorType === 'none' ? 1 : indicatorWidth}px`, '--shadow-area-width': `${shadowWidth}px` }">
|
|
9
9
|
<itf-notice-popout :visible="showGroupOperations" class="rounded-3 bg-black text-white">
|
|
10
|
-
<div class="d-flex gap-2 ps-
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
<div class="opacity-50">•</div>
|
|
14
|
-
</slot>
|
|
10
|
+
<div class="d-flex gap-2 ps-3 align-items-center small itf-table2_mass-operations">
|
|
11
|
+
<div>{{$tc('components.table.selectedItems', selectedIds.length, { n: selectedIds.length })}}</div>
|
|
12
|
+
<div class="opacity-50">•</div>
|
|
15
13
|
<a href="" class="me-3 opacity-50 text-white text-decoration-none" @click.stop.prevent="selectedIds = []">{{$t('components.table.cancelSelected')}}</a>
|
|
16
14
|
<div>
|
|
17
15
|
<slot name="group-operations"></slot>
|
|
@@ -19,61 +17,64 @@
|
|
|
19
17
|
</div>
|
|
20
18
|
</itf-notice-popout>
|
|
21
19
|
<div class="scrollable scrollable-x">
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
20
|
+
<itf-checkbox-group v-model="selectedIds">
|
|
21
|
+
<template v-for="(group, index) in groups">
|
|
22
|
+
<div class="table-view-body">
|
|
23
|
+
<itf-table-group
|
|
24
|
+
:key="index"
|
|
25
|
+
@update="$emit('update', { ...$event, group, groupIndex: index })"
|
|
26
|
+
@row-click="$emit('row-click', $event)"
|
|
27
|
+
:id-property="idProperty"
|
|
28
|
+
:columns="columns"
|
|
29
|
+
@update:columns="onColumnsUpdate"
|
|
30
|
+
:rows="group.rows"
|
|
31
|
+
:title="group.name"
|
|
32
|
+
:selected-ids.sync="selectedIds"
|
|
33
|
+
:add-new-rows="addNewRows"
|
|
34
|
+
:shadow-width="shadowWidth"
|
|
35
|
+
:column-sorting="columnSorting"
|
|
36
|
+
:column-resizing="columnResizing"
|
|
37
|
+
:show-grouping="showGrouping"
|
|
38
|
+
:show-summary="showSummary"
|
|
39
|
+
:show-add-column="showAddColumn"
|
|
40
|
+
:show-actions="showActions"
|
|
41
|
+
:show-header="!noHeader"
|
|
42
|
+
:schema="schema"
|
|
43
|
+
:editable="editable"
|
|
44
|
+
:no-column-menu="noColumnMenu"
|
|
45
|
+
:no-select-all="noSelectAll"
|
|
46
|
+
:currencies="currencies"
|
|
47
|
+
:currency="currency"
|
|
48
|
+
:subrows-property="subrowsProperty"
|
|
49
|
+
:async-subrows-property="asyncSubrowsProperty"
|
|
50
|
+
:divider-property="dividerProperty"
|
|
51
|
+
:indicator-type="indicatorType"
|
|
52
|
+
:expanded-all="expandedAll"
|
|
53
|
+
:indicatorWidth="indicatorWidth"
|
|
54
|
+
:striped="striped"
|
|
55
|
+
:expanded-ids="expandedIds"
|
|
56
|
+
:css-property="cssProperty"
|
|
57
|
+
:sticky-header="stickyHeader"
|
|
58
|
+
:editable-property="editableProperty"
|
|
59
|
+
:sorting.sync="_sorting"
|
|
60
|
+
:sort-as-string="sortAsString"
|
|
61
|
+
:active="active"
|
|
62
|
+
@loadChildren="$emit('loadChildren', $event)"
|
|
63
|
+
@update:expanded-ids="$emit('update:expanded-ids', $event)"
|
|
64
|
+
@new="$emit('new', $event)"
|
|
65
|
+
@filter="$emit('filter', $event)"
|
|
66
|
+
@add-column="$emit('add-column', $event)"
|
|
67
|
+
>
|
|
68
|
+
<template v-for="(_, name) in $slots" #[name]="slotData">
|
|
69
|
+
<slot :name="name" v-bind="slotData || {}" />
|
|
70
|
+
</template>
|
|
71
|
+
<template v-for="(_, name) in $scopedSlots" #[name]="slotData">
|
|
72
|
+
<slot :name="name" v-bind="slotData || {}" />
|
|
73
|
+
</template>
|
|
74
|
+
</itf-table-group>
|
|
75
|
+
</div>
|
|
76
|
+
</template>
|
|
77
|
+
</itf-checkbox-group>
|
|
77
78
|
</div>
|
|
78
79
|
</div>
|
|
79
80
|
|
|
@@ -104,11 +105,13 @@ export default @Component({
|
|
|
104
105
|
})
|
|
105
106
|
class itfTable2 extends Vue {
|
|
106
107
|
// @Prop({ required: true, type: Array }) columns;
|
|
108
|
+
@Prop(Boolean) sortAsString;
|
|
107
109
|
@Prop({ required: true, type: Array }) rows;
|
|
108
110
|
@Prop({ type: String, default: null }) groupBy;
|
|
109
111
|
@Prop({ type: String, default: null }) idProperty;
|
|
110
112
|
@Prop({ type: String, default: null }) cssProperty;
|
|
111
113
|
@Prop({ type: String, default: null }) subrowsProperty;
|
|
114
|
+
@Prop({ type: String, default: null }) asyncSubrowsProperty;
|
|
112
115
|
@Prop({ type: String, default: null }) dividerProperty;
|
|
113
116
|
@Prop({ type: String, default: null }) editableProperty;
|
|
114
117
|
@Prop({ default: null }) active;
|
|
@@ -244,7 +247,8 @@ class itfTable2 extends Vue {
|
|
|
244
247
|
@Watch('selectedIds')
|
|
245
248
|
onSelectedIdsUpdate(selectedIds) {
|
|
246
249
|
this.state.selectedIds = selectedIds;
|
|
247
|
-
|
|
250
|
+
// метод saveTableState не зберігає selectedIds в localStorage, не впевнений що він тут треба
|
|
251
|
+
// this.saveTableState();
|
|
248
252
|
}
|
|
249
253
|
|
|
250
254
|
onColumnsUpdate(columns) {
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
:columns="columns"
|
|
8
8
|
:id-property="idProperty"
|
|
9
9
|
:subrows-property="subrowsProperty"
|
|
10
|
+
:async-subrows-property="asyncSubrowsProperty"
|
|
10
11
|
:divider-property="dividerProperty"
|
|
11
12
|
:show-add-column="showAddColumn"
|
|
12
13
|
:show-actions="showActions"
|
|
@@ -144,6 +145,7 @@ class itfTableBody extends Vue {
|
|
|
144
145
|
@Prop() rows;
|
|
145
146
|
@Prop() idProperty;
|
|
146
147
|
@Prop() subrowsProperty;
|
|
148
|
+
@Prop() asyncSubrowsProperty;
|
|
147
149
|
@Prop() dividerProperty;
|
|
148
150
|
@Prop() active;
|
|
149
151
|
@Prop(Boolean) showAddColumn;
|
|
@@ -164,6 +166,10 @@ class itfTableBody extends Vue {
|
|
|
164
166
|
this.$emit('update:expanded-ids', this.expandedIds.includes(item[this.idProperty])
|
|
165
167
|
? this.expandedIds.filter((id) => id !== item[this.idProperty])
|
|
166
168
|
: [...this.expandedIds, item[this.idProperty]]);
|
|
169
|
+
|
|
170
|
+
if (this.asyncSubrowsProperty && item[this.asyncSubrowsProperty] && item[this.asyncSubrowsProperty]) {
|
|
171
|
+
this.$emit('loadChildren', item);
|
|
172
|
+
}
|
|
167
173
|
}
|
|
168
174
|
}
|
|
169
175
|
</script>
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<div class="shadow-area"></div>
|
|
18
18
|
<div class="header-wrapper" :class="{'header-additional-column': showAddColumn}" @click.prevent="toggleGroup">
|
|
19
19
|
<a class="header-content position-sticky d-flex align-items-center">
|
|
20
|
-
<itf-button
|
|
20
|
+
<itf-button icon small secondary class="collapse-arrow">
|
|
21
21
|
<itf-icon :name="isShowTable ? 'chevron_down' : 'chevron_right'"/>
|
|
22
22
|
</itf-button>
|
|
23
23
|
<span class="d-flex align-items-center line-overflow group-header-value text-primary"
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
:show-add-column="showAddColumn"
|
|
40
40
|
:show-actions="showActions"
|
|
41
41
|
:id-property="idProperty"
|
|
42
|
+
:sort-as-string="sortAsString"
|
|
42
43
|
:rows="rows"
|
|
43
44
|
:schema="schema"
|
|
44
45
|
:editable="editable"
|
|
@@ -61,11 +62,13 @@
|
|
|
61
62
|
@row-click="$emit('row-click', $event)"
|
|
62
63
|
:id-property="idProperty"
|
|
63
64
|
:subrows-property="subrowsProperty"
|
|
65
|
+
:async-subrows-property="asyncSubrowsProperty"
|
|
64
66
|
:divider-property="dividerProperty"
|
|
65
67
|
:rows="rows"
|
|
66
68
|
:editable="editable"
|
|
67
69
|
:currency="currency"
|
|
68
70
|
:currencies="currencies"
|
|
71
|
+
:sort-as-string="sortAsString"
|
|
69
72
|
:columns="visibleColumns"
|
|
70
73
|
:no-select-all="noSelectAll"
|
|
71
74
|
:selected-ids="selectedIds"
|
|
@@ -78,6 +81,7 @@
|
|
|
78
81
|
:css-property="cssProperty"
|
|
79
82
|
:editable-property="editableProperty"
|
|
80
83
|
:active="active"
|
|
84
|
+
@loadChildren="$emit('loadChildren', $event)"
|
|
81
85
|
@update:expanded-ids="$emit('update:expanded-ids', $event)"
|
|
82
86
|
>
|
|
83
87
|
<template v-for="(_, name) in $slots" #[name]="slotData">
|
|
@@ -91,11 +95,11 @@
|
|
|
91
95
|
|
|
92
96
|
<!-- Лінія додати нову -->
|
|
93
97
|
<div v-if="isShowTable && addNewRows"
|
|
94
|
-
class="table-row-template d-flex align-items-stretch">
|
|
98
|
+
class="table-row-template table-row-template__new-row d-flex align-items-stretch">
|
|
95
99
|
<div class="shadow-area"></div>
|
|
96
100
|
<a href="" @click.prevent="$emit('new', title)" data-test="table-add-new-item"
|
|
97
101
|
class="d-flex align-items-center flex-grow-1 table-add-new-item text-decoration-none">
|
|
98
|
-
<span class="d-sticky d-flex align-items-center py-1">
|
|
102
|
+
<span class="d-sticky d-flex align-items-center py-1 px-2 small">
|
|
99
103
|
<itf-icon name="plus"/>
|
|
100
104
|
<span>{{ newLabel }}</span>
|
|
101
105
|
</span>
|
|
@@ -264,7 +268,11 @@
|
|
|
264
268
|
min-height: var(--table-small-row-size);
|
|
265
269
|
}
|
|
266
270
|
|
|
271
|
+
.table-row-template.table-row-template__new-row {
|
|
272
|
+
min-height: 2rem;
|
|
273
|
+
}
|
|
267
274
|
.table-add-new-item {
|
|
275
|
+
background-color: var(--itf-table-header-bg);
|
|
268
276
|
border-right:var(--itf-table-border-base-width) solid var(--itf-table-border-base-color);
|
|
269
277
|
border-left:var(--itf-table-border-base-width) solid var(--itf-table-border-base-color);
|
|
270
278
|
border-bottom: var(--itf-table-border-base-width) solid var(--itf-table-border-base-color);
|
|
@@ -273,7 +281,7 @@
|
|
|
273
281
|
border-bottom-right-radius: var(--itf-table-table-border-radius);
|
|
274
282
|
|
|
275
283
|
& > span {
|
|
276
|
-
left: var(--shadow-area-width);
|
|
284
|
+
left: calc(var(--shadow-area-width) + 4px);
|
|
277
285
|
position: sticky;
|
|
278
286
|
padding-left: var(--shadow-area-width);
|
|
279
287
|
//border-left: var(--itf-table-border-base-width) solid var(--itf-table-border-base-color);
|
|
@@ -359,6 +367,7 @@ class itfTableGroup extends Vue {
|
|
|
359
367
|
@Prop() title;
|
|
360
368
|
@Prop() idProperty;
|
|
361
369
|
@Prop() subrowsProperty;
|
|
370
|
+
@Prop() asyncSubrowsProperty;
|
|
362
371
|
@Prop() dividerProperty;
|
|
363
372
|
@Prop() currency;
|
|
364
373
|
@Prop() currencies;
|
|
@@ -378,6 +387,7 @@ class itfTableGroup extends Vue {
|
|
|
378
387
|
@Prop(Boolean) expandedAll;
|
|
379
388
|
@Prop(Boolean) striped;
|
|
380
389
|
@Prop(Boolean) stickyHeader;
|
|
390
|
+
@Prop(Boolean) sortAsString;
|
|
381
391
|
@Prop() indicatorWidth;
|
|
382
392
|
@Prop() shadowWidth;
|
|
383
393
|
@Prop() cssProperty;
|