@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itfin/components",
3
- "version": "1.4.9",
3
+ "version": "1.4.11",
4
4
  "author": "Vitalii Savchuk <esvit666@gmail.com>",
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
@@ -42,6 +42,7 @@ $border-radius: $vs-border-radius;
42
42
  margin-right: -9px;
43
43
  align-items: center;
44
44
  padding: 1px 0 0;
45
+ min-width: 33px;
45
46
 
46
47
  .itf-button {
47
48
  margin: -0.25rem 0;
@@ -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 === 'period') {
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 === 'period') {
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 === 'period') {
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="$t('components.popover.yesDelete')"></span>
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
- this.saveTableState();
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
- v-model="currentTab"
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
- <div class="flex-grow-1 px-3 d-flex flex-column">
66
- <div class="position-relative flex-grow-1">
67
- <itf-table
68
- ref="table"
69
- style="--shadow-area-width: 0px;"
70
- absolute
71
- striped
72
- clickable
73
- column-sorting
74
- column-resizing
75
- :indicator-type="indicatorType"
76
- class="permanent-checkboxes"
77
- :state-name="stateName"
78
- id-property="id"
79
- :rows="items"
80
- :schema="tableSchema"
81
- :sorting="sorting"
82
- :active="activeIds"
83
- :show-actions="showActions"
84
- v-model="selectedIds"
85
- @row-click="$emit('open', $event)"
86
- @update:sorting="updateSorting($event)"
87
- >
88
- <template v-for="(_, name) in $slots" #[name]="slotData">
89
- <slot :name="name" v-bind="slotData || {}"/>
90
- </template>
91
- <template v-for="(_, name) in $scopedSlots" #[name]="slotData">
92
- <slot :name="name" v-bind="slotData || {}"/>
93
- </template>
94
- </itf-table>
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 { Vue, ModelSync, Component, Prop, Inject } from 'vue-property-decorator';
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: 'table' }) tab;
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
- get currentTab() {
182
- return this.tab;
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
- set currentTab(val) {
186
- this.$emit('update:tab', val);
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
- // const defaultSize = localStorage.getItem('sizePerPage') ?? 20;
221
- //
222
- // const { page, size, sorting } = this.panel.getPayload() ?? {};
223
- // this.page = page ?? 1;
224
- // this.size = size ?? defaultSize;
225
- // this.sorting = sorting ?? this.defaultSorting;
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
- // this.panel.setPayload(assignWithoutUndefined(this.panel.getPayload(), payload));
310
- //
311
- // function assignWithoutUndefined(...sources) {
312
- // const target = {};
313
- // sources.forEach(source => {
314
- // if (source && typeof source === 'object') {
315
- // Object.entries(source).forEach(([key, value]) => {
316
- // if (value !== undefined) {
317
- // target[key] = value;
318
- // }
319
- // });
320
- // }
321
- // });
322
- // return target;
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
- // this.setPanelPayload({ ...filter, page: 1 });
340
+ this.selectedIds = [];
341
+ this.setPanelPayload({ ...filter, page: 1 });
329
342
  this.loadData();
330
343
  }
331
344