@itfin/components 1.5.1 → 1.5.3
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/dist/ITFComponents.common.js +87 -0
- package/dist/ITFComponents.common.js.map +1 -0
- package/dist/ITFComponents.umd.js +98 -0
- package/dist/ITFComponents.umd.js.map +1 -0
- package/dist/ITFComponents.umd.min.js +2 -0
- package/dist/ITFComponents.umd.min.js.map +1 -0
- package/dist/demo.html +1 -0
- package/package.json +12 -1
- package/src/ITFSettings.js +0 -6
- package/src/components/alert/AlertBanner.vue +70 -14
- package/src/components/button/Button.vue +1 -3
- package/src/components/button/NativeButton.js +0 -4
- package/src/components/button/index.stories.js +2 -2
- package/src/components/checkbox/NestedCheckboxGroup.vue +109 -0
- package/src/components/customize/PropertiesList.vue +2 -0
- package/src/components/customize/PropertiesPopupMenu.vue +1 -1
- package/src/components/customize/PropertyItem.vue +24 -6
- package/src/components/datepicker/DatePicker.vue +1 -1
- package/src/components/datepicker/MonthPicker.vue +21 -1
- package/src/components/dropdown/Dropdown.vue +1 -1
- package/src/components/dropdown/DropdownMenu.vue +1 -1
- package/src/components/editable/EditButton.vue +1 -1
- package/src/components/filter/FilterBadge.vue +4 -3
- package/src/components/filter/FilterFacetsList.vue +16 -9
- package/src/components/filter/FilterPanel.vue +20 -6
- package/src/components/icon/components/nomi-.DS_Store +0 -0
- package/src/components/icon/components/nomi-approval-chain.vue +5 -0
- package/src/components/icon/components/nomi-calendar-view.vue +4 -0
- package/src/components/icon/components/nomi-close-alt.vue +5 -0
- package/src/components/icon/components/nomi-cog-lightning.vue +5 -0
- package/src/components/icon/components/nomi-comment-add.vue +5 -0
- package/src/components/icon/components/nomi-comment.vue +4 -0
- package/src/components/icon/components/nomi-comments.vue +5 -0
- package/src/components/icon/components/nomi-copy.vue +5 -0
- package/src/components/icon/components/nomi-dollar.vue +4 -0
- package/src/components/icon/components/nomi-expense-requests.vue +5 -0
- package/src/components/icon/components/nomi-file-doc.vue +7 -0
- package/src/components/icon/components/nomi-file-excel.vue +9 -0
- package/src/components/icon/components/nomi-file-image.vue +6 -0
- package/src/components/icon/components/nomi-file-pdf.vue +5 -0
- package/src/components/icon/components/nomi-help.vue +3 -2
- package/src/components/icon/components/nomi-kanban-view.vue +6 -0
- package/src/components/icon/components/nomi-light-bulb.vue +4 -0
- package/src/components/icon/components/nomi-list-view.vue +7 -0
- package/src/components/icon/components/nomi-lock.vue +1 -1
- package/src/components/icon/components/nomi-money-alt.vue +4 -0
- package/src/components/icon/components/nomi-money-requests.vue +12 -0
- package/src/components/icon/components/nomi-pending.vue +4 -0
- package/src/components/icon/components/nomi-plus.vue +5 -0
- package/src/components/icon/components/nomi-project.vue +2 -2
- package/src/components/icon/components/nomi-scissors.vue +1 -1
- package/src/components/icon/components/nomi-secure.vue +4 -0
- package/src/components/icon/components/nomi-stop.vue +4 -0
- package/src/components/icon/components/nomi-table-config.vue +9 -0
- package/src/components/icon/components/nomi-table-view.vue +4 -1
- package/src/components/icon/components/nomi-thumbs-down.vue +4 -0
- package/src/components/icon/components/nomi-thumbs-up.vue +4 -0
- package/src/components/icon/components/nomi-undo.vue +4 -0
- package/src/components/icon/components/nomi-user-settings.vue +5 -0
- package/src/components/icon/components/nomi-user.vue +3 -3
- package/src/components/icon/convert-icons.js +0 -3
- package/src/components/icon/icons.js +403 -372
- package/src/components/icon/new-icons/approval-chain.svg +4 -0
- package/src/components/icon/new-icons/budget.svg +3 -0
- package/src/components/icon/new-icons/calendar-view.svg +3 -0
- package/src/components/icon/new-icons/close-alt.svg +4 -0
- package/src/components/icon/new-icons/cog-lightning.svg +4 -0
- package/src/components/icon/new-icons/comment-add.svg +4 -0
- package/src/components/icon/new-icons/comment.svg +3 -0
- package/src/components/icon/new-icons/comments.svg +4 -0
- package/src/components/icon/new-icons/copy.svg +4 -0
- package/src/components/icon/new-icons/dollar.svg +3 -0
- package/src/components/icon/new-icons/expense-requests.svg +4 -0
- package/src/components/icon/new-icons/file-doc.svg +6 -0
- package/src/components/icon/new-icons/file-excel.svg +8 -0
- package/src/components/icon/new-icons/file-image.svg +5 -0
- package/src/components/icon/new-icons/file-pdf.svg +4 -0
- package/src/components/icon/new-icons/help.svg +3 -2
- package/src/components/icon/new-icons/kanban-view.svg +5 -0
- package/src/components/icon/new-icons/light-bulb.svg +3 -0
- package/src/components/icon/new-icons/list-view.svg +6 -0
- package/src/components/icon/new-icons/lock.svg +1 -1
- package/src/components/icon/new-icons/money-alt.svg +3 -0
- package/src/components/icon/new-icons/money-requests.svg +11 -0
- package/src/components/icon/new-icons/pending.svg +3 -0
- package/src/components/icon/new-icons/plus.svg +4 -0
- package/src/components/icon/new-icons/project.svg +2 -2
- package/src/components/icon/new-icons/scissors.svg +1 -1
- package/src/components/icon/new-icons/secure.svg +3 -0
- package/src/components/icon/new-icons/stop.svg +3 -0
- package/src/components/icon/new-icons/table-config.svg +8 -0
- package/src/components/icon/new-icons/table-view.svg +4 -1
- package/src/components/icon/new-icons/thumbs-down.svg +3 -0
- package/src/components/icon/new-icons/thumbs-up.svg +3 -0
- package/src/components/icon/new-icons/undo.svg +3 -0
- package/src/components/icon/new-icons/user-settings.svg +4 -0
- package/src/components/icon/new-icons/user.svg +3 -3
- package/src/components/kanban/BoardCard.vue +1 -1
- package/src/components/kanban/BoardCardTimer.vue +1 -1
- package/src/components/modal/Modal.vue +6 -1
- package/src/components/overlay/SensitiveOverlay.vue +4 -2
- package/src/components/pagination/Pagination2.vue +4 -3
- package/src/components/panels/Panel.vue +23 -1
- package/src/components/panels/PanelItemEdit.vue +91 -10
- package/src/components/panels/PanelList.vue +19 -6
- package/src/components/table/Table2.vue +65 -60
- package/src/components/table/TableBody.vue +6 -0
- package/src/components/table/TableGroup.vue +13 -4
- package/src/components/table/TableHeader.vue +77 -76
- package/src/components/table/TableRowToggle.vue +9 -1
- package/src/components/table/TableRows.vue +54 -30
- package/src/components/table/table2.scss +15 -34
- package/src/components/text-field/TextField.vue +8 -0
- package/src/components/tree/TreeEditor.vue +2 -3
- package/src/components/view/View.vue +217 -56
- package/src/helpers/validators.js +35 -9
- package/src/helpers/validators.spec.js +48 -11
- package/src/locales/en.js +8 -2
- package/src/locales/pl.js +2 -1
- package/src/locales/uk.js +7 -6
|
@@ -4,26 +4,29 @@
|
|
|
4
4
|
<itf-filter-panel
|
|
5
5
|
:search-placeholder="searchPlaceholder"
|
|
6
6
|
search
|
|
7
|
+
show-filter
|
|
7
8
|
:visible="!noFilters"
|
|
8
9
|
:filters-only="filtersOnly"
|
|
9
10
|
ref="filters"
|
|
10
11
|
:mini="panel.isMultiple()"
|
|
11
12
|
class="py-2 px-3"
|
|
13
|
+
:static-filters="filters"
|
|
12
14
|
:endpoint="filtersEndpoint"
|
|
13
15
|
:panel="panel"
|
|
14
16
|
v-model="filter"
|
|
15
17
|
@loaded="onFilterSet($event, true)"
|
|
16
18
|
@change="onFilterSet($event, false)"
|
|
19
|
+
@set-table-schema="setTableSchema"
|
|
17
20
|
>
|
|
18
21
|
<template #after-filter-btn>
|
|
19
|
-
<itf-dropdown v-if="$refs.table &&
|
|
22
|
+
<itf-dropdown v-if="$refs.table && tableSchema" shadow append-to-context :button-options="{ default: true, icon: true }" class="h-100" autoclose="outside">
|
|
20
23
|
<template #button>
|
|
21
|
-
<itf-icon new name="table-
|
|
24
|
+
<itf-icon new name="table-config" />
|
|
22
25
|
</template>
|
|
23
26
|
<div class="dropdown-header">
|
|
24
27
|
{{ $t('components.table.columns') }}
|
|
25
28
|
</div>
|
|
26
|
-
<a v-for="(property, n) of
|
|
29
|
+
<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">
|
|
27
30
|
<div class="d-flex align-items-center gap-1">
|
|
28
31
|
<itf-icon v-if="property.icon" :size="24" new :name="property.icon" />
|
|
29
32
|
{{getTitle(property.title)}}
|
|
@@ -42,64 +45,105 @@
|
|
|
42
45
|
</div>
|
|
43
46
|
</a>
|
|
44
47
|
</itf-dropdown>
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
<itf-dropdown v-if="downloadEndpoint" shadow append-to-context :button-options="{ default: true, small: true }" class="h-100" autoclose="outside">
|
|
49
|
+
<template #button>
|
|
50
|
+
<itf-icon name="download"/>
|
|
51
|
+
{{ $t('export') }}
|
|
52
|
+
</template>
|
|
53
|
+
<a v-for="(item, n) in getDownloadLinks()" target="_blank" :key="n" :href="item.link" class="dropdown-item">
|
|
54
|
+
{{item.title}}
|
|
55
|
+
</a>
|
|
56
|
+
</itf-dropdown>
|
|
57
|
+
|
|
58
|
+
<slot name="before-tabs"></slot>
|
|
47
59
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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)"
|
|
60
|
+
<itf-segmented-control
|
|
61
|
+
v-if="tabs.length > 1"
|
|
62
|
+
class="small"
|
|
63
|
+
v-model="currentTab"
|
|
64
|
+
item-key="value"
|
|
65
|
+
:items="tabs"
|
|
73
66
|
>
|
|
74
|
-
<template
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
67
|
+
<template #item="{ item }">
|
|
68
|
+
<div class="d-flex align-items-center">
|
|
69
|
+
<itf-icon class="text-muted" new :name="item.icon" />
|
|
70
|
+
{{item.text}}
|
|
71
|
+
</div>
|
|
79
72
|
</template>
|
|
80
|
-
</itf-
|
|
73
|
+
</itf-segmented-control>
|
|
74
|
+
</template>
|
|
75
|
+
</itf-filter-panel>
|
|
76
|
+
|
|
77
|
+
<div v-if="currentTab === 'list'" class="position-relative flex-grow-1">
|
|
78
|
+
<div class="position-absolute" style="top: 0; left: 0; right: 0; bottom: 0; overflow: auto;">
|
|
79
|
+
<slot name="list-view" :items="items" :loading="loading"></slot>
|
|
81
80
|
</div>
|
|
82
81
|
</div>
|
|
82
|
+
<slot v-else-if="currentTab === 'board'" name="kanban-view"></slot>
|
|
83
|
+
<slot v-else-if="currentTab === 'calendar'" name="calendar-view"></slot>
|
|
84
|
+
<slot v-else name="table-view">
|
|
85
|
+
<div class="flex-grow-1 px-3 d-flex flex-column">
|
|
86
|
+
<div class="position-relative flex-grow-1">
|
|
87
|
+
<itf-table
|
|
88
|
+
ref="table"
|
|
89
|
+
style="--shadow-area-width: 0px;"
|
|
90
|
+
absolute
|
|
91
|
+
striped
|
|
92
|
+
clickable
|
|
93
|
+
column-sorting
|
|
94
|
+
column-resizing
|
|
95
|
+
:indicator-type="indicatorType"
|
|
96
|
+
class="permanent-checkboxes"
|
|
97
|
+
:state-name="stateName"
|
|
98
|
+
id-property="id"
|
|
99
|
+
divider-property="hasDivider"
|
|
100
|
+
subrows-property="children"
|
|
101
|
+
:sort-as-string="sortAsString"
|
|
102
|
+
:rows="preparedItems"
|
|
103
|
+
:group-by="groupBy"
|
|
104
|
+
:schema="tableSchema"
|
|
105
|
+
:sorting="sorting"
|
|
106
|
+
:active="activeIds"
|
|
107
|
+
:expanded-ids.sync="expandedIds"
|
|
108
|
+
:no-select-all="noSelectAll"
|
|
109
|
+
:show-actions="showActions"
|
|
110
|
+
:indicator-width="indicatorWidth"
|
|
111
|
+
v-model="selectedIds"
|
|
112
|
+
@row-click="$emit('open', $event)"
|
|
113
|
+
@update:sorting="updateSorting($event)"
|
|
114
|
+
>
|
|
115
|
+
<template v-for="(_, name) in $slots" #[name]="slotData">
|
|
116
|
+
<slot :name="name" v-bind="slotData || {}"/>
|
|
117
|
+
</template>
|
|
118
|
+
<template v-for="(_, name) in $scopedSlots" #[name]="slotData">
|
|
119
|
+
<slot :name="name" v-bind="slotData || {}"/>
|
|
120
|
+
</template>
|
|
121
|
+
</itf-table>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
</slot>
|
|
83
125
|
|
|
84
126
|
<itf-pagination
|
|
85
127
|
class="my-2 px-3"
|
|
128
|
+
v-if="showPagination"
|
|
86
129
|
show-size
|
|
87
130
|
:size="size"
|
|
88
131
|
:items="preparedItems"
|
|
89
132
|
:pages="countPages"
|
|
90
133
|
:value="page"
|
|
134
|
+
:totalCount="showTotalCount ? total : null"
|
|
91
135
|
@input="updatePage($event)"
|
|
92
136
|
@per-page="updateSizePerPage($event)"
|
|
93
137
|
>
|
|
94
138
|
<template #center>
|
|
95
|
-
<slot name="pagination-center" />
|
|
139
|
+
<slot name="pagination-center" :totals="totals" />
|
|
96
140
|
</template>
|
|
97
141
|
</itf-pagination>
|
|
98
142
|
</div>
|
|
99
143
|
|
|
100
144
|
</template>
|
|
101
145
|
<script>
|
|
102
|
-
import {
|
|
146
|
+
import {Vue, ModelSync, Component, Prop, Inject, PropSync, Watch} from 'vue-property-decorator';
|
|
103
147
|
import loading from '../../directives/loading';
|
|
104
148
|
import itfTable from '../table/Table2.vue';
|
|
105
149
|
import itfFilterPanel from '../filter/FilterPanel.vue';
|
|
@@ -107,11 +151,16 @@ import itfPagination from '../pagination/Pagination2.vue';
|
|
|
107
151
|
import itfTableBody from "../table/TableBody.vue";
|
|
108
152
|
import itfIcon from "../icon/Icon.vue";
|
|
109
153
|
import itfDropdown from "../dropdown/Dropdown.vue";
|
|
154
|
+
import itfSegmentedControl from '../segmented-control/SegmentedControl.vue';
|
|
155
|
+
import itfButton from '@itfin/components/src/components/button/Button.vue';
|
|
110
156
|
|
|
111
157
|
export default @Component({
|
|
112
158
|
name: 'itfView',
|
|
113
159
|
components: {
|
|
114
|
-
|
|
160
|
+
itfButton,
|
|
161
|
+
itfSegmentedControl,
|
|
162
|
+
itfDropdown,
|
|
163
|
+
itfIcon,
|
|
115
164
|
itfPagination,
|
|
116
165
|
itfFilterPanel,
|
|
117
166
|
itfTableBody,
|
|
@@ -129,21 +178,34 @@ class itfView extends Vue {
|
|
|
129
178
|
@Prop({ type: Boolean }) filtersOnly;
|
|
130
179
|
@Prop({ type: Boolean }) noFilters;
|
|
131
180
|
@Prop({ type: Array }) filters;
|
|
132
|
-
@Prop({ type: Object
|
|
133
|
-
// @Prop({ default: 20 }) size;
|
|
134
|
-
// @Prop({ default: 1 }) page;
|
|
181
|
+
@Prop({ type: Object }) schema;
|
|
135
182
|
@Prop(String) defaultSorting;
|
|
136
183
|
@Prop(String) endpoint;
|
|
137
184
|
@Prop(String) filtersEndpoint;
|
|
138
185
|
@Prop(String) itemsKey;
|
|
186
|
+
@Prop({ type: String, default: null }) groupBy;
|
|
187
|
+
@Prop({ type: String, default: null }) downloadEndpoint; // префікс апі для завантаження
|
|
188
|
+
@Prop({ type: String, default: 'totals' }) totalsKey;
|
|
139
189
|
@Prop(String) panelKey;
|
|
140
190
|
@Prop(String) stateName;
|
|
141
191
|
@Prop({ type: String, default: 'checkbox' }) indicatorType;
|
|
192
|
+
@Prop({ type: String, default: 'list' }) tab;
|
|
142
193
|
@Prop({ type: String, default () { return this.$t('components.table.search'); } }) searchPlaceholder;
|
|
143
194
|
@Prop() panel;
|
|
144
195
|
@Prop() hardFilter; // встановлює жорсткий фільтр, наприклад, треба завжди показувати лише по контрагенту
|
|
145
196
|
@Prop(Boolean) showActions;
|
|
197
|
+
@Prop({ type: Boolean, default: true }) showPagination;
|
|
198
|
+
@Prop(Boolean) listViewEnabled;
|
|
199
|
+
@Prop(Boolean) kanbanViewEnabled;
|
|
200
|
+
@Prop(Boolean) calendarViewEnabled;
|
|
201
|
+
@Prop(Boolean) noSelectAll;
|
|
202
|
+
@Prop({ type: Boolean, default: true }) tableViewEnabled;
|
|
203
|
+
@Prop(Boolean) sortAsString;
|
|
204
|
+
@Prop(Boolean) oldFormat;
|
|
146
205
|
@Prop({ type: Array, default: () => [] }) disabledIds;
|
|
206
|
+
@Prop({ default: 45 }) indicatorWidth;
|
|
207
|
+
@Prop({type: Function, default: null }) onSplitSlectedIds // якщо потрібно розділяти вибрані рядки в таблиці на дві групи
|
|
208
|
+
@Prop({ type: Boolean, default: false }) showTotalCount;
|
|
147
209
|
|
|
148
210
|
page = 1;
|
|
149
211
|
total = 0;
|
|
@@ -153,6 +215,8 @@ class itfView extends Vue {
|
|
|
153
215
|
filter = {};
|
|
154
216
|
loadingData = false;
|
|
155
217
|
activeIds = [];
|
|
218
|
+
tableColumns = null;
|
|
219
|
+
totals = null;
|
|
156
220
|
expandedIds = [];
|
|
157
221
|
|
|
158
222
|
get preparedItems() {
|
|
@@ -160,6 +224,73 @@ class itfView extends Vue {
|
|
|
160
224
|
return this.items.map(item => ({ ...item, isDisabled: disabledIdsSet.has(item.id) }));
|
|
161
225
|
}
|
|
162
226
|
|
|
227
|
+
@Watch('selectedIds', { deep: true, immediate: true })
|
|
228
|
+
updateSelectedIds() {
|
|
229
|
+
if(this.onSplitSlectedIds && this.items.length && this.selectedIds.length) {
|
|
230
|
+
this.onSplitSlectedIds(this.selectedIds, this.items);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
getDownloadLinks() {
|
|
235
|
+
const state = this.$refs.table ? this.$refs.table.getTableState() : null;
|
|
236
|
+
const filter = { ...this.filter };
|
|
237
|
+
const sorting = this.sorting;
|
|
238
|
+
const filterableColumnsNames = (state?.columns ?? []).filter(column => column.visible).map(column => column.property);
|
|
239
|
+
|
|
240
|
+
const filterWithValue = Object.fromEntries(Object.entries(filter).filter(([_, value]) => typeof value !== 'undefined'));
|
|
241
|
+
const params = {
|
|
242
|
+
...filterWithValue,
|
|
243
|
+
sort: sorting
|
|
244
|
+
};
|
|
245
|
+
if (filterableColumnsNames.length) {
|
|
246
|
+
params.columns = filterableColumnsNames.join(',')
|
|
247
|
+
}
|
|
248
|
+
const xlsQueryParams = new URLSearchParams({ ...params, format: 'xlsx' }).toString();
|
|
249
|
+
const csvQueryParams = new URLSearchParams({ ...params, format: 'csv' }).toString();
|
|
250
|
+
return [
|
|
251
|
+
{ title: 'Excel (xlsx)', link: `${this.downloadEndpoint}?${xlsQueryParams}` },
|
|
252
|
+
{ title: 'Plain text (csv)', link: `${this.downloadEndpoint}?${csvQueryParams}` },
|
|
253
|
+
];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
get currentTab() {
|
|
257
|
+
return this.tab;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
set currentTab(val) {
|
|
261
|
+
this.$emit('update:tab', val);
|
|
262
|
+
this.setPanelPayload({ tab: val });
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
get tabs() {
|
|
266
|
+
const views = [];
|
|
267
|
+
if (this.listViewEnabled) {
|
|
268
|
+
views.push({ value: 'list', text: this.$t('list'), icon: 'list-view' });
|
|
269
|
+
}
|
|
270
|
+
if (this.kanbanViewEnabled) {
|
|
271
|
+
views.push({ value: 'board', text: this.$t('board'), icon: 'kanban-view' });
|
|
272
|
+
}
|
|
273
|
+
if (this.calendarViewEnabled) {
|
|
274
|
+
views.push({ value: 'calendar', text: this.$t('calendar'), icon: 'calendar-view' });
|
|
275
|
+
}
|
|
276
|
+
if (this.tableViewEnabled) {
|
|
277
|
+
views.push({ value: 'table', text: this.$t('table'), icon: 'table-view' });
|
|
278
|
+
}
|
|
279
|
+
return views;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
get tableSchema() {
|
|
283
|
+
if (this.tableColumns) {
|
|
284
|
+
return {
|
|
285
|
+
properties: this.tableColumns
|
|
286
|
+
}
|
|
287
|
+
} else if (this.schema) {
|
|
288
|
+
return this.schema
|
|
289
|
+
} else {
|
|
290
|
+
return {}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
163
294
|
created() {
|
|
164
295
|
const defaultSize = localStorage.getItem('sizePerPage') ?? 20;
|
|
165
296
|
|
|
@@ -189,29 +320,42 @@ class itfView extends Vue {
|
|
|
189
320
|
this.$emit('load', this.filter);
|
|
190
321
|
this.loadingData = true;
|
|
191
322
|
await this.$try(async () => {
|
|
192
|
-
|
|
323
|
+
let filter = { ...this.filter };
|
|
324
|
+
if (this.oldFormat) {
|
|
325
|
+
filter = Object.keys(filter).reduce((acc, key) => {
|
|
326
|
+
acc[`filter[${key}]`] = filter[key];
|
|
327
|
+
return acc;
|
|
328
|
+
}, {})
|
|
329
|
+
}
|
|
330
|
+
this.selectedIds = [];
|
|
331
|
+
const { data, headers } = await this.$axios.get(this.endpoint, {
|
|
193
332
|
preventRaceCondition: true,
|
|
194
333
|
params: {
|
|
195
|
-
...
|
|
334
|
+
...filter,
|
|
196
335
|
page: this.page,
|
|
197
336
|
size: this.size,
|
|
198
337
|
sort: this.sorting
|
|
199
338
|
}
|
|
200
339
|
});
|
|
201
|
-
this.
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
this
|
|
340
|
+
if (this.oldFormat) {
|
|
341
|
+
this.items = data;
|
|
342
|
+
this.page = Number(headers['x-page'] ?? 1);
|
|
343
|
+
this.total = Number(headers['x-count'] ?? 0);
|
|
344
|
+
this.size = Number(headers['x-size'] ?? 20);
|
|
345
|
+
} else {
|
|
346
|
+
this.items = data[this.itemsKey];
|
|
347
|
+
this.totals = data[this.totalsKey];
|
|
348
|
+
this.page = data.meta.page;
|
|
349
|
+
this.total = data.meta.total;
|
|
350
|
+
this.size = data.meta.size;
|
|
208
351
|
}
|
|
209
|
-
|
|
210
|
-
this.$emit('update:items', this.items);
|
|
211
|
-
this.loadingData = false;
|
|
212
|
-
}, () => {
|
|
213
|
-
this.loadingData = false;
|
|
214
352
|
});
|
|
353
|
+
if (res.columns) {
|
|
354
|
+
this.$emit('columns-loaded', res.columns);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
this.$emit('update:items', this.items);
|
|
358
|
+
this.loadingData = false;
|
|
215
359
|
this.$emit('loaded', this.filter);
|
|
216
360
|
}
|
|
217
361
|
|
|
@@ -241,6 +385,7 @@ class itfView extends Vue {
|
|
|
241
385
|
updateSizePerPage (val) {
|
|
242
386
|
this.page = 1;
|
|
243
387
|
this.size = val;
|
|
388
|
+
this.selectedIds = [];
|
|
244
389
|
this.setPanelPayload({ page: null, size: val });
|
|
245
390
|
this.loadData();
|
|
246
391
|
localStorage.setItem('sizePerPage', val);
|
|
@@ -277,10 +422,26 @@ class itfView extends Vue {
|
|
|
277
422
|
this.loadData();
|
|
278
423
|
}
|
|
279
424
|
|
|
425
|
+
setTableSchema(tableSchema) {
|
|
426
|
+
this.tableColumns = tableSchema;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
getSorting() {
|
|
430
|
+
return this.sorting;
|
|
431
|
+
}
|
|
432
|
+
|
|
280
433
|
loadFilters() {
|
|
281
434
|
if (this.filtersEndpoint) {
|
|
282
435
|
this.$refs.filters?.loadData();
|
|
283
436
|
}
|
|
284
437
|
}
|
|
438
|
+
|
|
439
|
+
getFilter() {
|
|
440
|
+
return this.filter;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
getTableState() {
|
|
444
|
+
return this.$refs.table ? this.$refs.table.getTableState() : null;
|
|
445
|
+
}
|
|
285
446
|
}
|
|
286
447
|
</script>
|
|
@@ -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}$/;
|
|
12
11
|
const DOUBLE_REGEXP = /^-?\d{0,11}(\.\d{0,8}){0,1}$/;
|
|
13
|
-
const EMAIL_REGEXP =
|
|
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;
|
|
14
13
|
const EMAIL_LIST_REGEXP = /^(\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]{2,4}\s*?,?\s*?)+$/g;
|
|
15
14
|
const HEX_REGEXP = /[0-9A-Fa-f]{6}/;
|
|
16
|
-
const
|
|
15
|
+
const PASSWORD_MIN_LENGTH = 8;
|
|
16
|
+
const PASSWORD_MAX_LENGTH = 50;
|
|
17
17
|
|
|
18
18
|
const STANDART_DATE_FORMAT = 'yyyy-MM-dd';
|
|
19
19
|
|
|
@@ -67,10 +67,6 @@ 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
|
-
|
|
74
70
|
export function doubleValidation (message) {
|
|
75
71
|
return (v, $t = (s) => s) => !v || !!(v + '').match(DOUBLE_REGEXP) || (message || $t('components.thisFieldMustBeANumberFormatZero'));
|
|
76
72
|
}
|
|
@@ -188,8 +184,38 @@ export function dateSameOrBeforeValidation (dateCompare, message) {
|
|
|
188
184
|
};
|
|
189
185
|
}
|
|
190
186
|
|
|
191
|
-
export function
|
|
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) {
|
|
192
206
|
return (v, $t) => {
|
|
193
|
-
return !isEmpty(v) &&
|
|
207
|
+
return !isEmpty(v) && /[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]/.test(v + '') || (message || $t('components.atLeastOneSpecialCharacterRequired'));
|
|
194
208
|
};
|
|
195
209
|
}
|
|
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,7 +7,10 @@ import {
|
|
|
7
7
|
dateAfterValidation,
|
|
8
8
|
dateSameOrAfterValidation,
|
|
9
9
|
dateSameOrBeforeValidation,
|
|
10
|
-
|
|
10
|
+
hasUppercaseValidation,
|
|
11
|
+
hasLowercaseValidation,
|
|
12
|
+
hasDigitValidation,
|
|
13
|
+
hasSpecialCharValidation,
|
|
11
14
|
} from './validators';
|
|
12
15
|
|
|
13
16
|
describe('Validators', () => {
|
|
@@ -83,16 +86,50 @@ describe('Validators', () => {
|
|
|
83
86
|
expect(mediumTextValidation()('0'.repeat(16777216), $t)).toEqual('components.mediumTextLength');
|
|
84
87
|
});
|
|
85
88
|
|
|
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
|
+
});
|
|
86
125
|
|
|
87
|
-
test('
|
|
88
|
-
expect(
|
|
89
|
-
expect(
|
|
90
|
-
expect(
|
|
91
|
-
expect(
|
|
92
|
-
expect(
|
|
93
|
-
expect(
|
|
94
|
-
expect(
|
|
95
|
-
expect(passwordValidation()(' ТестТест1 ', $t)).toEqual('components.passwordValidation');
|
|
96
|
-
expect(passwordValidation()(' ТестТест1@ ', $t)).toEqual(true);
|
|
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');
|
|
97
134
|
});
|
|
98
135
|
});
|
package/src/locales/en.js
CHANGED
|
@@ -56,6 +56,11 @@ 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
|
+
dropzoneText: 'Click or drag file to upload',
|
|
59
64
|
|
|
60
65
|
select: {
|
|
61
66
|
loading: 'Loading...',
|
|
@@ -99,7 +104,7 @@ module.exports = {
|
|
|
99
104
|
copyingToClipboardWasSuccessful: 'Copying to clipboard was successful',
|
|
100
105
|
},
|
|
101
106
|
table: {
|
|
102
|
-
new: 'New',
|
|
107
|
+
new: 'New row',
|
|
103
108
|
noResults: 'No items',
|
|
104
109
|
sortAscending: 'Sort ascending',
|
|
105
110
|
sortDescending: 'Sort descending',
|
|
@@ -133,7 +138,7 @@ module.exports = {
|
|
|
133
138
|
cancelSelected: 'Cancel',
|
|
134
139
|
},
|
|
135
140
|
pagination: {
|
|
136
|
-
itemsPerPage: '
|
|
141
|
+
itemsPerPage: 'On the page',
|
|
137
142
|
previous: 'Previous',
|
|
138
143
|
next: 'Next'
|
|
139
144
|
},
|
|
@@ -155,4 +160,5 @@ module.exports = {
|
|
|
155
160
|
},
|
|
156
161
|
passwordValidation: 'Password should contain at least 8 characters, including uppercase letters, lowercase letters, numbers, and special characters (e.g. @, $, !, %, *, ?, &)',
|
|
157
162
|
iveGotIt: 'I\'ve got it',
|
|
163
|
+
totalItems: 'Total',
|
|
158
164
|
};
|
package/src/locales/pl.js
CHANGED
|
@@ -133,7 +133,7 @@ module.exports = {
|
|
|
133
133
|
cancelSelected: 'Anuluj zaznaczenie',
|
|
134
134
|
},
|
|
135
135
|
pagination: {
|
|
136
|
-
itemsPerPage: '
|
|
136
|
+
itemsPerPage: 'Na stronie',
|
|
137
137
|
previous: 'Poprzednia',
|
|
138
138
|
next: 'Następna',
|
|
139
139
|
},
|
|
@@ -155,4 +155,5 @@ module.exports = {
|
|
|
155
155
|
},
|
|
156
156
|
passwordValidation: 'Hasło powinno zawierać co najmniej 8 znaków, w tym wielkie i małe litery, cyfry oraz znaki specjalne (np. @, $, !, %, *, ?, &)',
|
|
157
157
|
iveGotIt: 'Rozumiem',
|
|
158
|
+
totalItems: 'Całkowity',
|
|
158
159
|
};
|
package/src/locales/uk.js
CHANGED
|
@@ -28,8 +28,7 @@ module.exports = {
|
|
|
28
28
|
pleaseEnterValidURL: 'Будь ласка, введіть дійсний URL',
|
|
29
29
|
pleaseEnteraValidHex: 'Будь ласка, введіть дійсний код кольору',
|
|
30
30
|
passwordsDontMatch: 'Паролі не збігаються',
|
|
31
|
-
|
|
32
|
-
thisFieldMustBeANumberFormatZero: 'Це поле має містити число (формат 0.00)',
|
|
31
|
+
thisFieldMustBeANumberFormatZero: 'Це поле має містити числом (формат 0.00)',
|
|
33
32
|
theValueMustBeGreaterThanOrEqualToMinAndMax: 'Значення має бути більше або дорівнювати {min} і менше або дорівнювати {max}',
|
|
34
33
|
theValueMustBeGreaterThanOrEqualToMin: 'Значення має бути більше або дорівнювати {min}',
|
|
35
34
|
mustBeLessThanMax: 'Має бути менше ніж {max}',
|
|
@@ -57,6 +56,10 @@ module.exports = {
|
|
|
57
56
|
addMore: 'Додати ще',
|
|
58
57
|
close: 'Закрити',
|
|
59
58
|
wholeYear: 'Весь рік',
|
|
59
|
+
atLeastOneUppercaseLetterRequired: 'Має бути принаймні одна велика літера',
|
|
60
|
+
atLeastOneLowercaseLetterRequired: 'Має бути принаймні одна мала літера',
|
|
61
|
+
atLeastOneNumberRequired: 'Має бути принаймні одна цифра',
|
|
62
|
+
atLeastOneSpecialCharacterRequired: 'Має бути принаймні один спеціальний символ (@,$,!,%,*,?,&)',
|
|
60
63
|
|
|
61
64
|
select: {
|
|
62
65
|
loading: 'Завантаження...',
|
|
@@ -105,7 +108,7 @@ module.exports = {
|
|
|
105
108
|
next: 'Наступна',
|
|
106
109
|
},
|
|
107
110
|
table: {
|
|
108
|
-
new: 'Додати',
|
|
111
|
+
new: 'Додати рядок',
|
|
109
112
|
noResults: 'Немає записів',
|
|
110
113
|
sortAscending: 'Сортувати за зростанням',
|
|
111
114
|
sortDescending: 'Сортувати за спаданням',
|
|
@@ -153,7 +156,5 @@ module.exports = {
|
|
|
153
156
|
from: 'Від',
|
|
154
157
|
to: 'До',
|
|
155
158
|
value: 'Значення',
|
|
156
|
-
}
|
|
157
|
-
passwordValidation: 'Пароль має містити принаймні 8 символів, включаючи великі літери, малі літери, цифри та спеціальні символи (@, $, !, %, *, ?, &)',
|
|
158
|
-
iveGotIt: 'Зрозуміло',
|
|
159
|
+
}
|
|
159
160
|
};
|