@itfin/components 1.4.40 → 1.5.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 (187) hide show
  1. package/package.json +17 -20
  2. package/src/ITFSettings.js +6 -0
  3. package/src/assets/scss/components/_button.scss +118 -0
  4. package/src/assets/scss/components/_text-field.scss +22 -8
  5. package/src/components/alert/AlertBanner.vue +75 -0
  6. package/src/components/app/App.vue +6 -3
  7. package/src/components/button/Button.vue +3 -1
  8. package/src/components/button/NativeButton.js +4 -0
  9. package/src/components/button/index.stories.js +2 -2
  10. package/src/components/checkbox/Checkbox.vue +2 -1
  11. package/src/components/checkbox/RadioBox.vue +13 -7
  12. package/src/components/copyToClipboard/CopyToClipboard.vue +4 -1
  13. package/src/components/customize/PropertiesList.vue +0 -2
  14. package/src/components/customize/PropertiesPopupMenu.vue +1 -1
  15. package/src/components/customize/PropertyItem.vue +6 -24
  16. package/src/components/datepicker/DatePicker.vue +3 -1
  17. package/src/components/datepicker/DatePickerInline.vue +2 -2
  18. package/src/components/datepicker/DateRangePickerInline.vue +6 -1
  19. package/src/components/dropdown/Dropdown.vue +1 -1
  20. package/src/components/dropdown/DropdownMenu.vue +1 -1
  21. package/src/components/editable/EditButton.vue +1 -1
  22. package/src/components/editor/plugins.js +1012 -0
  23. package/src/components/filter/FilterBadge.vue +17 -3
  24. package/src/components/filter/FilterFacetsList.vue +67 -13
  25. package/src/components/filter/FilterPanel.vue +8 -21
  26. package/src/components/filter/NewFilter.vue +305 -0
  27. package/src/components/form/Label.vue +5 -5
  28. package/src/components/icon/components/nomi-ai-alt.vue +5 -0
  29. package/src/components/icon/components/nomi-bell.vue +5 -0
  30. package/src/components/icon/components/nomi-budget.vue +4 -0
  31. package/src/components/icon/components/nomi-calendar-payment.vue +10 -0
  32. package/src/components/icon/components/nomi-card-plus.vue +1 -0
  33. package/src/components/icon/components/nomi-cash-provider.vue +9 -0
  34. package/src/components/icon/components/nomi-category-edit.vue +5 -0
  35. package/src/components/icon/components/nomi-delta.vue +7 -0
  36. package/src/components/icon/components/nomi-exit-right.vue +4 -0
  37. package/src/components/icon/components/nomi-help.vue +2 -3
  38. package/src/components/icon/components/nomi-lock.vue +1 -1
  39. package/src/components/icon/components/nomi-project.vue +2 -2
  40. package/src/components/icon/components/nomi-refresh-off.vue +4 -0
  41. package/src/components/icon/components/nomi-refresh.vue +4 -0
  42. package/src/components/icon/components/nomi-scissors.vue +1 -1
  43. package/src/components/icon/components/nomi-start.vue +28 -0
  44. package/src/components/icon/components/nomi-table-view.vue +1 -4
  45. package/src/components/icon/components/nomi-transactions-delete.vue +5 -0
  46. package/src/components/icon/components/nomi-type-array.vue +6 -0
  47. package/src/components/icon/components/nomi-type-boolean.vue +5 -0
  48. package/src/components/icon/components/nomi-type-date.vue +4 -0
  49. package/src/components/icon/components/nomi-type-null.vue +4 -0
  50. package/src/components/icon/components/nomi-type-number.vue +4 -0
  51. package/src/components/icon/components/nomi-type-object.vue +4 -0
  52. package/src/components/icon/components/nomi-type-string.vue +4 -0
  53. package/src/components/icon/components/nomi-unarchive.vue +17 -0
  54. package/src/components/icon/components/nomi-unlink.vue +10 -0
  55. package/src/components/icon/components/nomi-user.vue +3 -3
  56. package/src/components/icon/components/nomi-warning-triangle.vue +6 -0
  57. package/src/components/icon/components/nomi-warning_triangle_filled.vue +6 -0
  58. package/src/components/icon/convert-icons.js +3 -0
  59. package/src/components/icon/icons.js +390 -312
  60. package/src/components/icon/new-icons/ai-alt.svg +4 -0
  61. package/src/components/icon/new-icons/arrow-right-alt.svg +3 -0
  62. package/src/components/icon/new-icons/arrow-right.svg +3 -0
  63. package/src/components/icon/new-icons/arrow_left.svg +3 -0
  64. package/src/components/icon/new-icons/automation.svg +4 -0
  65. package/src/components/icon/new-icons/balance.svg +3 -0
  66. package/src/components/icon/new-icons/balance_turnover.svg +4 -0
  67. package/src/components/icon/new-icons/bar-horizontal.svg +6 -0
  68. package/src/components/icon/new-icons/bell.svg +4 -0
  69. package/src/components/icon/new-icons/calendar-payment.svg +9 -0
  70. package/src/components/icon/new-icons/card-plus.svg +1 -0
  71. package/src/components/icon/new-icons/cash-provider.svg +8 -0
  72. package/src/components/icon/new-icons/cash-repeat.svg +5 -0
  73. package/src/components/icon/new-icons/cash.svg +3 -0
  74. package/src/components/icon/new-icons/cashflow.svg +3 -0
  75. package/src/components/icon/new-icons/category-edit.svg +4 -0
  76. package/src/components/icon/new-icons/category.svg +4 -0
  77. package/src/components/icon/new-icons/category_alt.svg +3 -0
  78. package/src/components/icon/new-icons/chart-bars.svg +5 -0
  79. package/src/components/icon/new-icons/chart-donut.svg +3 -0
  80. package/src/components/icon/new-icons/chart-funnel.svg +5 -0
  81. package/src/components/icon/new-icons/chart-kpi.svg +7 -0
  82. package/src/components/icon/new-icons/chart-line.svg +4 -0
  83. package/src/components/icon/new-icons/chart-lines.svg +5 -0
  84. package/src/components/icon/new-icons/check-alt.svg +3 -0
  85. package/src/components/icon/new-icons/check.svg +3 -0
  86. package/src/components/icon/new-icons/chevron-down.svg +3 -0
  87. package/src/components/icon/new-icons/chevron-left.svg +3 -0
  88. package/src/components/icon/new-icons/chevron-right.svg +3 -0
  89. package/src/components/icon/new-icons/chevron-up.svg +3 -0
  90. package/src/components/icon/new-icons/collapse.svg +6 -0
  91. package/src/components/icon/new-icons/control-panel.svg +7 -0
  92. package/src/components/icon/new-icons/credit.svg +3 -0
  93. package/src/components/icon/new-icons/currencies.svg +3 -0
  94. package/src/components/icon/new-icons/debt.svg +3 -0
  95. package/src/components/icon/new-icons/delta.svg +6 -0
  96. package/src/components/icon/new-icons/demo.svg +6 -0
  97. package/src/components/icon/new-icons/dev.svg +3 -0
  98. package/src/components/icon/new-icons/dots.svg +5 -0
  99. package/src/components/icon/new-icons/duplicate.svg +4 -0
  100. package/src/components/icon/new-icons/exit-right.svg +3 -0
  101. package/src/components/icon/new-icons/export.svg +3 -0
  102. package/src/components/icon/new-icons/file.svg +3 -0
  103. package/src/components/icon/new-icons/folder.svg +3 -0
  104. package/src/components/icon/new-icons/goods-turnover.svg +3 -0
  105. package/src/components/icon/new-icons/goods.svg +4 -0
  106. package/src/components/icon/new-icons/help-alt.svg +3 -0
  107. package/src/components/icon/new-icons/help.svg +2 -3
  108. package/src/components/icon/new-icons/history.svg +6 -0
  109. package/src/components/icon/new-icons/integration.svg +3 -0
  110. package/src/components/icon/new-icons/link.svg +5 -0
  111. package/src/components/icon/new-icons/lock.svg +1 -1
  112. package/src/components/icon/new-icons/menu.svg +5 -0
  113. package/src/components/icon/new-icons/minus.svg +3 -0
  114. package/src/components/icon/new-icons/payment_calendar.svg +3 -0
  115. package/src/components/icon/new-icons/pc.svg +3 -0
  116. package/src/components/icon/new-icons/pen-alt.svg +3 -0
  117. package/src/components/icon/new-icons/planFact.svg +4 -0
  118. package/src/components/icon/new-icons/pnl.svg +7 -0
  119. package/src/components/icon/new-icons/project.svg +2 -2
  120. package/src/components/icon/new-icons/project_alt.svg +3 -0
  121. package/src/components/icon/new-icons/project_alt2.svg +3 -0
  122. package/src/components/icon/new-icons/promo.svg +3 -0
  123. package/src/components/icon/new-icons/refresh-off.svg +3 -0
  124. package/src/components/icon/new-icons/refresh.svg +3 -0
  125. package/src/components/icon/new-icons/scissors.svg +1 -1
  126. package/src/components/icon/new-icons/segment.svg +3 -0
  127. package/src/components/icon/new-icons/start.svg +27 -0
  128. package/src/components/icon/new-icons/strongbox.svg +3 -0
  129. package/src/components/icon/new-icons/subscription.svg +3 -0
  130. package/src/components/icon/new-icons/table-view.svg +1 -4
  131. package/src/components/icon/new-icons/time.svg +3 -0
  132. package/src/components/icon/new-icons/transactions_alt.svg +6 -0
  133. package/src/components/icon/new-icons/transactions_delete.svg +4 -0
  134. package/src/components/icon/new-icons/type-array.svg +5 -0
  135. package/src/components/icon/new-icons/type-boolean.svg +4 -0
  136. package/src/components/icon/new-icons/type-date.svg +3 -0
  137. package/src/components/icon/new-icons/type-null.svg +3 -0
  138. package/src/components/icon/new-icons/type-number.svg +3 -0
  139. package/src/components/icon/new-icons/type-object.svg +3 -0
  140. package/src/components/icon/new-icons/type-string.svg +3 -0
  141. package/src/components/icon/new-icons/types.svg +6 -0
  142. package/src/components/icon/new-icons/unarchive.svg +16 -0
  143. package/src/components/icon/new-icons/unlink.svg +9 -0
  144. package/src/components/icon/new-icons/user.svg +3 -3
  145. package/src/components/icon/new-icons/user_plus.svg +10 -0
  146. package/src/components/icon/new-icons/warehouse.svg +3 -0
  147. package/src/components/icon/new-icons/warning_triangle.svg +5 -0
  148. package/src/components/icon/new-icons/warning_triangle_filled.svg +5 -0
  149. package/src/components/kanban/BoardCard.vue +1 -1
  150. package/src/components/kanban/BoardCardTimer.vue +1 -1
  151. package/src/components/modal/DeleteConfirmModal.vue +10 -6
  152. package/src/components/modal/ItemEditor.vue +1 -1
  153. package/src/components/modal/Modal.vue +1 -1
  154. package/src/components/overlay/SensitiveOverlay.vue +2 -4
  155. package/src/components/panels/Panel.vue +110 -23
  156. package/src/components/panels/PanelItemEdit.vue +8 -6
  157. package/src/components/panels/PanelList.vue +164 -40
  158. package/src/components/panels/helpers.ts +41 -13
  159. package/src/components/popover/Popover.vue +105 -22
  160. package/src/components/segmented-control/SegmentedControl.vue +9 -3
  161. package/src/components/sortable/draggable.js +1 -1
  162. package/src/components/table/Table2.vue +68 -67
  163. package/src/components/table/TableBody.vue +17 -22
  164. package/src/components/table/TableGroup.vue +40 -24
  165. package/src/components/table/TableHeader.vue +86 -81
  166. package/src/components/table/TableRowToggle.vue +1 -9
  167. package/src/components/table/TableRows.vue +49 -55
  168. package/src/components/table/mobile.js +4 -0
  169. package/src/components/table/table2.scss +34 -15
  170. package/src/components/text-field/MoneyField.vue +10 -4
  171. package/src/components/text-field/TextField.vue +17 -8
  172. package/src/components/tree/TreeEditor.vue +3 -2
  173. package/src/components/view/View.vue +80 -207
  174. package/src/directives/appendToBody.js +1 -0
  175. package/src/helpers/validators.js +9 -35
  176. package/src/helpers/validators.spec.js +11 -48
  177. package/src/locales/en.js +4 -6
  178. package/src/locales/pl.js +158 -0
  179. package/src/locales/uk.js +6 -7
  180. package/src/components/icon/components/nomi-calendar-view.vue +0 -4
  181. package/src/components/icon/components/nomi-kanban-view.vue +0 -6
  182. package/src/components/icon/components/nomi-list-view.vue +0 -7
  183. package/src/components/icon/components/nomi-table-config.vue +0 -9
  184. package/src/components/icon/new-icons/calendar-view.svg +0 -3
  185. package/src/components/icon/new-icons/kanban-view.svg +0 -5
  186. package/src/components/icon/new-icons/list-view.svg +0 -6
  187. package/src/components/icon/new-icons/table-config.svg +0 -8
@@ -7,10 +7,10 @@
7
7
  --itf-table-alt-bg: #F9FAFB;
8
8
  --itf-table-alt-selected-bg: #eff1f3;
9
9
  --itf-table-header-bg: #f5f7f8;
10
- --itf-table-header-color: #575b63;
10
+ --itf-table-header-color: #7A818EA5;
11
11
  --itf-table-mirror-bg: #F2F4F7;
12
12
  --itf-table-border-color: transparent; //var(--itf-table-header-bg);
13
- --itf-table-header-border-color: #8E97A533;
13
+ --itf-table-header-border-color: #7A818E33;
14
14
  --itf-table-border-base-color: var(--itf-table-header-bg); // кольори границь таблиці без внутрішніх рядків
15
15
  --itf-table-border-base-width: 2px;
16
16
  --itf-table-hover-header-bg: #dfe5ef;
@@ -23,8 +23,6 @@
23
23
  --itf-table-summary-text: var(--bs-tertiary-color);
24
24
  --itf-table-table-border-radius: 1rem;
25
25
  --itf-table-header-height: 2.25rem;
26
- --itf-table-divider-bg: #F7F8FA;
27
- --itf-table-divider-border: rgba(238, 238, 238, 1);
28
26
 
29
27
  --group-title-height: 40px;
30
28
  --table-row-height: none;
@@ -45,9 +43,6 @@ body[data-theme="dark"] {
45
43
  --itf-table-selected-bg: #011534;
46
44
  --itf-table-active-bg: #022e72;
47
45
  --itf-table-summary-text: #82909d80;
48
- --itf-table-border-base-color: var(--itf-table-header-bg);
49
- --itf-table-divider-bg: #0f0f0f;
50
- --itf-table-divider-border: rgb(100, 100, 100, .1);
51
46
  }
52
47
  .itf-table2 {
53
48
  font-size: var(--itf-table-content-font-size, var(--itf-table-font-size));
@@ -65,7 +60,7 @@ body[data-theme="dark"] {
65
60
  height: 100%;
66
61
  }
67
62
  .scroller {
68
- //margin-bottom: .5rem;
63
+ margin-bottom: 12px;
69
64
  }
70
65
  .scrollable-x {
71
66
  overflow-x: scroll;
@@ -102,18 +97,34 @@ body[data-theme="dark"] {
102
97
  position: sticky;
103
98
  top: 0;
104
99
  bottom: 0;
105
- right: -5px;
100
+ right: -.5rem;
106
101
  z-index: 8;
107
- padding-right: 5px;
108
- padding-left: 5px;
109
102
  display: flex;
110
103
  align-items: center;
104
+
105
+ @media (max-width: 768px) {
106
+ position: relative;
107
+ opacity: 1;
108
+ }
111
109
  }
112
110
  .on-hover {
113
111
  opacity: 0;
112
+ width: 0;
113
+ padding: 4px .5rem;
114
+ overflow: hidden;
114
115
  pointer-events: none;
116
+ position: absolute;
117
+ right: 0;
118
+ background: linear-gradient(90deg, transparent 0, var(--itf-table2-row-bg) 10px);
119
+
120
+ @media (max-width: 768px) {
121
+ width: max-content;
122
+ opacity: 1;
123
+ position: relative;
124
+ }
115
125
  }
116
126
  .table-row-template:hover .on-hover {
127
+ width: max-content;
117
128
  opacity: 1;
118
129
  pointer-events: all;
119
130
  }
@@ -229,6 +240,9 @@ body[data-theme="dark"] {
229
240
  &:not(.draggable-container--is-dragging):hover .table-view-header-value {
230
241
  z-index: 39;
231
242
  }
243
+ &:not(.draggable-container--is-dragging):hover .sticky {
244
+ z-index: 40;
245
+ }
232
246
  &:after {
233
247
  content: "";
234
248
  position: absolute;
@@ -437,14 +451,20 @@ body[data-theme="dark"] {
437
451
  .indicator {
438
452
  border-left: var(--itf-table-border-base-width) solid var(--itf-table2-border-color);
439
453
  }
454
+
455
+ &.disabled {
456
+ .table-view-item-value {
457
+ opacity: 0.5;
458
+ }
459
+ }
440
460
  }
441
461
 
442
462
  &__row-divider {
443
- background-color: var(--itf-table-divider-bg);
463
+ background-color: #F7F8FA;
444
464
  height: 5px;
445
465
  padding: 0;
446
- border-top: 1px solid var(--itf-table-divider-border);
447
- border-bottom: 1px solid var(--itf-table-divider-border);
466
+ border-top: 1px solid rgba(238, 238, 238, 1);
467
+ border-bottom: 1px solid rgba(238, 238, 238, 1);
448
468
  }
449
469
  //&:hover, &.permanent-editable-border {
450
470
  // .table-view-item-value.editable {
@@ -457,7 +477,6 @@ body[data-theme="dark"] {
457
477
  position: relative;
458
478
  z-index: 2;
459
479
  width: 100%;
460
- display: flex;
461
480
  height: 100%;
462
481
  background: var(--itf-table2-row-bg)
463
482
  }
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="itf-money-field ph-no-capture" :class="{'currency-arrow': !currencyDisabled, 'currency-select': currencySelect}">
3
- <div :class="{'input-group h-100': noCurrencySign}" :style="`--itf-money-field-padding-left: ${noCurrencySign ? 1 : selectedCurrencySymbol.length * 0.6 + 1}rem`">
3
+ <div class="h-100" :class="{'input-group h-100': noCurrencySign}" :style="`--itf-money-field-padding-left: ${noCurrencySign ? 1 : selectedCurrencySymbol.length * 0.6 + 1}rem`">
4
4
  <span class="itf-money-field__prepend" v-if="!noCurrencySign">{{ selectedCurrencySymbol }}</span>
5
5
  <i-mask-component
6
6
  ref="input"
@@ -9,6 +9,7 @@
9
9
  :class="{ 'is-invalid': isInvalid(), 'is-valid': isSuccess() }"
10
10
  @input="setValue"
11
11
  :value="maskedValue"
12
+ :placeholder="placeholder"
12
13
  :unmask="false"
13
14
  :disabled="disabled"
14
15
  />
@@ -100,6 +101,7 @@ class itfMoneyField extends Vue {
100
101
  @Inject({ default: null }) itemLabel;
101
102
 
102
103
  @Model('input', { default: '' }) value;
104
+ @Prop({ default: '' }) placeholder;
103
105
  @Prop({ type: Object, default: null }) currency;
104
106
  @Prop({ type: Boolean, default: false }) noCurrencySign;
105
107
  @Prop({ type: Boolean, default: false }) disabled;
@@ -145,7 +147,7 @@ class itfMoneyField extends Vue {
145
147
  }
146
148
 
147
149
  onCurrencyChanged(e) {
148
- const currency = this.currenciesList.find((c) => c[this.itemKey] === parseInt(e.target.value));
150
+ const currency = this.currenciesList.find((c) => `${c[this.itemKey]}` === `${e.target.value}`);
149
151
  this.$emit('update:currency', currency)
150
152
  }
151
153
 
@@ -154,11 +156,11 @@ class itfMoneyField extends Vue {
154
156
  }
155
157
 
156
158
  get selectedCurrencySymbol() {
157
- return this.selectedCurrency ? this.selectedCurrency[this.symbolKey] : '#';
159
+ return this.selectedCurrency ? this.selectedCurrency[this.symbolKey] : '';
158
160
  }
159
161
 
160
162
  get selectedCurrencyCode() {
161
- return this.selectedCurrency ? this.selectedCurrency[this.codeKey] : '###';
163
+ return this.selectedCurrency ? this.selectedCurrency[this.codeKey] : '';
162
164
  }
163
165
 
164
166
  get currencyId() {
@@ -173,6 +175,10 @@ class itfMoneyField extends Vue {
173
175
  }
174
176
 
175
177
  setValue (val) {
178
+ if (val === '') {
179
+ this.$emit('input', '');
180
+ return;
181
+ }
176
182
  if (!isNumeric(val) || (val || '').toString().match(/\..*0$/)) { // що не видаляло останній нуль вкінці
177
183
  return;
178
184
  }
@@ -1,17 +1,18 @@
1
1
  <template>
2
2
 
3
- <div class="itf-text-field input-group" :class="{ 'with-addon addon-start': prependIcon, 'with-addon addon-end': clearable }">
3
+ <div class="itf-text-field input-group form-control p-0" :class="{ 'is-invalid': isInvalid(), 'is-valid': isSuccess() }">
4
4
  <slot name="addon">
5
- <div class="addon" v-if="prependIcon">
6
- <itf-icon :name="prependIcon"/>
5
+ <div class="input-group-text prepend text-muted" v-if="prependIcon">
6
+ <itf-icon :size="small ? 18 : 20" :name="prependIcon"/>
7
7
  </div>
8
8
  </slot>
9
9
 
10
10
  <input
11
+ :name="`text-field-${_uid}`"
11
12
  ref="input"
12
13
  autocomplete="off"
13
14
  :placeholder="placeholder"
14
- :class="{ 'is-invalid': isInvalid(), 'is-valid': isSuccess(), 'form-control-sm': small }"
15
+ :class="{ 'form-control-sm': small }"
15
16
  class="itf-text-field__input form-control"
16
17
  :type="type"
17
18
  :value="value"
@@ -24,12 +25,16 @@
24
25
  @blur="$emit('blur', $event)"
25
26
  @focus="$emit('focus', $event)"
26
27
  @change="$emit('change', $event.target.value)"
28
+ :maxlength="maxlength"
27
29
  :min="min"
28
30
  :max="max"
29
31
  :step="step"
30
32
  />
33
+ <div class="input-group-text append text-muted" v-if="postfix">
34
+ {{ postfix }}
35
+ </div>
31
36
 
32
- <div class="addon-end" v-if="clearable && value">
37
+ <template v-if="clearable && value">
33
38
  <slot name="clear">
34
39
  <itf-button
35
40
  icon
@@ -39,7 +44,7 @@
39
44
  <itf-icon name="close" />
40
45
  </itf-button>
41
46
  </slot>
42
- </div>
47
+ </template>
43
48
  </div>
44
49
 
45
50
  </template>
@@ -64,10 +69,14 @@ class itfTextField extends Vue {
64
69
  @Prop() step;
65
70
  @Prop() min;
66
71
  @Prop() max;
72
+ @Prop() maxlength;
73
+ @Prop() postfix;
67
74
  @Prop(Boolean) clearable;
68
75
  @Prop(Boolean) disabled;
69
76
  @Prop(Boolean) readonly;
70
77
  @Prop(Boolean) small;
78
+ @Prop({ type: Boolean, default: undefined }) invalid;
79
+ @Prop({ type: Boolean, default: undefined }) valid;
71
80
  @Prop({ type: String, default: 'text' }) type;
72
81
  @Prop({ type: [Number, String], default: 0 }) delayInput;
73
82
 
@@ -78,11 +87,11 @@ class itfTextField extends Vue {
78
87
  }
79
88
 
80
89
  isInvalid() {
81
- return this.itemLabel && this.itemLabel.isHasError();
90
+ return typeof this.invalid !== 'undefined' ? this.invalid : (this.itemLabel && this.itemLabel.isHasError());
82
91
  }
83
92
 
84
93
  isSuccess() {
85
- return this.itemLabel && this.itemLabel.isHasSuccess();
94
+ return typeof this.valid !== 'undefined' ? this.valid : (this.itemLabel && this.itemLabel.isHasSuccess());
86
95
  }
87
96
 
88
97
  insertTextToCurrentPosition(text) {
@@ -25,10 +25,11 @@
25
25
  @keyup.enter="(e)=>{$emit('click',{event:e,ele:e.target,node,knode})}"
26
26
  @click="(e)=>{$emit('click',{event:e,ele:e.target,node,knode})}"
27
27
  >
28
- <div v-if="node.level >= toggleStartLevel" class="itf-tree-editor_node_toggle ps-2">
28
+ <div v-if="node.level >= toggleStartLevel" class="itf-tree-editor_node_toggle">
29
29
  <itf-button
30
- v-if="autoToggleTree && node.level >= toggleStartLevel && node.Children && node.Children.length > 0"
30
+ v-if="autoToggleTree && node.level >= toggleStartLevel && node[itemChildren] && node[itemChildren].length > 0"
31
31
  small
32
+ icon
32
33
  @click.stop="toggleNode($event, node, knode)"
33
34
  >
34
35
  <itf-icon v-if="isNodeToggled(node)" name="plus" size="24" />
@@ -4,25 +4,26 @@
4
4
  <itf-filter-panel
5
5
  :search-placeholder="searchPlaceholder"
6
6
  search
7
- show-filter
7
+ :visible="!noFilters"
8
+ :filters-only="filtersOnly"
9
+ ref="filters"
10
+ :mini="panel.isMultiple()"
8
11
  class="py-2 px-3"
9
- :static-filters="filters"
10
12
  :endpoint="filtersEndpoint"
11
13
  :panel="panel"
12
14
  v-model="filter"
13
15
  @loaded="onFilterSet($event, true)"
14
16
  @change="onFilterSet($event, false)"
15
- @set-table-schema="setTableSchema"
16
17
  >
17
18
  <template #after-filter-btn>
18
- <itf-dropdown v-if="$refs.table && tableSchema" shadow append-to-context :button-options="{ default: true, icon: true }" class="h-100" autoclose="outside">
19
+ <itf-dropdown v-if="$refs.table && schema" shadow append-to-context :button-options="{ default: true, icon: true }" class="h-100" autoclose="outside">
19
20
  <template #button>
20
- <itf-icon new name="table-config" />
21
+ <itf-icon new name="table-view" />
21
22
  </template>
22
23
  <div class="dropdown-header">
23
24
  {{ $t('components.table.columns') }}
24
25
  </div>
25
- <a v-for="(property, n) of tableSchema.properties" :key="n" href="" @click.stop.prevent="$refs.table.toggleVisibility(property.property)" class="dropdown-item justify-content-between d-flex gap-3">
26
+ <a v-for="(property, n) of schema.properties" :key="n" href="" @click.stop.prevent="$refs.table.toggleVisibility(property.property)" class="dropdown-item justify-content-between d-flex gap-3">
26
27
  <div class="d-flex align-items-center gap-1">
27
28
  <itf-icon v-if="property.icon" :size="24" new :name="property.icon" />
28
29
  {{getTitle(property.title)}}
@@ -41,101 +42,64 @@
41
42
  </div>
42
43
  </a>
43
44
  </itf-dropdown>
44
- <itf-dropdown v-if="downloadEndpoint" shadow append-to-context :button-options="{ default: true, small: true }" class="h-100" autoclose="outside">
45
- <template #button>
46
- <itf-icon name="download"/>
47
- {{ $t('export') }}
48
- </template>
49
- <a v-for="(item, n) in getDownloadLinks()" target="_blank" :key="n" :href="item.link" class="dropdown-item">
50
- {{item.title}}
51
- </a>
52
- </itf-dropdown>
53
-
54
- <slot name="before-tabs"></slot>
55
-
56
- <itf-segmented-control
57
- v-if="tabs.length > 1"
58
- class="small"
59
- v-model="currentTab"
60
- item-key="value"
61
- :items="tabs"
62
- >
63
- <template #item="{ item }">
64
- <div class="d-flex align-items-center">
65
- <itf-icon class="text-muted" new :name="item.icon" />
66
- {{item.text}}
67
- </div>
68
- </template>
69
- </itf-segmented-control>
70
45
  </template>
71
46
  </itf-filter-panel>
72
47
 
73
- <div v-if="currentTab === 'list'" class="position-relative flex-grow-1">
74
- <div class="position-absolute" style="top: 0; left: 0; right: 0; bottom: 0; overflow: auto;">
75
- <slot name="list-view" :items="items" :loading="loading"></slot>
48
+ <div class="flex-grow-1 px-3 d-flex flex-column">
49
+ <div class="position-relative flex-grow-1">
50
+ <itf-table
51
+ ref="table"
52
+ style="--shadow-area-width: 0px;"
53
+ absolute
54
+ striped
55
+ clickable
56
+ column-sorting
57
+ column-resizing
58
+ :indicator-type="indicatorType"
59
+ class="permanent-checkboxes"
60
+ divider-property="hasDivider"
61
+ subrows-property="children"
62
+ :state-name="stateName"
63
+ id-property="id"
64
+ :rows="preparedItems"
65
+ :schema="schema"
66
+ :sorting="sorting"
67
+ :active="activeIds"
68
+ :show-actions="showActions"
69
+ :expanded-ids.sync="expandedIds"
70
+ v-model="selectedIds"
71
+ @row-click="$emit('open', $event)"
72
+ @update:sorting="updateSorting($event)"
73
+ >
74
+ <template v-for="(_, name) in $slots" #[name]="slotData">
75
+ <slot :name="name" v-bind="slotData || {}"/>
76
+ </template>
77
+ <template v-for="(_, name) in $scopedSlots" #[name]="slotData">
78
+ <slot :name="name" v-bind="slotData || {}"/>
79
+ </template>
80
+ </itf-table>
76
81
  </div>
77
82
  </div>
78
- <slot v-else-if="currentTab === 'board'" name="kanban-view"></slot>
79
- <slot v-else-if="currentTab === 'calendar'" name="calendar-view"></slot>
80
- <slot v-else name="table-view">
81
- <div class="flex-grow-1 px-3 d-flex flex-column">
82
- <div class="position-relative flex-grow-1">
83
- <itf-table
84
- ref="table"
85
- style="--shadow-area-width: 0px;"
86
- absolute
87
- striped
88
- clickable
89
- column-sorting
90
- column-resizing
91
- :indicator-type="indicatorType"
92
- class="permanent-checkboxes"
93
- :state-name="stateName"
94
- id-property="id"
95
- :sort-as-string="sortAsString"
96
- :rows="items"
97
- :group-by="groupBy"
98
- :schema="tableSchema"
99
- :sorting.sync="sorting"
100
- :active="activeIds"
101
- :no-select-all="noSelectAll"
102
- :show-actions="showActions"
103
- :indicator-width="indicatorWidth"
104
- v-model="selectedIds"
105
- @row-click="$emit('open', $event)"
106
- @update:sorting="updateSorting($event)"
107
- >
108
- <template v-for="(_, name) in $slots" #[name]="slotData">
109
- <slot :name="name" v-bind="slotData || {}"/>
110
- </template>
111
- <template v-for="(_, name) in $scopedSlots" #[name]="slotData">
112
- <slot :name="name" v-bind="slotData || {}"/>
113
- </template>
114
- </itf-table>
115
- </div>
116
- </div>
117
- </slot>
118
83
 
119
84
  <itf-pagination
120
85
  class="my-2 px-3"
121
- v-if="showPagination"
122
86
  show-size
123
87
  :size="size"
124
- :items="items"
88
+ :items="preparedItems"
125
89
  :pages="countPages"
126
90
  :value="page"
127
91
  @input="updatePage($event)"
128
92
  @per-page="updateSizePerPage($event)"
129
93
  >
130
94
  <template #center>
131
- <slot name="pagination-center" :totals="totals" />
95
+ <slot name="pagination-center" />
132
96
  </template>
133
97
  </itf-pagination>
134
98
  </div>
135
99
 
136
100
  </template>
137
101
  <script>
138
- import {Vue, ModelSync, Component, Prop, Inject, PropSync, Watch} from 'vue-property-decorator';
102
+ import { Vue, ModelSync, Component, Prop, Inject } from 'vue-property-decorator';
139
103
  import loading from '../../directives/loading';
140
104
  import itfTable from '../table/Table2.vue';
141
105
  import itfFilterPanel from '../filter/FilterPanel.vue';
@@ -143,16 +107,11 @@ import itfPagination from '../pagination/Pagination2.vue';
143
107
  import itfTableBody from "../table/TableBody.vue";
144
108
  import itfIcon from "../icon/Icon.vue";
145
109
  import itfDropdown from "../dropdown/Dropdown.vue";
146
- import itfSegmentedControl from '../segmented-control/SegmentedControl.vue';
147
- import itfButton from '@itfin/components/src/components/button/Button.vue';
148
110
 
149
111
  export default @Component({
150
112
  name: 'itfView',
151
113
  components: {
152
- itfButton,
153
- itfSegmentedControl,
154
- itfDropdown,
155
- itfIcon,
114
+ itfDropdown, itfIcon,
156
115
  itfPagination,
157
116
  itfFilterPanel,
158
117
  itfTableBody,
@@ -167,32 +126,24 @@ class itfView extends Vue {
167
126
  @ModelSync('value', 'input') selectedIds;
168
127
 
169
128
  @Prop({ type: Boolean }) loading;
129
+ @Prop({ type: Boolean }) filtersOnly;
130
+ @Prop({ type: Boolean }) noFilters;
170
131
  @Prop({ type: Array }) filters;
171
- @Prop({ type: Object }) schema;
132
+ @Prop({ type: Object, required: true }) schema;
133
+ // @Prop({ default: 20 }) size;
134
+ // @Prop({ default: 1 }) page;
172
135
  @Prop(String) defaultSorting;
173
136
  @Prop(String) endpoint;
174
137
  @Prop(String) filtersEndpoint;
175
138
  @Prop(String) itemsKey;
176
- @Prop({ type: String, default: null }) groupBy;
177
- @Prop({ type: String, default: null }) downloadEndpoint; // префікс апі для завантаження
178
- @Prop({ type: String, default: 'totals' }) totalsKey;
179
139
  @Prop(String) panelKey;
180
140
  @Prop(String) stateName;
181
141
  @Prop({ type: String, default: 'checkbox' }) indicatorType;
182
- @Prop({ type: String, default: 'list' }) tab;
183
142
  @Prop({ type: String, default () { return this.$t('components.table.search'); } }) searchPlaceholder;
184
143
  @Prop() panel;
144
+ @Prop() hardFilter; // встановлює жорсткий фільтр, наприклад, треба завжди показувати лише по контрагенту
185
145
  @Prop(Boolean) showActions;
186
- @Prop({ type: Boolean, default: true }) showPagination;
187
- @Prop(Boolean) listViewEnabled;
188
- @Prop(Boolean) kanbanViewEnabled;
189
- @Prop(Boolean) calendarViewEnabled;
190
- @Prop(Boolean) noSelectAll;
191
- @Prop({ type: Boolean, default: true }) tableViewEnabled;
192
- @Prop(Boolean) sortAsString;
193
- @Prop(Boolean) oldFormat;
194
- @Prop({ default: 45 }) indicatorWidth;
195
- @Prop({type: Function, default: null }) onSplitSlectedIds // якщо потрібно розділяти вибрані рядки в таблиці на дві групи
146
+ @Prop({ type: Array, default: () => [] }) disabledIds;
196
147
 
197
148
  page = 1;
198
149
  total = 0;
@@ -202,74 +153,11 @@ class itfView extends Vue {
202
153
  filter = {};
203
154
  loadingData = false;
204
155
  activeIds = [];
205
- tableColumns = null;
206
- totals = null;
207
-
208
- @Watch('selectedIds', { deep: true, immediate: true })
209
- updateSelectedIds() {
210
- if(this.onSplitSlectedIds && this.items.length && this.selectedIds.length) {
211
- this.onSplitSlectedIds(this.selectedIds, this.items);
212
- }
213
- }
214
-
215
- getDownloadLinks() {
216
- const state = this.$refs.table ? this.$refs.table.getTableState() : null;
217
- const filter = { ...this.filter };
218
- const sorting = this.sorting;
219
- const filterableColumnsNames = (state?.columns ?? []).filter(column => column.visible).map(column => column.property);
220
-
221
- const filterWithValue = Object.fromEntries(Object.entries(filter).filter(([_, value]) => typeof value !== 'undefined'));
222
- const params = {
223
- ...filterWithValue,
224
- sort: sorting
225
- };
226
- if (filterableColumnsNames.length) {
227
- params.columns = filterableColumnsNames.join(',')
228
- }
229
- const xlsQueryParams = new URLSearchParams({ ...params, format: 'xlsx' }).toString();
230
- const csvQueryParams = new URLSearchParams({ ...params, format: 'csv' }).toString();
231
- return [
232
- { title: 'Excel (xlsx)', link: `${this.downloadEndpoint}?${xlsQueryParams}` },
233
- { title: 'Plain text (csv)', link: `${this.downloadEndpoint}?${csvQueryParams}` },
234
- ];
235
- }
236
-
237
- get currentTab() {
238
- return this.tab;
239
- }
156
+ expandedIds = [];
240
157
 
241
- set currentTab(val) {
242
- this.$emit('update:tab', val);
243
- this.setPanelPayload({ tab: val });
244
- }
245
-
246
- get tabs() {
247
- const views = [];
248
- if (this.listViewEnabled) {
249
- views.push({ value: 'list', text: this.$t('list'), icon: 'list-view' });
250
- }
251
- if (this.kanbanViewEnabled) {
252
- views.push({ value: 'board', text: this.$t('board'), icon: 'kanban-view' });
253
- }
254
- if (this.calendarViewEnabled) {
255
- views.push({ value: 'calendar', text: this.$t('calendar'), icon: 'calendar-view' });
256
- }
257
- if (this.tableViewEnabled) {
258
- views.push({ value: 'table', text: this.$t('table'), icon: 'table-view' });
259
- }
260
- return views;
261
- }
262
-
263
- get tableSchema() {
264
- if (this.tableColumns) {
265
- return {
266
- properties: this.tableColumns
267
- }
268
- } else if (this.schema) {
269
- return this.schema
270
- } else {
271
- return {}
272
- }
158
+ get preparedItems() {
159
+ const disabledIdsSet = new Set(this.disabledIds);
160
+ return this.items.map(item => ({ ...item, isDisabled: disabledIdsSet.has(item.id) }));
273
161
  }
274
162
 
275
163
  created() {
@@ -291,42 +179,39 @@ class itfView extends Vue {
291
179
  }
292
180
  }
293
181
 
294
- async loadData() {
182
+ async loadData(reloadFilters = false) {
295
183
  if (!this.endpoint) {
296
184
  return;
297
185
  }
186
+ if (reloadFilters) {
187
+ this.loadFilters();
188
+ }
298
189
  this.$emit('load', this.filter);
299
190
  this.loadingData = true;
300
191
  await this.$try(async () => {
301
- let filter = { ...this.filter };
302
- if (this.oldFormat) {
303
- filter = Object.keys(filter).reduce((acc, key) => {
304
- acc[`filter[${key}]`] = filter[key];
305
- return acc;
306
- }, {})
307
- }
308
- const { data, headers } = await this.$axios.get(this.endpoint, {
192
+ const res = await this.$axios.$get(this.endpoint, {
193
+ preventRaceCondition: true,
309
194
  params: {
310
- ...filter,
195
+ ...Object.assign(this.filter ?? {}, this.hardFilter ?? {}),
311
196
  page: this.page,
312
197
  size: this.size,
313
198
  sort: this.sorting
314
199
  }
315
200
  });
316
- if (this.oldFormat) {
317
- this.items = data;
318
- this.page = Number(headers['x-page'] ?? 1);
319
- this.total = Number(headers['x-count'] ?? 0);
320
- this.size = Number(headers['x-size'] ?? 20);
321
- } else {
322
- this.items = data[this.itemsKey];
323
- this.totals = data[this.totalsKey];
324
- this.page = data.meta.page;
325
- this.total = data.meta.total;
326
- this.size = data.meta.size;
201
+ this.selectedIds = [];
202
+ this.items = res[this.itemsKey];
203
+ this.page = res.meta.page;
204
+ this.total = res.meta.total;
205
+ this.size = res.meta.size;
206
+ if (res.columns) {
207
+ this.$emit('columns-loaded', res.columns);
327
208
  }
209
+
210
+ this.$emit('update:items', this.items);
211
+ this.loadingData = false;
212
+ }, () => {
213
+ this.loadingData = false;
328
214
  });
329
- this.loadingData = false;
330
215
  this.$emit('loaded', this.filter);
331
216
  }
332
217
 
@@ -349,16 +234,14 @@ class itfView extends Vue {
349
234
 
350
235
  updatePage (val) {
351
236
  this.page = val;
352
- this.selectedIds = [];
353
- this.setPanelPayload({ page: val });
237
+ this.setPanelPayload({ page: val === 1 ? null : val });
354
238
  this.loadData();
355
239
  }
356
240
 
357
241
  updateSizePerPage (val) {
358
242
  this.page = 1;
359
243
  this.size = val;
360
- this.selectedIds = [];
361
- this.setPanelPayload({ page: 1, size: val });
244
+ this.setPanelPayload({ page: null, size: val });
362
245
  this.loadData();
363
246
  localStorage.setItem('sizePerPage', val);
364
247
  }
@@ -394,20 +277,10 @@ class itfView extends Vue {
394
277
  this.loadData();
395
278
  }
396
279
 
397
- setTableSchema(tableSchema) {
398
- this.tableColumns = tableSchema;
399
- }
400
-
401
- getSorting() {
402
- return this.sorting;
403
- }
404
-
405
- getFilter() {
406
- return this.filter;
407
- }
408
-
409
- getTableState() {
410
- return this.$refs.table ? this.$refs.table.getTableState() : null;
280
+ loadFilters() {
281
+ if (this.filtersEndpoint) {
282
+ this.$refs.filters?.loadData();
283
+ }
411
284
  }
412
285
  }
413
286
  </script>