@itfin/components 1.4.9 → 1.4.11
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/package.json +1 -1
- package/src/assets/scss/components/select/_dropdown-toggle.scss +1 -0
- package/src/components/filter/FilterBadge.vue +10 -0
- package/src/components/filter/FilterPanel.vue +12 -4
- package/src/components/modal/DeleteConfirmModal.vue +3 -3
- package/src/components/table/Table2.vue +2 -1
- package/src/components/view/View.vue +78 -65
package/package.json
CHANGED
|
@@ -29,6 +29,14 @@
|
|
|
29
29
|
@input="onFilterChange({ value: $event })"
|
|
30
30
|
/>
|
|
31
31
|
</template>
|
|
32
|
+
<template v-else-if="type === 'period-selector'">
|
|
33
|
+
<itf-period-picker
|
|
34
|
+
style="margin: -.5rem"
|
|
35
|
+
:value="value.value"
|
|
36
|
+
value-format="yyyy-MM-dd"
|
|
37
|
+
@input="onFilterChange({ value: $event })"
|
|
38
|
+
/>
|
|
39
|
+
</template>
|
|
32
40
|
<template v-else-if="type === 'date'">
|
|
33
41
|
<itf-date-picker-inline
|
|
34
42
|
style="margin: -.5rem"
|
|
@@ -146,6 +154,7 @@ import itfButton from '../button/Button';
|
|
|
146
154
|
import itfDropdown from '../dropdown/Dropdown.vue';
|
|
147
155
|
import itfDatePickerInline from '../datepicker/DatePickerInline.vue';
|
|
148
156
|
import itfDateRangePickerInline from '../datepicker/DateRangePickerInline.vue';
|
|
157
|
+
import itfPeriodPicker from '../datepicker/PeriodPicker.vue'
|
|
149
158
|
import itfTextField from '../text-field/TextField.vue';
|
|
150
159
|
import FilterFacetsList from './FilterFacetsList';
|
|
151
160
|
import FilterAmountRange from './FilterAmountRange.vue';
|
|
@@ -157,6 +166,7 @@ export default @Component({
|
|
|
157
166
|
itfDropdown,
|
|
158
167
|
itfDatePickerInline,
|
|
159
168
|
itfDateRangePickerInline,
|
|
169
|
+
itfPeriodPicker,
|
|
160
170
|
itfTextField,
|
|
161
171
|
FilterFacetsList,
|
|
162
172
|
FilterAmountRange
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
</style>
|
|
81
81
|
<script>
|
|
82
82
|
import { DateTime } from 'luxon';
|
|
83
|
-
import { Vue, Model, Prop, Component } from 'vue-property-decorator';
|
|
83
|
+
import { Vue, Watch, Model, Prop, Component } from 'vue-property-decorator';
|
|
84
84
|
import tooltip from '../../directives/tooltip';
|
|
85
85
|
import itfIcon from '../icon/Icon';
|
|
86
86
|
import itfButton from '../button/Button';
|
|
@@ -120,6 +120,8 @@ class FilterPanel extends Vue {
|
|
|
120
120
|
loading = false;
|
|
121
121
|
showFilters = true;
|
|
122
122
|
|
|
123
|
+
periodFilters = ['period', 'period-selector'];
|
|
124
|
+
|
|
123
125
|
get visibleFilters() {
|
|
124
126
|
if (this.mini) {
|
|
125
127
|
return sortBy(this.filters, (f) => this.filter[f.name].isDefault).filter(f => !f.options?.hidden).slice(0, 2);
|
|
@@ -135,6 +137,12 @@ class FilterPanel extends Vue {
|
|
|
135
137
|
return `filter-panel-${this.stateName}-filters`;
|
|
136
138
|
}
|
|
137
139
|
|
|
140
|
+
@Watch('staticFilters', { deep: true })
|
|
141
|
+
onStaticFiltersUpdate() {
|
|
142
|
+
this.filters = this.staticFilters ?? [];
|
|
143
|
+
this.loadFiltersValue();
|
|
144
|
+
}
|
|
145
|
+
|
|
138
146
|
async mounted() {
|
|
139
147
|
if (this.stateName) {
|
|
140
148
|
const item = localStorage.getItem(this.localstorageKey);
|
|
@@ -173,7 +181,7 @@ class FilterPanel extends Vue {
|
|
|
173
181
|
const filterValue = {};
|
|
174
182
|
if (this.filters) {
|
|
175
183
|
for (const item of this.filters) {
|
|
176
|
-
if (item.type
|
|
184
|
+
if (this.periodFilters.includes(item.type)) {
|
|
177
185
|
filter[item.name] = payload.from ? this.formatValue(item, { value: [payload.from, payload.to] }) : { isDefault: true, ...item.options.defaultValue };
|
|
178
186
|
filterValue.from = payload.from;
|
|
179
187
|
filterValue.to = payload.to;
|
|
@@ -205,7 +213,7 @@ class FilterPanel extends Vue {
|
|
|
205
213
|
|
|
206
214
|
onFilterChange(facet, value) {
|
|
207
215
|
this.filter[facet.name] = this.formatValue(facet, value);
|
|
208
|
-
if (facet.type
|
|
216
|
+
if (this.periodFilters.includes(facet.type)) {
|
|
209
217
|
this.filterValue.from = this.filter[facet.name].isDefault ? undefined : value.value[0];
|
|
210
218
|
this.filterValue.to = this.filter[facet.name].isDefault ? undefined : value.value[1];
|
|
211
219
|
} else {
|
|
@@ -236,7 +244,7 @@ class FilterPanel extends Vue {
|
|
|
236
244
|
}
|
|
237
245
|
|
|
238
246
|
formatValue(facet, value) {
|
|
239
|
-
if (facet.type
|
|
247
|
+
if (this.periodFilters.includes(facet.type)) {
|
|
240
248
|
if (value.value) {
|
|
241
249
|
let from = DateTime.fromFormat(value.value[0], 'yyyy-MM-dd');
|
|
242
250
|
let to = DateTime.fromFormat(value.value[1], 'yyyy-MM-dd');
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
:class="confirmClass"
|
|
35
35
|
@click="onConfirm"
|
|
36
36
|
>
|
|
37
|
-
<span v-html="
|
|
37
|
+
<span v-html="deleteCaption"></span>
|
|
38
38
|
</button>
|
|
39
39
|
</div>
|
|
40
40
|
</div>
|
|
@@ -59,8 +59,8 @@ class itfDeleteConfirmModal extends Vue {
|
|
|
59
59
|
@Prop(Boolean) loading;
|
|
60
60
|
@Prop({ type: Boolean, default: false }) disabled;
|
|
61
61
|
@Prop({ type: String, default: 'text-danger' }) confirmClass;
|
|
62
|
-
@Prop({ type: String, default () { return this.$t('noKeepIt'); } }) cancelCaption;
|
|
63
|
-
@Prop({ type: String, default () { return this.$t('yesDelete'); } }) deleteCaption;
|
|
62
|
+
@Prop({ type: String, default () { return this.$t('components.noKeepIt'); } }) cancelCaption;
|
|
63
|
+
@Prop({ type: String, default () { return this.$t('components.yesDelete'); } }) deleteCaption;
|
|
64
64
|
|
|
65
65
|
isModalShown = false;
|
|
66
66
|
|
|
@@ -249,7 +249,8 @@ class itfTable2 extends Vue {
|
|
|
249
249
|
@Watch('selectedIds')
|
|
250
250
|
onSelectedIdsUpdate(selectedIds) {
|
|
251
251
|
this.state.selectedIds = selectedIds;
|
|
252
|
-
|
|
252
|
+
// метод saveTableState не зберігає selectedIds в localStorage, не впевнений що він тут треба
|
|
253
|
+
// this.saveTableState();
|
|
253
254
|
}
|
|
254
255
|
|
|
255
256
|
onColumnsUpdate(columns) {
|
|
@@ -44,9 +44,10 @@
|
|
|
44
44
|
<itf-segmented-control
|
|
45
45
|
v-if="tabs.length > 1"
|
|
46
46
|
class="small"
|
|
47
|
-
|
|
47
|
+
:value="currentTab"
|
|
48
48
|
item-key="value"
|
|
49
49
|
:items="tabs"
|
|
50
|
+
@input="updateTabs"
|
|
50
51
|
>
|
|
51
52
|
<template #item="{ item }">
|
|
52
53
|
<div class="d-flex align-items-center">
|
|
@@ -62,38 +63,41 @@
|
|
|
62
63
|
<slot v-else-if="currentTab === 'board'" name="kanban-view"></slot>
|
|
63
64
|
<slot v-else-if="currentTab === 'calendar'" name="calendar-view"></slot>
|
|
64
65
|
<slot v-else name="table-view">
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
66
|
+
<div class="flex-grow-1 px-3 d-flex flex-column">
|
|
67
|
+
<div class="position-relative flex-grow-1">
|
|
68
|
+
<itf-table
|
|
69
|
+
ref="table"
|
|
70
|
+
style="--shadow-area-width: 0px;"
|
|
71
|
+
absolute
|
|
72
|
+
striped
|
|
73
|
+
clickable
|
|
74
|
+
column-sorting
|
|
75
|
+
column-resizing
|
|
76
|
+
:indicator-type="indicatorType"
|
|
77
|
+
class="permanent-checkboxes"
|
|
78
|
+
:state-name="stateName"
|
|
79
|
+
id-property="id"
|
|
80
|
+
:sort-as-string="sortAsString"
|
|
81
|
+
:rows="items"
|
|
82
|
+
:schema="tableSchema"
|
|
83
|
+
:sorting="sorting"
|
|
84
|
+
:active="activeIds"
|
|
85
|
+
:no-select-all="noSelectAll"
|
|
86
|
+
:show-actions="showActions"
|
|
87
|
+
:indicator-width="indicatorWidth"
|
|
88
|
+
v-model="selectedIds"
|
|
89
|
+
@row-click="$emit('open', $event)"
|
|
90
|
+
@update:sorting="updateSorting($event)"
|
|
91
|
+
>
|
|
92
|
+
<template v-for="(_, name) in $slots" #[name]="slotData">
|
|
93
|
+
<slot :name="name" v-bind="slotData || {}"/>
|
|
94
|
+
</template>
|
|
95
|
+
<template v-for="(_, name) in $scopedSlots" #[name]="slotData">
|
|
96
|
+
<slot :name="name" v-bind="slotData || {}"/>
|
|
97
|
+
</template>
|
|
98
|
+
</itf-table>
|
|
99
|
+
</div>
|
|
95
100
|
</div>
|
|
96
|
-
</div>
|
|
97
101
|
</slot>
|
|
98
102
|
|
|
99
103
|
<itf-pagination
|
|
@@ -115,7 +119,7 @@
|
|
|
115
119
|
|
|
116
120
|
</template>
|
|
117
121
|
<script>
|
|
118
|
-
import {
|
|
122
|
+
import {Vue, ModelSync, Component, Prop, Inject, PropSync, Watch} from 'vue-property-decorator';
|
|
119
123
|
import loading from '../../directives/loading';
|
|
120
124
|
import itfTable from '../table/Table2.vue';
|
|
121
125
|
import itfFilterPanel from '../filter/FilterPanel.vue';
|
|
@@ -145,10 +149,7 @@ class itfView extends Vue {
|
|
|
145
149
|
|
|
146
150
|
@Prop({ type: Boolean }) loading;
|
|
147
151
|
@Prop({ type: Array }) filters;
|
|
148
|
-
// @Prop({ type: Object, required: true }) schema;
|
|
149
152
|
@Prop({ type: Object }) schema;
|
|
150
|
-
// @Prop({ default: 20 }) size;
|
|
151
|
-
// @Prop({ default: 1 }) page;
|
|
152
153
|
@Prop(String) defaultSorting;
|
|
153
154
|
@Prop(String) endpoint;
|
|
154
155
|
@Prop(String) filtersEndpoint;
|
|
@@ -156,7 +157,7 @@ class itfView extends Vue {
|
|
|
156
157
|
@Prop(String) panelKey;
|
|
157
158
|
@Prop(String) stateName;
|
|
158
159
|
@Prop({ type: String, default: 'checkbox' }) indicatorType;
|
|
159
|
-
@Prop({ type: String, default: '
|
|
160
|
+
@Prop({ type: String, default: 'list' }) tab;
|
|
160
161
|
@Prop({ type: String, default () { return this.$t('components.table.search'); } }) searchPlaceholder;
|
|
161
162
|
@Prop() panel;
|
|
162
163
|
@Prop(Boolean) showActions;
|
|
@@ -164,8 +165,12 @@ class itfView extends Vue {
|
|
|
164
165
|
@Prop(Boolean) listViewEnabled;
|
|
165
166
|
@Prop(Boolean) kanbanViewEnabled;
|
|
166
167
|
@Prop(Boolean) calendarViewEnabled;
|
|
168
|
+
@Prop(Boolean) noSelectAll;
|
|
167
169
|
@Prop({ type: Boolean, default: true }) tableViewEnabled;
|
|
170
|
+
@Prop(Boolean) sortAsString;
|
|
168
171
|
@Prop(Boolean) oldFormat;
|
|
172
|
+
@Prop({ default: 45 }) indicatorWidth;
|
|
173
|
+
@Prop({type: Function, default: null }) onSplitSlectedIds // якщо потрібно розділяти вибрані рядки в таблиці на дві групи
|
|
169
174
|
|
|
170
175
|
page = 1;
|
|
171
176
|
total = 0;
|
|
@@ -178,12 +183,15 @@ class itfView extends Vue {
|
|
|
178
183
|
tableColumns = undefined;
|
|
179
184
|
_currentTab = null;
|
|
180
185
|
|
|
181
|
-
|
|
182
|
-
|
|
186
|
+
@Watch('selectedIds', { deep: true, immediate: true })
|
|
187
|
+
updateSelectedIds() {
|
|
188
|
+
if(this.onSplitSlectedIds && this.items.length && this.selectedIds.length) {
|
|
189
|
+
this.onSplitSlectedIds(this.selectedIds, this.items);
|
|
190
|
+
}
|
|
183
191
|
}
|
|
184
192
|
|
|
185
|
-
|
|
186
|
-
this
|
|
193
|
+
get currentTab() {
|
|
194
|
+
return this.tab;
|
|
187
195
|
}
|
|
188
196
|
|
|
189
197
|
get tabs() {
|
|
@@ -204,7 +212,6 @@ class itfView extends Vue {
|
|
|
204
212
|
}
|
|
205
213
|
|
|
206
214
|
get tableSchema() {
|
|
207
|
-
// return this.tableColumns || this.schema;
|
|
208
215
|
if (this.tableColumns) {
|
|
209
216
|
return {
|
|
210
217
|
properties: this.tableColumns
|
|
@@ -217,13 +224,12 @@ class itfView extends Vue {
|
|
|
217
224
|
}
|
|
218
225
|
|
|
219
226
|
created() {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
this.sorting = this.defaultSorting;
|
|
227
|
+
const defaultSize = localStorage.getItem('sizePerPage') ?? 20;
|
|
228
|
+
|
|
229
|
+
const { page, size, sorting } = this.panel.getPayload() ?? {};
|
|
230
|
+
this.page = page ?? 1;
|
|
231
|
+
this.size = size ?? defaultSize;
|
|
232
|
+
this.sorting = sorting ?? this.defaultSorting;
|
|
227
233
|
}
|
|
228
234
|
|
|
229
235
|
mounted() {
|
|
@@ -293,6 +299,7 @@ class itfView extends Vue {
|
|
|
293
299
|
|
|
294
300
|
updatePage (val) {
|
|
295
301
|
this.page = val;
|
|
302
|
+
this.selectedIds = [];
|
|
296
303
|
this.setPanelPayload({ page: val });
|
|
297
304
|
this.loadData();
|
|
298
305
|
}
|
|
@@ -300,32 +307,38 @@ class itfView extends Vue {
|
|
|
300
307
|
updateSizePerPage (val) {
|
|
301
308
|
this.page = 1;
|
|
302
309
|
this.size = val;
|
|
310
|
+
this.selectedIds = [];
|
|
303
311
|
this.setPanelPayload({ page: 1, size: val });
|
|
304
312
|
this.loadData();
|
|
305
313
|
localStorage.setItem('sizePerPage', val);
|
|
306
314
|
}
|
|
307
315
|
|
|
316
|
+
updateTabs(val) {
|
|
317
|
+
this.setPanelPayload({ tab: val });
|
|
318
|
+
}
|
|
319
|
+
|
|
308
320
|
setPanelPayload(payload) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
321
|
+
this.panel.setPayload(assignWithoutUndefined(this.panel.getPayload(), payload));
|
|
322
|
+
|
|
323
|
+
function assignWithoutUndefined(...sources) {
|
|
324
|
+
const target = {};
|
|
325
|
+
sources.forEach(source => {
|
|
326
|
+
if (source && typeof source === 'object') {
|
|
327
|
+
Object.entries(source).forEach(([key, value]) => {
|
|
328
|
+
if (value !== undefined) {
|
|
329
|
+
target[key] = value;
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
return target;
|
|
335
|
+
}
|
|
324
336
|
}
|
|
325
337
|
|
|
326
338
|
onFilterSet(filter) {
|
|
327
339
|
this.page = 1;
|
|
328
|
-
|
|
340
|
+
this.selectedIds = [];
|
|
341
|
+
this.setPanelPayload({ ...filter, page: 1 });
|
|
329
342
|
this.loadData();
|
|
330
343
|
}
|
|
331
344
|
|