@itfin/components 1.4.35 → 1.5.0

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 (202) hide show
  1. package/package.json +17 -20
  2. package/src/ITFSettings.js +6 -0
  3. package/src/assets/scss/_css_variables.scss +2 -7
  4. package/src/assets/scss/_dark-theme.scss +2 -12
  5. package/src/assets/scss/_variables.scss +34 -9
  6. package/src/assets/scss/components/_button.scss +147 -10
  7. package/src/assets/scss/components/_checkbox.scss +9 -0
  8. package/src/assets/scss/components/_datepicker.scss +3 -3
  9. package/src/assets/scss/components/_pagination.scss +4 -1
  10. package/src/assets/scss/components/_popover.scss +22 -0
  11. package/src/assets/scss/components/_segmeneted-control.scss +19 -8
  12. package/src/assets/scss/components/_select.scss +6 -8
  13. package/src/assets/scss/components/_text-field.scss +27 -11
  14. package/src/assets/scss/components/select/_dropdown-menu.scss +1 -0
  15. package/src/assets/scss/components/select/_dropdown-toggle.scss +0 -1
  16. package/src/assets/scss/directives/tooltip.scss +10 -5
  17. package/src/assets/scss/main.scss +48 -0
  18. package/src/components/alert/AlertBanner.vue +75 -0
  19. package/src/components/app/App.vue +1 -1
  20. package/src/components/button/Button.vue +3 -1
  21. package/src/components/button/NativeButton.js +4 -0
  22. package/src/components/button/index.stories.js +2 -2
  23. package/src/components/checkbox/Checkbox.vue +2 -1
  24. package/src/components/checkbox/RadioBox.vue +1 -2
  25. package/src/components/copyToClipboard/CopyToClipboard.vue +4 -1
  26. package/src/components/customize/PropertiesList.vue +0 -2
  27. package/src/components/customize/PropertiesPopupMenu.vue +1 -1
  28. package/src/components/customize/PropertyItem.vue +6 -24
  29. package/src/components/datepicker/DatePicker.vue +3 -1
  30. package/src/components/datepicker/DatePickerInline.vue +2 -2
  31. package/src/components/datepicker/DateRangePickerInline.vue +6 -1
  32. package/src/components/dropdown/Dropdown.vue +1 -1
  33. package/src/components/dropdown/DropdownMenu.vue +1 -1
  34. package/src/components/editable/EditButton.vue +1 -1
  35. package/src/components/filter/FilterBadge.vue +20 -1
  36. package/src/components/filter/FilterFacetsList.vue +67 -13
  37. package/src/components/filter/FilterPanel.vue +39 -14
  38. package/src/components/filter/NewFilter.vue +305 -0
  39. package/src/components/form/Label.vue +5 -5
  40. package/src/components/icon/components/nomi-ai-alt.vue +5 -0
  41. package/src/components/icon/components/nomi-arrow-right.vue +4 -0
  42. package/src/components/icon/components/nomi-bell.vue +5 -0
  43. package/src/components/icon/components/nomi-calendar-payment.vue +10 -0
  44. package/src/components/icon/components/nomi-card-plus.vue +1 -0
  45. package/src/components/icon/components/nomi-cash-provider.vue +9 -0
  46. package/src/components/icon/components/nomi-cash-repeat.vue +6 -0
  47. package/src/components/icon/components/nomi-category-edit.vue +5 -0
  48. package/src/components/icon/components/nomi-chavron-up.vue +4 -0
  49. package/src/components/icon/components/nomi-chavron_down.vue +4 -0
  50. package/src/components/icon/components/nomi-chavron_up.vue +4 -0
  51. package/src/components/icon/components/nomi-chevron-up.vue +4 -0
  52. package/src/components/icon/components/nomi-exit-right.vue +4 -0
  53. package/src/components/icon/components/nomi-help.vue +2 -3
  54. package/src/components/icon/components/nomi-history.vue +7 -0
  55. package/src/components/icon/components/nomi-lock.vue +1 -1
  56. package/src/components/icon/components/nomi-pen-alt.vue +4 -0
  57. package/src/components/icon/components/nomi-project.vue +2 -2
  58. package/src/components/icon/components/nomi-refresh-off.vue +4 -0
  59. package/src/components/icon/components/nomi-refresh.vue +4 -0
  60. package/src/components/icon/components/nomi-scissors.vue +1 -1
  61. package/src/components/icon/components/nomi-start.vue +28 -0
  62. package/src/components/icon/components/nomi-table-view.vue +1 -4
  63. package/src/components/icon/components/nomi-transactions-delete.vue +5 -0
  64. package/src/components/icon/components/nomi-type-array.vue +6 -0
  65. package/src/components/icon/components/nomi-type-boolean.vue +5 -0
  66. package/src/components/icon/components/nomi-type-date.vue +4 -0
  67. package/src/components/icon/components/nomi-type-null.vue +4 -0
  68. package/src/components/icon/components/nomi-type-number.vue +4 -0
  69. package/src/components/icon/components/nomi-type-object.vue +4 -0
  70. package/src/components/icon/components/nomi-type-string.vue +4 -0
  71. package/src/components/icon/components/nomi-unarchive.vue +17 -0
  72. package/src/components/icon/components/nomi-unlink.vue +10 -0
  73. package/src/components/icon/components/nomi-user.vue +3 -3
  74. package/src/components/icon/components/nomi-warning-triangle.vue +6 -0
  75. package/src/components/icon/components/nomi-warning_triangle_filled.vue +6 -0
  76. package/src/components/icon/convert-icons.js +3 -0
  77. package/src/components/icon/icons.js +390 -312
  78. package/src/components/icon/new-icons/ai-alt.svg +4 -0
  79. package/src/components/icon/new-icons/arrow-right-alt.svg +3 -0
  80. package/src/components/icon/new-icons/arrow-right.svg +3 -0
  81. package/src/components/icon/new-icons/arrow_left.svg +3 -0
  82. package/src/components/icon/new-icons/automation.svg +4 -0
  83. package/src/components/icon/new-icons/balance.svg +3 -0
  84. package/src/components/icon/new-icons/balance_turnover.svg +4 -0
  85. package/src/components/icon/new-icons/bar-horizontal.svg +6 -0
  86. package/src/components/icon/new-icons/bell.svg +4 -0
  87. package/src/components/icon/new-icons/calendar-payment.svg +9 -0
  88. package/src/components/icon/new-icons/card-plus.svg +1 -0
  89. package/src/components/icon/new-icons/cash-provider.svg +8 -0
  90. package/src/components/icon/new-icons/cash-repeat.svg +5 -0
  91. package/src/components/icon/new-icons/cash.svg +3 -0
  92. package/src/components/icon/new-icons/cashflow.svg +3 -0
  93. package/src/components/icon/new-icons/category-edit.svg +4 -0
  94. package/src/components/icon/new-icons/category.svg +4 -0
  95. package/src/components/icon/new-icons/category_alt.svg +3 -0
  96. package/src/components/icon/new-icons/chart-bars.svg +5 -0
  97. package/src/components/icon/new-icons/chart-donut.svg +3 -0
  98. package/src/components/icon/new-icons/chart-funnel.svg +5 -0
  99. package/src/components/icon/new-icons/chart-kpi.svg +7 -0
  100. package/src/components/icon/new-icons/chart-line.svg +4 -0
  101. package/src/components/icon/new-icons/chart-lines.svg +5 -0
  102. package/src/components/icon/new-icons/check-alt.svg +3 -0
  103. package/src/components/icon/new-icons/check.svg +3 -0
  104. package/src/components/icon/new-icons/chevron-down.svg +3 -0
  105. package/src/components/icon/new-icons/chevron-left.svg +3 -0
  106. package/src/components/icon/new-icons/chevron-right.svg +3 -0
  107. package/src/components/icon/new-icons/chevron-up.svg +3 -0
  108. package/src/components/icon/new-icons/collapse.svg +6 -0
  109. package/src/components/icon/new-icons/control-panel.svg +7 -0
  110. package/src/components/icon/new-icons/credit.svg +3 -0
  111. package/src/components/icon/new-icons/currencies.svg +3 -0
  112. package/src/components/icon/new-icons/debt.svg +3 -0
  113. package/src/components/icon/new-icons/demo.svg +6 -0
  114. package/src/components/icon/new-icons/dev.svg +3 -0
  115. package/src/components/icon/new-icons/dots.svg +5 -0
  116. package/src/components/icon/new-icons/duplicate.svg +4 -0
  117. package/src/components/icon/new-icons/exit-right.svg +3 -0
  118. package/src/components/icon/new-icons/export.svg +3 -0
  119. package/src/components/icon/new-icons/file.svg +3 -0
  120. package/src/components/icon/new-icons/folder.svg +3 -0
  121. package/src/components/icon/new-icons/goods-turnover.svg +3 -0
  122. package/src/components/icon/new-icons/goods.svg +4 -0
  123. package/src/components/icon/new-icons/help-alt.svg +3 -0
  124. package/src/components/icon/new-icons/help.svg +2 -3
  125. package/src/components/icon/new-icons/history.svg +6 -0
  126. package/src/components/icon/new-icons/integration.svg +3 -0
  127. package/src/components/icon/new-icons/link.svg +5 -0
  128. package/src/components/icon/new-icons/lock.svg +1 -1
  129. package/src/components/icon/new-icons/menu.svg +5 -0
  130. package/src/components/icon/new-icons/minus.svg +3 -0
  131. package/src/components/icon/new-icons/payment_calendar.svg +3 -0
  132. package/src/components/icon/new-icons/pc.svg +3 -0
  133. package/src/components/icon/new-icons/pen-alt.svg +3 -0
  134. package/src/components/icon/new-icons/planFact.svg +4 -0
  135. package/src/components/icon/new-icons/pnl.svg +7 -0
  136. package/src/components/icon/new-icons/project.svg +2 -2
  137. package/src/components/icon/new-icons/project_alt.svg +3 -0
  138. package/src/components/icon/new-icons/project_alt2.svg +3 -0
  139. package/src/components/icon/new-icons/promo.svg +3 -0
  140. package/src/components/icon/new-icons/refresh-off.svg +3 -0
  141. package/src/components/icon/new-icons/refresh.svg +3 -0
  142. package/src/components/icon/new-icons/scissors.svg +1 -1
  143. package/src/components/icon/new-icons/segment.svg +3 -0
  144. package/src/components/icon/new-icons/start.svg +27 -0
  145. package/src/components/icon/new-icons/strongbox.svg +3 -0
  146. package/src/components/icon/new-icons/subscription.svg +3 -0
  147. package/src/components/icon/new-icons/table-view.svg +1 -4
  148. package/src/components/icon/new-icons/time.svg +3 -0
  149. package/src/components/icon/new-icons/transactions_alt.svg +6 -0
  150. package/src/components/icon/new-icons/transactions_delete.svg +4 -0
  151. package/src/components/icon/new-icons/type-array.svg +5 -0
  152. package/src/components/icon/new-icons/type-boolean.svg +4 -0
  153. package/src/components/icon/new-icons/type-date.svg +3 -0
  154. package/src/components/icon/new-icons/type-null.svg +3 -0
  155. package/src/components/icon/new-icons/type-number.svg +3 -0
  156. package/src/components/icon/new-icons/type-object.svg +3 -0
  157. package/src/components/icon/new-icons/type-string.svg +3 -0
  158. package/src/components/icon/new-icons/types.svg +6 -0
  159. package/src/components/icon/new-icons/unarchive.svg +16 -0
  160. package/src/components/icon/new-icons/unlink.svg +9 -0
  161. package/src/components/icon/new-icons/user.svg +3 -3
  162. package/src/components/icon/new-icons/user_plus.svg +10 -0
  163. package/src/components/icon/new-icons/warehouse.svg +3 -0
  164. package/src/components/icon/new-icons/warning_triangle.svg +5 -0
  165. package/src/components/icon/new-icons/warning_triangle_filled.svg +5 -0
  166. package/src/components/kanban/BoardCard.vue +1 -1
  167. package/src/components/kanban/BoardCardTimer.vue +1 -1
  168. package/src/components/modal/DeleteConfirmModal.vue +10 -6
  169. package/src/components/modal/ItemEditor.vue +1 -1
  170. package/src/components/modal/Modal.vue +1 -1
  171. package/src/components/overlay/SensitiveOverlay.vue +2 -4
  172. package/src/components/panels/Panel.vue +110 -23
  173. package/src/components/panels/PanelItemEdit.vue +1 -1
  174. package/src/components/panels/PanelList.vue +65 -11
  175. package/src/components/popover/Popover.vue +105 -22
  176. package/src/components/segmented-control/SegmentedControl.vue +9 -3
  177. package/src/components/sortable/draggable.js +1 -1
  178. package/src/components/table/Table2.vue +8 -3
  179. package/src/components/table/TableBody.vue +17 -16
  180. package/src/components/table/TableGroup.vue +38 -12
  181. package/src/components/table/TableHeader.vue +83 -73
  182. package/src/components/table/TableRows.vue +15 -9
  183. package/src/components/table/mobile.js +4 -0
  184. package/src/components/table/table2.scss +9 -0
  185. package/src/components/text-field/MoneyField.vue +10 -4
  186. package/src/components/text-field/TextField.vue +17 -8
  187. package/src/components/tree/TreeEditor.vue +3 -2
  188. package/src/components/view/View.vue +86 -214
  189. package/src/directives/appendToBody.js +1 -0
  190. package/src/helpers/validators.js +9 -35
  191. package/src/helpers/validators.spec.js +11 -48
  192. package/src/locales/en.js +4 -6
  193. package/src/locales/pl.js +158 -0
  194. package/src/locales/uk.js +6 -7
  195. package/src/components/icon/components/nomi-calendar-view.vue +0 -4
  196. package/src/components/icon/components/nomi-kanban-view.vue +0 -6
  197. package/src/components/icon/components/nomi-list-view.vue +0 -7
  198. package/src/components/icon/components/nomi-table-config.vue +0 -9
  199. package/src/components/icon/new-icons/calendar-view.svg +0 -3
  200. package/src/components/icon/new-icons/kanban-view.svg +0 -5
  201. package/src/components/icon/new-icons/list-view.svg +0 -6
  202. package/src/components/icon/new-icons/table-config.svg +0 -8
@@ -4,24 +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
- @input="onFilterSet"
14
- @set-table-schema="setTableSchema"
15
+ @loaded="onFilterSet($event, true)"
16
+ @change="onFilterSet($event, false)"
15
17
  >
16
18
  <template #after-filter-btn>
17
- <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">
18
20
  <template #button>
19
- <itf-icon new name="table-config" />
21
+ <itf-icon new name="table-view" />
20
22
  </template>
21
23
  <div class="dropdown-header">
22
24
  {{ $t('components.table.columns') }}
23
25
  </div>
24
- <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">
25
27
  <div class="d-flex align-items-center gap-1">
26
28
  <itf-icon v-if="property.icon" :size="24" new :name="property.icon" />
27
29
  {{getTitle(property.title)}}
@@ -40,101 +42,61 @@
40
42
  </div>
41
43
  </a>
42
44
  </itf-dropdown>
43
- <itf-dropdown v-if="downloadEndpoint" shadow append-to-context :button-options="{ default: true, small: true }" class="h-100" autoclose="outside">
44
- <template #button>
45
- <itf-icon name="download"/>
46
- {{ $t('export') }}
47
- </template>
48
- <a v-for="(item, n) in getDownloadLinks()" target="_blank" :key="n" :href="item.link" class="dropdown-item">
49
- {{item.title}}
50
- </a>
51
- </itf-dropdown>
52
-
53
- <slot name="before-tabs"></slot>
54
-
55
- <itf-segmented-control
56
- v-if="tabs.length > 1"
57
- class="small"
58
- v-model="currentTab"
59
- item-key="value"
60
- :items="tabs"
61
- >
62
- <template #item="{ item }">
63
- <div class="d-flex align-items-center">
64
- <itf-icon class="text-muted" new :name="item.icon" />
65
- {{item.text}}
66
- </div>
67
- </template>
68
- </itf-segmented-control>
69
45
  </template>
70
46
  </itf-filter-panel>
71
47
 
72
- <div v-if="currentTab === 'list'" class="position-relative flex-grow-1">
73
- <div class="position-absolute" style="top: 0; left: 0; right: 0; bottom: 0; overflow: auto;">
74
- <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
+ :state-name="stateName"
61
+ id-property="id"
62
+ :rows="preparedItems"
63
+ :schema="schema"
64
+ :sorting="sorting"
65
+ :active="activeIds"
66
+ :show-actions="showActions"
67
+ v-model="selectedIds"
68
+ @row-click="$emit('open', $event)"
69
+ @update:sorting="updateSorting($event)"
70
+ >
71
+ <template v-for="(_, name) in $slots" #[name]="slotData">
72
+ <slot :name="name" v-bind="slotData || {}"/>
73
+ </template>
74
+ <template v-for="(_, name) in $scopedSlots" #[name]="slotData">
75
+ <slot :name="name" v-bind="slotData || {}"/>
76
+ </template>
77
+ </itf-table>
75
78
  </div>
76
79
  </div>
77
- <slot v-else-if="currentTab === 'board'" name="kanban-view"></slot>
78
- <slot v-else-if="currentTab === 'calendar'" name="calendar-view"></slot>
79
- <slot v-else name="table-view">
80
- <div class="flex-grow-1 px-3 d-flex flex-column">
81
- <div class="position-relative flex-grow-1">
82
- <itf-table
83
- ref="table"
84
- style="--shadow-area-width: 0px;"
85
- absolute
86
- striped
87
- clickable
88
- column-sorting
89
- column-resizing
90
- :indicator-type="indicatorType"
91
- class="permanent-checkboxes"
92
- :state-name="stateName"
93
- id-property="id"
94
- :sort-as-string="sortAsString"
95
- :rows="items"
96
- :group-by="groupBy"
97
- :schema="tableSchema"
98
- :sorting.sync="sorting"
99
- :active="activeIds"
100
- :no-select-all="noSelectAll"
101
- :show-actions="showActions"
102
- :indicator-width="indicatorWidth"
103
- v-model="selectedIds"
104
- @row-click="$emit('open', $event)"
105
- @update:sorting="updateSorting($event)"
106
- >
107
- <template v-for="(_, name) in $slots" #[name]="slotData">
108
- <slot :name="name" v-bind="slotData || {}"/>
109
- </template>
110
- <template v-for="(_, name) in $scopedSlots" #[name]="slotData">
111
- <slot :name="name" v-bind="slotData || {}"/>
112
- </template>
113
- </itf-table>
114
- </div>
115
- </div>
116
- </slot>
117
80
 
118
81
  <itf-pagination
119
82
  class="my-2 px-3"
120
- v-if="showPagination"
121
83
  show-size
122
84
  :size="size"
123
- :items="items"
85
+ :items="preparedItems"
124
86
  :pages="countPages"
125
87
  :value="page"
126
88
  @input="updatePage($event)"
127
89
  @per-page="updateSizePerPage($event)"
128
90
  >
129
91
  <template #center>
130
- <slot name="pagination-center" :totals="totals" />
92
+ <slot name="pagination-center" />
131
93
  </template>
132
94
  </itf-pagination>
133
95
  </div>
134
96
 
135
97
  </template>
136
98
  <script>
137
- import {Vue, ModelSync, Component, Prop, Inject, PropSync, Watch} from 'vue-property-decorator';
99
+ import { Vue, ModelSync, Component, Prop, Inject } from 'vue-property-decorator';
138
100
  import loading from '../../directives/loading';
139
101
  import itfTable from '../table/Table2.vue';
140
102
  import itfFilterPanel from '../filter/FilterPanel.vue';
@@ -142,16 +104,11 @@ import itfPagination from '../pagination/Pagination2.vue';
142
104
  import itfTableBody from "../table/TableBody.vue";
143
105
  import itfIcon from "../icon/Icon.vue";
144
106
  import itfDropdown from "../dropdown/Dropdown.vue";
145
- import itfSegmentedControl from '../segmented-control/SegmentedControl.vue';
146
- import itfButton from '@itfin/components/src/components/button/Button.vue';
147
107
 
148
108
  export default @Component({
149
109
  name: 'itfView',
150
110
  components: {
151
- itfButton,
152
- itfSegmentedControl,
153
- itfDropdown,
154
- itfIcon,
111
+ itfDropdown, itfIcon,
155
112
  itfPagination,
156
113
  itfFilterPanel,
157
114
  itfTableBody,
@@ -166,32 +123,24 @@ class itfView extends Vue {
166
123
  @ModelSync('value', 'input') selectedIds;
167
124
 
168
125
  @Prop({ type: Boolean }) loading;
126
+ @Prop({ type: Boolean }) filtersOnly;
127
+ @Prop({ type: Boolean }) noFilters;
169
128
  @Prop({ type: Array }) filters;
170
- @Prop({ type: Object }) schema;
129
+ @Prop({ type: Object, required: true }) schema;
130
+ // @Prop({ default: 20 }) size;
131
+ // @Prop({ default: 1 }) page;
171
132
  @Prop(String) defaultSorting;
172
133
  @Prop(String) endpoint;
173
134
  @Prop(String) filtersEndpoint;
174
135
  @Prop(String) itemsKey;
175
- @Prop({ type: String, default: null }) groupBy;
176
- @Prop({ type: String, default: null }) downloadEndpoint; // префікс апі для завантаження
177
- @Prop({ type: String, default: 'totals' }) totalsKey;
178
136
  @Prop(String) panelKey;
179
137
  @Prop(String) stateName;
180
138
  @Prop({ type: String, default: 'checkbox' }) indicatorType;
181
- @Prop({ type: String, default: 'list' }) tab;
182
139
  @Prop({ type: String, default () { return this.$t('components.table.search'); } }) searchPlaceholder;
183
140
  @Prop() panel;
141
+ @Prop() hardFilter; // встановлює жорсткий фільтр, наприклад, треба завжди показувати лише по контрагенту
184
142
  @Prop(Boolean) showActions;
185
- @Prop({ type: Boolean, default: true }) showPagination;
186
- @Prop(Boolean) listViewEnabled;
187
- @Prop(Boolean) kanbanViewEnabled;
188
- @Prop(Boolean) calendarViewEnabled;
189
- @Prop(Boolean) noSelectAll;
190
- @Prop({ type: Boolean, default: true }) tableViewEnabled;
191
- @Prop(Boolean) sortAsString;
192
- @Prop(Boolean) oldFormat;
193
- @Prop({ default: 45 }) indicatorWidth;
194
- @Prop({type: Function, default: null }) onSplitSlectedIds // якщо потрібно розділяти вибрані рядки в таблиці на дві групи
143
+ @Prop({ type: Array, default: () => [] }) disabledIds;
195
144
 
196
145
  page = 1;
197
146
  total = 0;
@@ -201,74 +150,10 @@ class itfView extends Vue {
201
150
  filter = {};
202
151
  loadingData = false;
203
152
  activeIds = [];
204
- tableColumns = null;
205
- totals = null;
206
-
207
- @Watch('selectedIds', { deep: true, immediate: true })
208
- updateSelectedIds() {
209
- if(this.onSplitSlectedIds && this.items.length && this.selectedIds.length) {
210
- this.onSplitSlectedIds(this.selectedIds, this.items);
211
- }
212
- }
213
-
214
- getDownloadLinks() {
215
- const state = this.$refs.table ? this.$refs.table.getTableState() : null;
216
- const filter = this.filter;
217
- const sorting = this.sorting;
218
- const filterableColumnsNames = (state?.columns ?? []).filter(column => column.visible).map(column => column.property);
219
-
220
- const filterWithValue = Object.fromEntries(Object.entries(filter).filter(([_, value]) => typeof value !== 'undefined'));
221
- const params = {
222
- ...filterWithValue,
223
- sort: sorting
224
- };
225
- if (filterableColumnsNames.length) {
226
- params.columns = filterableColumnsNames.join(',')
227
- }
228
- const xlsQueryParams = new URLSearchParams({ ...params, format: 'xlsx' }).toString();
229
- const csvQueryParams = new URLSearchParams({ ...params, format: 'csv' }).toString();
230
- return [
231
- { title: 'Excel (xlsx)', link: `${this.downloadEndpoint}?${xlsQueryParams}` },
232
- { title: 'Plain text (csv)', link: `${this.downloadEndpoint}?${csvQueryParams}` },
233
- ];
234
- }
235
-
236
- get currentTab() {
237
- return this.tab;
238
- }
239
153
 
240
- set currentTab(val) {
241
- this.$emit('update:tab', val);
242
- this.setPanelPayload({ tab: val });
243
- }
244
-
245
- get tabs() {
246
- const views = [];
247
- if (this.listViewEnabled) {
248
- views.push({ value: 'list', text: this.$t('list'), icon: 'list-view' });
249
- }
250
- if (this.kanbanViewEnabled) {
251
- views.push({ value: 'board', text: this.$t('board'), icon: 'kanban-view' });
252
- }
253
- if (this.calendarViewEnabled) {
254
- views.push({ value: 'calendar', text: this.$t('calendar'), icon: 'calendar-view' });
255
- }
256
- if (this.tableViewEnabled) {
257
- views.push({ value: 'table', text: this.$t('table'), icon: 'table-view' });
258
- }
259
- return views;
260
- }
261
-
262
- get tableSchema() {
263
- if (this.tableColumns) {
264
- return {
265
- properties: this.tableColumns
266
- }
267
- } else if (this.schema) {
268
- return this.schema
269
- } else {
270
- return {}
271
- }
154
+ get preparedItems() {
155
+ const disabledIdsSet = new Set(this.disabledIds);
156
+ return this.items.map(item => ({ ...item, isDisabled: disabledIdsSet.has(item.id) }));
272
157
  }
273
158
 
274
159
  created() {
@@ -290,42 +175,35 @@ class itfView extends Vue {
290
175
  }
291
176
  }
292
177
 
293
- async loadData() {
178
+ async loadData(reloadFilters = false) {
294
179
  if (!this.endpoint) {
295
180
  return;
296
181
  }
182
+ if (reloadFilters) {
183
+ this.loadFilters();
184
+ }
297
185
  this.$emit('load', this.filter);
298
186
  this.loadingData = true;
299
187
  await this.$try(async () => {
300
- let filter = this.filter;
301
- if (this.oldFormat) {
302
- filter = Object.keys(filter).reduce((acc, key) => {
303
- acc[`filter[${key}]`] = filter[key];
304
- return acc;
305
- }, {})
306
- }
307
- const { data, headers } = await this.$axios.get(this.endpoint, {
188
+ const res = await this.$axios.$get(this.endpoint, {
189
+ preventRaceCondition: true,
308
190
  params: {
309
- ...filter,
191
+ ...Object.assign(this.filter ?? {}, this.hardFilter ?? {}),
310
192
  page: this.page,
311
193
  size: this.size,
312
194
  sort: this.sorting
313
195
  }
314
196
  });
315
- if (this.oldFormat) {
316
- this.items = data;
317
- this.page = Number(headers['x-page'] ?? 1);
318
- this.total = Number(headers['x-count'] ?? 0);
319
- this.size = Number(headers['x-size'] ?? 20);
320
- } else {
321
- this.items = data[this.itemsKey];
322
- this.totals = data[this.totalsKey];
323
- this.page = data.meta.page;
324
- this.total = data.meta.total;
325
- this.size = data.meta.size;
326
- }
197
+ this.selectedIds = [];
198
+ this.items = res[this.itemsKey];
199
+ this.page = res.meta.page;
200
+ this.total = res.meta.total;
201
+ this.size = res.meta.size;
202
+ this.$emit('update:items', this.items);
203
+ this.loadingData = false;
204
+ }, () => {
205
+ this.loadingData = false;
327
206
  });
328
- this.loadingData = false;
329
207
  this.$emit('loaded', this.filter);
330
208
  }
331
209
 
@@ -348,16 +226,14 @@ class itfView extends Vue {
348
226
 
349
227
  updatePage (val) {
350
228
  this.page = val;
351
- this.selectedIds = [];
352
- this.setPanelPayload({ page: val });
229
+ this.setPanelPayload({ page: val === 1 ? null : val });
353
230
  this.loadData();
354
231
  }
355
232
 
356
233
  updateSizePerPage (val) {
357
234
  this.page = 1;
358
235
  this.size = val;
359
- this.selectedIds = [];
360
- this.setPanelPayload({ page: 1, size: val });
236
+ this.setPanelPayload({ page: null, size: val });
361
237
  this.loadData();
362
238
  localStorage.setItem('sizePerPage', val);
363
239
  }
@@ -370,7 +246,9 @@ class itfView extends Vue {
370
246
  sources.forEach(source => {
371
247
  if (source && typeof source === 'object') {
372
248
  Object.entries(source).forEach(([key, value]) => {
373
- if (value !== undefined) {
249
+ if (key === 'page' && value === null) {
250
+ delete target[key];
251
+ } else if (value !== undefined) {
374
252
  target[key] = value;
375
253
  }
376
254
  });
@@ -380,27 +258,21 @@ class itfView extends Vue {
380
258
  }
381
259
  }
382
260
 
383
- onFilterSet(filter) {
384
- this.page = 1;
385
- this.selectedIds = [];
386
- this.setPanelPayload({ ...filter, page: 1 });
261
+ onFilterSet(filter, keepPage = false) {
262
+ if (keepPage) {
263
+ // при завантаженні сторінки не потрібно скидувати сторінку
264
+ this.setPanelPayload({ ...filter });
265
+ } else {
266
+ this.page = 1;
267
+ this.setPanelPayload({ ...filter, page: null });
268
+ }
387
269
  this.loadData();
388
270
  }
389
271
 
390
- setTableSchema(tableSchema) {
391
- this.tableColumns = tableSchema;
392
- }
393
-
394
- getSorting() {
395
- return this.sorting;
396
- }
397
-
398
- getFilter() {
399
- return this.filter;
400
- }
401
-
402
- getTableState() {
403
- return this.$refs.table ? this.$refs.table.getTableState() : null;
272
+ loadFilters() {
273
+ if (this.filtersEndpoint) {
274
+ this.$refs.filters?.loadData();
275
+ }
404
276
  }
405
277
  }
406
278
  </script>
@@ -30,6 +30,7 @@ export default {
30
30
  width: width + 'px',
31
31
  left: left + 'px',
32
32
  top: (top + height) + 'px',
33
+ root: rootEl
33
34
  });
34
35
  }
35
36
 
@@ -8,12 +8,12 @@ const LINKED_IN_REGEXP = /(http(s)?:\/\/)?([\w]+\.)?linkedin\.com\/(pub|in|profi
8
8
  const SPECIAL_CHARS_REGEXP = /^[\w_\-+~,/\\:'"().&*|[\]?# ]+$/i;
9
9
  const GREETINGS_REGEXP = /\b(dr|mr|mister|mrs|ms|miss|sir|hello|hi)\b/i;
10
10
  const PHONE_REGEXP = /(\+?\(?\+?[0-9]{1,3}\)?[-. ]+([0-9]{2,4})[-. ]?([0-9]{3,5}))|\+?[0-9]{7,}/gi;
11
+ const INTEGER_REGEXP = /^-?\d{0,11}$/;
11
12
  const DOUBLE_REGEXP = /^-?\d{0,11}(\.\d{0,8}){0,1}$/;
12
- const EMAIL_REGEXP = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/g;
13
+ const EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i;
13
14
  const EMAIL_LIST_REGEXP = /^(\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]{2,4}\s*?,?\s*?)+$/g;
14
15
  const HEX_REGEXP = /[0-9A-Fa-f]{6}/;
15
- const PASSWORD_MIN_LENGTH = 8;
16
- const PASSWORD_MAX_LENGTH = 50;
16
+ const PASSWORD_REGEX = /^(?=.*\p{Lu})(?=.*\p{Ll})(?=.*\d)(?=.*[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]).{8,}$/u;
17
17
 
18
18
  const STANDART_DATE_FORMAT = 'yyyy-MM-dd';
19
19
 
@@ -67,6 +67,10 @@ export function emptyArrayValidation (message) {
67
67
  return (v, $t = (s) => s) => (Array.isArray(v) && v.length > 0) || (message || $t('components.thisFieldIsRequired'));
68
68
  }
69
69
 
70
+ export function integerValidation (message) {
71
+ return (v, $t = (s) => s) => !v || !!(v + '').match(INTEGER_REGEXP) || (message || $t('components.thisFieldMustBeANumberFormatZero'));
72
+ }
73
+
70
74
  export function doubleValidation (message) {
71
75
  return (v, $t = (s) => s) => !v || !!(v + '').match(DOUBLE_REGEXP) || (message || $t('components.thisFieldMustBeANumberFormatZero'));
72
76
  }
@@ -184,38 +188,8 @@ export function dateSameOrBeforeValidation (dateCompare, message) {
184
188
  };
185
189
  }
186
190
 
187
- export function hasUppercaseValidation(message) {
188
- return (v, $t) => {
189
- return !isEmpty(v) && /\p{Lu}/u.test(v + '') || (message || $t('components.atLeastOneUppercaseLetterRequired'));
190
- };
191
- }
192
-
193
- export function hasLowercaseValidation(message) {
194
- return (v, $t) => {
195
- return !isEmpty(v) && /\p{Ll}/u.test(v + '') || (message || $t('components.atLeastOneLowercaseLetterRequired'));
196
- };
197
- }
198
-
199
- export function hasDigitValidation(message) {
200
- return (v, $t) => {
201
- return !isEmpty(v) && /\d/.test(v + '') || (message || $t('components.atLeastOneNumberRequired'));
202
- };
203
- }
204
-
205
- export function hasSpecialCharValidation(message) {
191
+ export function passwordValidation(message) {
206
192
  return (v, $t) => {
207
- return !isEmpty(v) && /[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]/.test(v + '') || (message || $t('components.atLeastOneSpecialCharacterRequired'));
193
+ return !isEmpty(v) && PASSWORD_REGEX.test(v.trim() + '') || (message || $t('components.passwordValidation'));
208
194
  };
209
195
  }
210
-
211
- export function accountPasswordValidation(message) {
212
- return [
213
- emptyValidation(message),
214
- minLengthValidation(PASSWORD_MIN_LENGTH, message),
215
- lengthValidation(PASSWORD_MAX_LENGTH, message),
216
- hasUppercaseValidation(message),
217
- hasLowercaseValidation(message),
218
- hasDigitValidation(message),
219
- hasSpecialCharValidation(message),
220
- ];
221
- }
@@ -7,10 +7,7 @@ import {
7
7
  dateAfterValidation,
8
8
  dateSameOrAfterValidation,
9
9
  dateSameOrBeforeValidation,
10
- hasUppercaseValidation,
11
- hasLowercaseValidation,
12
- hasDigitValidation,
13
- hasSpecialCharValidation,
10
+ passwordValidation,
14
11
  } from './validators';
15
12
 
16
13
  describe('Validators', () => {
@@ -86,50 +83,16 @@ describe('Validators', () => {
86
83
  expect(mediumTextValidation()('0'.repeat(16777216), $t)).toEqual('components.mediumTextLength');
87
84
  });
88
85
 
89
- test('hasUppercaseValidation', () => {
90
- expect(hasUppercaseValidation()('', $t)).toEqual('components.atLeastOneUppercaseLetterRequired');
91
- expect(hasUppercaseValidation()(' ', $t)).toEqual('components.atLeastOneUppercaseLetterRequired');
92
- expect(hasUppercaseValidation()(null, $t)).toEqual('components.atLeastOneUppercaseLetterRequired');
93
- expect(hasUppercaseValidation()(undefined, $t)).toEqual('components.atLeastOneUppercaseLetterRequired');
94
- expect(hasUppercaseValidation()('A', $t)).toEqual(true);
95
- expect(hasUppercaseValidation()(' Test ', $t)).toEqual(true);
96
- expect(hasUppercaseValidation()(' test ', $t)).toEqual('components.atLeastOneUppercaseLetterRequired');
97
- expect(hasUppercaseValidation()(' Тест ', $t)).toEqual(true);
98
- expect(hasUppercaseValidation()(' тест ', $t)).toEqual('components.atLeastOneUppercaseLetterRequired');
99
- expect(hasUppercaseValidation()(' ТЕСТ ', $t)).toEqual(true);
100
- });
101
-
102
- test('hasLowercaseValidation', () => {
103
- expect(hasLowercaseValidation()('', $t)).toEqual('components.atLeastOneLowercaseLetterRequired');
104
- expect(hasLowercaseValidation()(' ', $t)).toEqual('components.atLeastOneLowercaseLetterRequired');
105
- expect(hasLowercaseValidation()(null, $t)).toEqual('components.atLeastOneLowercaseLetterRequired');
106
- expect(hasLowercaseValidation()(undefined, $t)).toEqual('components.atLeastOneLowercaseLetterRequired');
107
- expect(hasLowercaseValidation()('a', $t)).toEqual(true);
108
- expect(hasLowercaseValidation()(' test ', $t)).toEqual(true);
109
- expect(hasLowercaseValidation()('A', $t)).toEqual('components.atLeastOneLowercaseLetterRequired');
110
- expect(hasLowercaseValidation()(' Test ', $t)).toEqual(true);
111
- expect(hasLowercaseValidation()(' Тест ', $t)).toEqual(true);
112
- expect(hasLowercaseValidation()(' тест ', $t)).toEqual(true);
113
- expect(hasLowercaseValidation()(' ТЕСТ ', $t)).toEqual('components.atLeastOneLowercaseLetterRequired');
114
- })
115
-
116
- test('hasDigitValidation', () => {
117
- expect(hasDigitValidation()('', $t)).toEqual('components.atLeastOneNumberRequired');
118
- expect(hasDigitValidation()(' ', $t)).toEqual('components.atLeastOneNumberRequired');
119
- expect(hasDigitValidation()(null, $t)).toEqual('components.atLeastOneNumberRequired');
120
- expect(hasDigitValidation()(undefined, $t)).toEqual('components.atLeastOneNumberRequired');
121
- expect(hasDigitValidation()('1', $t)).toEqual(true);
122
- expect(hasDigitValidation()(' 1 ', $t)).toEqual(true);
123
- expect(hasDigitValidation()('a', $t)).toEqual('components.atLeastOneNumberRequired');
124
- });
125
86
 
126
- test('hasSpecialCharValidation', () => {
127
- expect(hasSpecialCharValidation()('', $t)).toEqual('components.atLeastOneSpecialCharacterRequired');
128
- expect(hasSpecialCharValidation()(' ', $t)).toEqual('components.atLeastOneSpecialCharacterRequired');
129
- expect(hasSpecialCharValidation()(null, $t)).toEqual('components.atLeastOneSpecialCharacterRequired');
130
- expect(hasSpecialCharValidation()(undefined, $t)).toEqual('components.atLeastOneSpecialCharacterRequired');
131
- expect(hasSpecialCharValidation()('@', $t)).toEqual(true);
132
- expect(hasSpecialCharValidation()(' @ ', $t)).toEqual(true);
133
- expect(hasSpecialCharValidation()('a', $t)).toEqual('components.atLeastOneSpecialCharacterRequired');
87
+ test('passwordValidation', () => {
88
+ expect(passwordValidation()('', $t)).toEqual('components.passwordValidation');
89
+ expect(passwordValidation()(' ', $t)).toEqual('components.passwordValidation');
90
+ expect(passwordValidation()(null, $t)).toEqual('components.passwordValidation');
91
+ expect(passwordValidation()(undefined, $t)).toEqual('components.passwordValidation');
92
+ expect(passwordValidation()(' тесттест ', $t)).toEqual('components.passwordValidation');
93
+ expect(passwordValidation()(' ТЕСТТЕСТ ', $t)).toEqual('components.passwordValidation');
94
+ expect(passwordValidation()(' ТестТест ', $t)).toEqual('components.passwordValidation');
95
+ expect(passwordValidation()(' ТестТест1 ', $t)).toEqual('components.passwordValidation');
96
+ expect(passwordValidation()(' ТестТест1@ ', $t)).toEqual(true);
134
97
  });
135
98
  });
package/src/locales/en.js CHANGED
@@ -56,10 +56,6 @@ module.exports = {
56
56
  addMore: 'Add more',
57
57
  close: 'Close',
58
58
  wholeYear: 'Whole year',
59
- atLeastOneUppercaseLetterRequired: 'At least one uppercase letter is required',
60
- atLeastOneLowercaseLetterRequired: 'At least one lowercase letter is required',
61
- atLeastOneNumberRequired: 'At least one number is required',
62
- atLeastOneSpecialCharacterRequired: 'At least one special character is required (e.g. @,$,!,%,*,?,&)',
63
59
 
64
60
  select: {
65
61
  loading: 'Loading...',
@@ -103,7 +99,7 @@ module.exports = {
103
99
  copyingToClipboardWasSuccessful: 'Copying to clipboard was successful',
104
100
  },
105
101
  table: {
106
- new: 'New row',
102
+ new: 'New',
107
103
  noResults: 'No items',
108
104
  sortAscending: 'Sort ascending',
109
105
  sortDescending: 'Sort descending',
@@ -156,5 +152,7 @@ module.exports = {
156
152
  from: 'From',
157
153
  to: 'To',
158
154
  value: 'Value',
159
- }
155
+ },
156
+ passwordValidation: 'Password should contain at least 8 characters, including uppercase letters, lowercase letters, numbers, and special characters (e.g. @, $, !, %, *, ?, &)',
157
+ iveGotIt: 'I\'ve got it',
160
158
  };