@processmaker/screen-builder 2.90.0 → 2.92.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.
- package/README.md +5 -4
- package/dist/vue-form-builder.css +1 -1
- package/dist/vue-form-builder.es.js +7897 -7488
- package/dist/vue-form-builder.es.js.map +1 -1
- package/dist/vue-form-builder.umd.js +76 -59
- package/dist/vue-form-builder.umd.js.map +1 -1
- package/package.json +3 -3
- package/src/DataProvider.js +31 -11
- package/src/assets/icons/Bypass.svg +5 -0
- package/src/assets/icons/Unbypass.svg +5 -0
- package/src/components/accordions.js +1 -0
- package/src/components/computed-properties.vue +211 -110
- package/src/components/index.js +2 -0
- package/src/components/inspector/options-list.vue +1 -1
- package/src/components/renderer/form-list-table.vue +11 -2
- package/src/components/renderer/form-requests.vue +13 -26
- package/src/components/renderer/form-tasks.vue +5 -3
- package/src/components/renderer/index.js +1 -0
- package/src/components/renderer/link-button.vue +30 -0
- package/src/components/sortable/Sortable.vue +95 -13
- package/src/components/sortable/sortable.scss +5 -0
- package/src/components/sortable/sortableList/SortableList.vue +103 -36
- package/src/components/sortable/sortableList/sortableList.scss +63 -22
- package/src/components/task.vue +256 -59
- package/src/components/vue-form-builder.vue +19 -10
- package/src/components/watchers-form.vue +4 -3
- package/src/components/watchers-list.vue +46 -100
- package/src/components/watchers-popup.vue +89 -16
- package/src/customLogs.js +26 -0
- package/src/form-builder-controls.js +42 -0
- package/src/main.js +26 -1
- package/src/mixins/Json2Vue.js +5 -3
- package/src/mixins/computedFields.js +25 -7
- package/src/mixins/extensions/ComputedFields.js +26 -5
- package/src/mixins/extensions/Watchers.js +4 -0
- package/src/mixins/watchers.js +5 -2
- package/src/stories/Sortable.stories.js +58 -11
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div v-if="showTable">
|
|
3
3
|
<filter-table
|
|
4
|
+
table-name="form-cases"
|
|
4
5
|
:headers="tableHeaders"
|
|
5
6
|
:data="tableData"
|
|
6
7
|
:unread="unreadColumnName"
|
|
7
8
|
:loading="shouldShowLoader"
|
|
8
9
|
>
|
|
9
|
-
<template
|
|
10
|
-
v-for="(row, rowIndex) in data.data"
|
|
11
|
-
v-slot:[`row-${rowIndex}`]
|
|
12
|
-
>
|
|
10
|
+
<template v-for="(row, rowIndex) in data.data" #[`row-${rowIndex}`]>
|
|
13
11
|
<td
|
|
14
12
|
v-for="(header, colIndex) in tableHeaders"
|
|
15
13
|
:key="`${rowIndex}-${colIndex}`"
|
|
@@ -98,7 +96,7 @@ export default {
|
|
|
98
96
|
},
|
|
99
97
|
computed: {
|
|
100
98
|
noDataUrl() {
|
|
101
|
-
return `${window.ProcessMaker?.app?.url}/
|
|
99
|
+
return `${window.ProcessMaker?.app?.url}/cases`;
|
|
102
100
|
}
|
|
103
101
|
},
|
|
104
102
|
mounted() {
|
|
@@ -167,11 +165,12 @@ export default {
|
|
|
167
165
|
variant: "primary",
|
|
168
166
|
textColor: "text-primary",
|
|
169
167
|
colorText: "color: #1572C2",
|
|
170
|
-
url: "/
|
|
168
|
+
url: "/cases",
|
|
171
169
|
dropdownShow: "requests"
|
|
172
170
|
};
|
|
173
171
|
const tasksDropdown = [];
|
|
174
172
|
this.$emit("requestsCount", { dataControls, tasksDropdown });
|
|
173
|
+
this.$refs["form-case"].resetToOriginalWidths();
|
|
175
174
|
})
|
|
176
175
|
.catch(() => {
|
|
177
176
|
this.tableData = [];
|
|
@@ -249,24 +248,17 @@ export default {
|
|
|
249
248
|
this.fetch();
|
|
250
249
|
},
|
|
251
250
|
setupColumns() {
|
|
252
|
-
const
|
|
253
|
-
this.tableHeaders = this.
|
|
251
|
+
const columnsCases = this.getColumnsCases();
|
|
252
|
+
this.tableHeaders = this.getColumnsCases();
|
|
254
253
|
|
|
255
|
-
|
|
254
|
+
columnsCases.forEach((column) => {
|
|
256
255
|
const field = {
|
|
257
|
-
title: () => this.$t(column.label)
|
|
256
|
+
title: () => this.$t(column.label)
|
|
258
257
|
};
|
|
259
258
|
|
|
260
259
|
switch (column.field) {
|
|
261
|
-
case "
|
|
262
|
-
field.name = "__slot:
|
|
263
|
-
field.title = "#";
|
|
264
|
-
break;
|
|
265
|
-
case "participants":
|
|
266
|
-
field.name = "__slot:participants";
|
|
267
|
-
break;
|
|
268
|
-
case "name":
|
|
269
|
-
field.name = "__slot:name";
|
|
260
|
+
case "case_number":
|
|
261
|
+
field.name = "__slot:case_number";
|
|
270
262
|
break;
|
|
271
263
|
case "case_title":
|
|
272
264
|
field.name = "__slot:case_title";
|
|
@@ -293,13 +285,8 @@ export default {
|
|
|
293
285
|
|
|
294
286
|
this.fields.push(field);
|
|
295
287
|
});
|
|
296
|
-
|
|
297
|
-
this.fields.push({
|
|
298
|
-
name: "__slot:actions",
|
|
299
|
-
title: ""
|
|
300
|
-
});
|
|
301
288
|
},
|
|
302
|
-
|
|
289
|
+
getColumnsCases() {
|
|
303
290
|
return [
|
|
304
291
|
{
|
|
305
292
|
label: "Case #",
|
|
@@ -325,7 +312,7 @@ export default {
|
|
|
325
312
|
sortable: true,
|
|
326
313
|
default: true,
|
|
327
314
|
width: 113,
|
|
328
|
-
fixed_width:
|
|
315
|
+
fixed_width: 113,
|
|
329
316
|
resizable: false,
|
|
330
317
|
filter_subject: { type: "Status" }
|
|
331
318
|
},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div v-if="showTable">
|
|
3
3
|
<filter-table
|
|
4
|
+
table-name="form-tasks"
|
|
4
5
|
:headers="tableHeaders"
|
|
5
6
|
:data="tableData"
|
|
6
7
|
:unread="unreadColumnName"
|
|
@@ -270,6 +271,7 @@ export default {
|
|
|
270
271
|
dropdownShow: "tasks"
|
|
271
272
|
};
|
|
272
273
|
this.$emit("tasksCount", { dataControls, tasksDropdown });
|
|
274
|
+
this.$refs["form-task"].resetToOriginalWidths();
|
|
273
275
|
})
|
|
274
276
|
.catch(() => {
|
|
275
277
|
this.tableData = [];
|
|
@@ -308,7 +310,7 @@ export default {
|
|
|
308
310
|
let draftBadge = "";
|
|
309
311
|
if (record.draft && record.status !== "CLOSED") {
|
|
310
312
|
draftBadge = `
|
|
311
|
-
<span class ="badge badge-warning status-
|
|
313
|
+
<span class ="badge badge-warning status-warning">
|
|
312
314
|
${this.$t("Draft")}
|
|
313
315
|
</span>
|
|
314
316
|
`;
|
|
@@ -386,9 +388,9 @@ export default {
|
|
|
386
388
|
},
|
|
387
389
|
setupColumns() {
|
|
388
390
|
this.tableHeaders = this.getColumns();
|
|
389
|
-
const
|
|
391
|
+
const columnsTasks = this.getColumns();
|
|
390
392
|
|
|
391
|
-
|
|
393
|
+
columnsTasks.forEach((column) => {
|
|
392
394
|
const field = {
|
|
393
395
|
title: () => this.$t(column.label)
|
|
394
396
|
};
|
|
@@ -18,3 +18,4 @@ export { default as FormListTable } from "./form-list-table.vue";
|
|
|
18
18
|
export { default as FormAnalyticsChart } from "./form-analytics-chart.vue";
|
|
19
19
|
export { default as FormRequests } from "./form-requests.vue";
|
|
20
20
|
export { default as FormTasks } from "./form-tasks.vue";
|
|
21
|
+
export { default as LinkButton } from "./link-button.vue";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="form-group">
|
|
3
|
+
<a :class="classColor" :href="inputUrlLink"> {{ label }} </a>
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
export default {
|
|
9
|
+
props: [
|
|
10
|
+
"variant",
|
|
11
|
+
"label",
|
|
12
|
+
"event",
|
|
13
|
+
"eventData",
|
|
14
|
+
"name",
|
|
15
|
+
"fieldValue",
|
|
16
|
+
"value",
|
|
17
|
+
"inputUrlLink"
|
|
18
|
+
],
|
|
19
|
+
computed: {
|
|
20
|
+
classColor() {
|
|
21
|
+
return `text-${this.variant}`;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
</script>
|
|
26
|
+
<style scoped>
|
|
27
|
+
a {
|
|
28
|
+
text-decoration: underline;
|
|
29
|
+
}
|
|
30
|
+
</style>
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
<button
|
|
16
16
|
type="button"
|
|
17
17
|
class="btn sortable-btn-new"
|
|
18
|
+
v-bind="testActions.btnNew"
|
|
18
19
|
@click="$emit('add-page', $event)"
|
|
19
20
|
>
|
|
20
21
|
<i class="fa fa-plus"></i>
|
|
@@ -23,26 +24,47 @@
|
|
|
23
24
|
</div>
|
|
24
25
|
|
|
25
26
|
<SortableList
|
|
27
|
+
:fields="fields"
|
|
26
28
|
:items="items"
|
|
27
29
|
:filtered-items="filteredItems"
|
|
30
|
+
:inline-edit="inlineEdit"
|
|
31
|
+
:disable-key="disableKey"
|
|
32
|
+
:data-test-actions="testActions"
|
|
28
33
|
@ordered="$emit('ordered', $event)"
|
|
29
34
|
@item-edit="$emit('item-edit', $event)"
|
|
30
35
|
@item-delete="$emit('item-delete', $event)"
|
|
31
|
-
|
|
36
|
+
>
|
|
37
|
+
<template #options="{ item }">
|
|
38
|
+
<slot name="options" :item="item"></slot>
|
|
39
|
+
</template>
|
|
40
|
+
</SortableList>
|
|
32
41
|
</div>
|
|
33
42
|
</template>
|
|
34
43
|
|
|
35
44
|
<script>
|
|
36
|
-
import SortableList from './sortableList/SortableList.vue'
|
|
45
|
+
import SortableList from './sortableList/SortableList.vue';
|
|
37
46
|
|
|
38
47
|
export default {
|
|
39
48
|
name: 'Sortable',
|
|
40
49
|
components: {
|
|
41
|
-
SortableList
|
|
50
|
+
SortableList,
|
|
42
51
|
},
|
|
43
52
|
props: {
|
|
53
|
+
fields: { type: Array, required: true },
|
|
44
54
|
items: { type: Array, required: true },
|
|
45
|
-
|
|
55
|
+
disableKey: { type: String, default: null },
|
|
56
|
+
inlineEdit: { type: Boolean, default: true },
|
|
57
|
+
dataTestActions: {
|
|
58
|
+
type: Object,
|
|
59
|
+
default: () => ({}),
|
|
60
|
+
},
|
|
61
|
+
searchProperties: {
|
|
62
|
+
type: Array,
|
|
63
|
+
required: false,
|
|
64
|
+
default() {
|
|
65
|
+
return []; // Return a new instance of the array
|
|
66
|
+
},
|
|
67
|
+
},
|
|
46
68
|
},
|
|
47
69
|
data() {
|
|
48
70
|
return {
|
|
@@ -54,34 +76,94 @@ export default {
|
|
|
54
76
|
this.$set(item, "order", index + 1);
|
|
55
77
|
}
|
|
56
78
|
return item;
|
|
57
|
-
})
|
|
79
|
+
}),
|
|
80
|
+
defaultTestActions: {
|
|
81
|
+
tableBox: { 'data-test': 'sortable-table-box' },
|
|
82
|
+
btnNew: { 'data-test': 'sortable-btn-new' },
|
|
83
|
+
btnEdit: { 'data-test': 'sortable-btn-edit' },
|
|
84
|
+
btnDelete: { 'data-test': 'sortable-btn-remove' },
|
|
85
|
+
},
|
|
58
86
|
};
|
|
59
87
|
},
|
|
88
|
+
computed: {
|
|
89
|
+
testActions() {
|
|
90
|
+
return { ...this.defaultTestActions, ...this.dataTestActions };
|
|
91
|
+
},
|
|
92
|
+
},
|
|
60
93
|
watch: {
|
|
61
94
|
search(value) {
|
|
62
|
-
this.filteredItems = this.filterItems(value, this.items);
|
|
95
|
+
this.filteredItems = this.filterItems(value, this.items, this.searchProperties);
|
|
63
96
|
},
|
|
64
97
|
items: {
|
|
65
98
|
handler(newItems) {
|
|
66
99
|
this.filteredItems = [...newItems];
|
|
67
100
|
|
|
68
101
|
if (this.search.length > 0) {
|
|
69
|
-
this.filteredItems = this.filterItems(this.search, newItems);
|
|
102
|
+
this.filteredItems = this.filterItems(this.search, newItems, this.searchProperties);
|
|
70
103
|
}
|
|
71
104
|
},
|
|
72
105
|
deep: true,
|
|
73
106
|
},
|
|
74
107
|
},
|
|
75
108
|
methods: {
|
|
76
|
-
|
|
77
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Filters items by searching within specified properties, including nested properties, considering substrings.
|
|
111
|
+
*
|
|
112
|
+
* @param {string} searchValue - The value to search for within item properties.
|
|
113
|
+
* @param {Array} items - The collection of items to filter.
|
|
114
|
+
* @param {Array} searchProperties - The properties to search within each item.
|
|
115
|
+
* @returns {Array} - The filtered items.
|
|
116
|
+
*/
|
|
117
|
+
filterItems(searchValue, items, searchProperties) {
|
|
118
|
+
const cleanSearch = this.clearSearch(searchValue).toLowerCase();
|
|
119
|
+
|
|
120
|
+
return items.filter((item) => {
|
|
121
|
+
return this.propertyMatchesSearch(item, searchProperties, cleanSearch);
|
|
122
|
+
});
|
|
78
123
|
},
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Checks if any of the specified properties of an item match the cleaned search value as a substring.
|
|
127
|
+
*
|
|
128
|
+
* @param {Object} item - The item object to check.
|
|
129
|
+
* @param {Array} properties - The properties to search within each item.
|
|
130
|
+
* @param {string} cleanSearch - The cleaned and lowercase search value.
|
|
131
|
+
* @returns {boolean} - True if any property matches the search value, otherwise false.
|
|
132
|
+
*/
|
|
133
|
+
propertyMatchesSearch(item, properties, cleanSearch) {
|
|
134
|
+
return properties.some((property) => {
|
|
135
|
+
const value = this.getPropertyValue(item, property);
|
|
136
|
+
if (value && typeof value === 'string') {
|
|
137
|
+
const normalizedValue = value.toLowerCase();
|
|
138
|
+
return normalizedValue.includes(cleanSearch);
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
141
|
+
});
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Retrieves the value of a nested property within an object.
|
|
146
|
+
*
|
|
147
|
+
* @param {Object} obj - The object from which to retrieve the property value.
|
|
148
|
+
* @param {string} path - The path to the nested property, e.g., "item.title".
|
|
149
|
+
* @returns {*} - The value of the nested property if found, otherwise undefined.
|
|
150
|
+
*/
|
|
151
|
+
getPropertyValue(obj, path) {
|
|
152
|
+
const parts = path.split('.');
|
|
153
|
+
return parts.reduce((acc, curr) => acc?.[curr], obj);
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Cleans the search value by removing unwanted characters and trimming spaces.
|
|
158
|
+
*
|
|
159
|
+
* @param {string} searchValue - The value to be cleaned.
|
|
160
|
+
* @returns {string} - The cleaned search value.
|
|
161
|
+
*/
|
|
162
|
+
clearSearch(searchValue) {
|
|
163
|
+
return searchValue.trim();
|
|
82
164
|
},
|
|
83
165
|
},
|
|
84
|
-
}
|
|
166
|
+
};
|
|
85
167
|
</script>
|
|
86
168
|
|
|
87
169
|
<style lang="scss" scoped src="./sortable.scss"></style>
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
.sortable {
|
|
2
2
|
&-box {
|
|
3
3
|
font-family: "Open Sans", sans-serif !important;
|
|
4
|
+
overflow-x: auto;
|
|
4
5
|
}
|
|
5
6
|
|
|
6
7
|
&-search-box {
|
|
7
8
|
display: flex;
|
|
8
9
|
align-items: center;
|
|
9
10
|
border-color: #cdddee !important;
|
|
11
|
+
|
|
12
|
+
& > input.form-control:focus {
|
|
13
|
+
border: 0 none !important;
|
|
14
|
+
}
|
|
10
15
|
}
|
|
11
16
|
|
|
12
17
|
&-search-icon {
|
|
@@ -1,51 +1,90 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="row mt-3">
|
|
3
|
-
<div
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
<div class="sortable-
|
|
3
|
+
<div
|
|
4
|
+
class="p-0 border rounded-lg sortable-list"
|
|
5
|
+
v-bind="dataTestActions.tableBox"
|
|
6
|
+
@dragover="dragOver"
|
|
7
|
+
>
|
|
8
|
+
<div class="sortable-list-tr">
|
|
9
|
+
<div class="sortable-list-td"></div>
|
|
9
10
|
<div
|
|
10
|
-
v-for="
|
|
11
|
-
:key="
|
|
12
|
-
|
|
13
|
-
:data-test="`item-${item.order}`"
|
|
14
|
-
:title="item.name"
|
|
15
|
-
draggable="true"
|
|
16
|
-
@dragstart="(event) => dragStart(event, item.order)"
|
|
17
|
-
@dragenter="(event) => dragEnter(event, item.order)"
|
|
18
|
-
@dragend="dragEnd"
|
|
19
|
-
class="sortable-item sortable-draggable"
|
|
11
|
+
v-for="field in fields"
|
|
12
|
+
:key="field.key"
|
|
13
|
+
class="sortable-list-td"
|
|
20
14
|
>
|
|
15
|
+
<span class="sortable-list-separator"> </span>
|
|
16
|
+
<span class="sortable-list-header">{{ field.label }}</span>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="sortable-list-td">
|
|
19
|
+
<span class="sortable-list-separator"> </span>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
<div
|
|
23
|
+
v-for="(item, index) in sortedItems"
|
|
24
|
+
:key="`item-${index}`"
|
|
25
|
+
:data-order="item.order"
|
|
26
|
+
:data-test="`item-${item.order}`"
|
|
27
|
+
:title="item.name"
|
|
28
|
+
:class="[
|
|
29
|
+
'sortable-list-tr',
|
|
30
|
+
'sortable-item',
|
|
31
|
+
{ 'sortable-item-disabled': isDisabled(item) },
|
|
32
|
+
]"
|
|
33
|
+
draggable="true"
|
|
34
|
+
@dragstart="(event) => dragStart(event, item.order)"
|
|
35
|
+
@dragenter="(event) => dragEnter(event, item.order)"
|
|
36
|
+
@dragend="dragEnd"
|
|
37
|
+
>
|
|
38
|
+
<div class="sortable-list-td">
|
|
21
39
|
<div class="sortable-item-icon">
|
|
22
40
|
<i class="fas fa-bars"></i>
|
|
23
41
|
</div>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
</div>
|
|
43
|
+
<div
|
|
44
|
+
v-for="field in fields"
|
|
45
|
+
:key="field.key"
|
|
46
|
+
class="sortable-list-td sortable-item-prop"
|
|
47
|
+
>
|
|
48
|
+
<b-form-input
|
|
49
|
+
v-if="editRowIndex === index"
|
|
50
|
+
v-model="newName"
|
|
51
|
+
type="text"
|
|
52
|
+
autofocus
|
|
53
|
+
required
|
|
54
|
+
:state="validateState(newName, item)"
|
|
55
|
+
:error="validateError(newName, item)"
|
|
56
|
+
@blur.stop="onBlur(newName, item)"
|
|
57
|
+
@keydown.enter.stop="onBlur(newName, item)"
|
|
58
|
+
@keydown.esc.stop="onCancel(item)"
|
|
59
|
+
@focus="onFocus(item)"
|
|
60
|
+
/>
|
|
61
|
+
<span v-else>{{ getItemValue(item, field.key, field.cb) }}</span>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<div class="sortable-list-td">
|
|
40
65
|
<div class="border rounded-lg sortable-item-action">
|
|
41
66
|
<button v-if="editRowIndex === index" class="btn">
|
|
42
67
|
<i class="fas fa-check"></i>
|
|
43
68
|
</button>
|
|
44
|
-
<button
|
|
69
|
+
<button
|
|
70
|
+
v-else
|
|
71
|
+
v-b-tooltip="{ customClass: 'sortable-item-action-btn-tooltip' }"
|
|
72
|
+
class="btn"
|
|
73
|
+
:title="$t('Edit')"
|
|
74
|
+
v-bind="dataTestActions.btnEdit"
|
|
75
|
+
@click.stop="onClick(item, index)"
|
|
76
|
+
>
|
|
45
77
|
<i class="fas fa-edit"></i>
|
|
46
78
|
</button>
|
|
47
79
|
<div class="sortable-item-vr"></div>
|
|
48
|
-
<
|
|
80
|
+
<slot name="options" :item="item"></slot>
|
|
81
|
+
<button
|
|
82
|
+
v-b-tooltip="{ customClass: 'sortable-item-action-btn-tooltip' }"
|
|
83
|
+
class="btn"
|
|
84
|
+
:title="$t('Delete')"
|
|
85
|
+
v-bind="dataTestActions.btnDelete"
|
|
86
|
+
@click="$emit('item-delete', item)"
|
|
87
|
+
>
|
|
49
88
|
<i class="fas fa-trash-alt"></i>
|
|
50
89
|
</button>
|
|
51
90
|
</div>
|
|
@@ -59,8 +98,12 @@
|
|
|
59
98
|
export default {
|
|
60
99
|
name: 'SortableList',
|
|
61
100
|
props: {
|
|
101
|
+
fields: { type: Array, required: true },
|
|
62
102
|
items: { type: Array, required: true },
|
|
63
103
|
filteredItems: { type: Array, required: true },
|
|
104
|
+
inlineEdit: { type: Boolean, default: true },
|
|
105
|
+
disableKey: { type: String, default: null },
|
|
106
|
+
dataTestActions: { type: Object, required: true },
|
|
64
107
|
},
|
|
65
108
|
data() {
|
|
66
109
|
return {
|
|
@@ -77,9 +120,22 @@ export default {
|
|
|
77
120
|
this.refreshSort &&
|
|
78
121
|
[...this.filteredItems].sort((a, b) => a.order - b.order);
|
|
79
122
|
return sortedItems;
|
|
80
|
-
}
|
|
123
|
+
},
|
|
81
124
|
},
|
|
82
125
|
methods: {
|
|
126
|
+
/** Get the value of a nested field in an object
|
|
127
|
+
* @param {Object} item - The object to get the value from
|
|
128
|
+
* @param {String} fieldKey - The key of the field to get the value from
|
|
129
|
+
* @param {Function} cb - Callback function to apply to the value
|
|
130
|
+
*
|
|
131
|
+
* @returns {String} The value of the field
|
|
132
|
+
*/
|
|
133
|
+
getItemValue(item, fieldKey, cb = null) {
|
|
134
|
+
return fieldKey.split('.').reduce((obj, key) => {
|
|
135
|
+
if (!obj[key]) return '';
|
|
136
|
+
return cb instanceof Function ? cb(obj[key]) : obj[key];
|
|
137
|
+
}, item);
|
|
138
|
+
},
|
|
83
139
|
validateState(name, item) {
|
|
84
140
|
const isEmpty = !name?.trim();
|
|
85
141
|
const isDuplicated = this.items
|
|
@@ -120,6 +176,11 @@ export default {
|
|
|
120
176
|
this.editRowIndex = null;
|
|
121
177
|
},
|
|
122
178
|
onClick(item, index) {
|
|
179
|
+
if (!this.inlineEdit) {
|
|
180
|
+
this.$emit("item-edit", item);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
123
184
|
this.editRowIndex = index;
|
|
124
185
|
this.$emit("item-edit", item);
|
|
125
186
|
},
|
|
@@ -129,6 +190,9 @@ export default {
|
|
|
129
190
|
this.draggedItem = order;
|
|
130
191
|
// add dragging class to the element
|
|
131
192
|
event.target.classList.add('dragging');
|
|
193
|
+
if (event?.dataTransfer) {
|
|
194
|
+
event.dataTransfer.effectAllowed = 'move';
|
|
195
|
+
}
|
|
132
196
|
},
|
|
133
197
|
dragEnter(event, order) {
|
|
134
198
|
this.draggedOverItem = order;
|
|
@@ -185,8 +249,11 @@ export default {
|
|
|
185
249
|
dragOver(event) {
|
|
186
250
|
event.preventDefault();
|
|
187
251
|
},
|
|
252
|
+
isDisabled(item) {
|
|
253
|
+
return this.disableKey ? item[this.disableKey] : false;
|
|
254
|
+
},
|
|
188
255
|
},
|
|
189
|
-
}
|
|
256
|
+
};
|
|
190
257
|
</script>
|
|
191
258
|
|
|
192
259
|
<style lang="scss" scoped src="./sortableList.scss"></style>
|
|
@@ -2,44 +2,67 @@ $border-color: #cdddee;
|
|
|
2
2
|
|
|
3
3
|
.sortable {
|
|
4
4
|
&-list {
|
|
5
|
-
display:
|
|
5
|
+
display: table;
|
|
6
6
|
flex-direction: column;
|
|
7
|
+
width: 100%;
|
|
7
8
|
border: 1px solid $border-color !important;
|
|
8
9
|
|
|
9
|
-
&-
|
|
10
|
-
display:
|
|
11
|
-
|
|
10
|
+
&-tr {
|
|
11
|
+
display: table-row;
|
|
12
|
+
|
|
13
|
+
&:last-child > .sortable-list-td {
|
|
14
|
+
border-bottom: none;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
&-td {
|
|
19
|
+
display: table-cell;
|
|
12
20
|
border-bottom: 1px solid $border-color;
|
|
21
|
+
white-space: nowrap;
|
|
22
|
+
|
|
23
|
+
&:first-child {
|
|
24
|
+
width: 60px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
&:nth-child(2) {
|
|
28
|
+
min-width: 30%;
|
|
29
|
+
width: auto;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&:not(:first-child):not(:nth-child(2)):not(:last-child) {
|
|
33
|
+
width: auto;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
&:last-child {
|
|
37
|
+
width: 1%;
|
|
38
|
+
white-space: nowrap;
|
|
39
|
+
}
|
|
13
40
|
}
|
|
14
41
|
|
|
15
|
-
&-
|
|
16
|
-
padding
|
|
42
|
+
&-header {
|
|
43
|
+
padding: 16px 0 16px 16px;
|
|
17
44
|
font-size: 14px;
|
|
18
|
-
font-weight:
|
|
45
|
+
font-weight: 700;
|
|
19
46
|
color: #566877;
|
|
47
|
+
text-transform: uppercase;
|
|
48
|
+
display: inline-block;
|
|
49
|
+
white-space: normal;
|
|
50
|
+
}
|
|
51
|
+
&-separator {
|
|
52
|
+
border-left: 1px solid $border-color;
|
|
53
|
+
display: inline-block;
|
|
54
|
+
padding: 0.5rem 0rem;
|
|
55
|
+
width: 1px;
|
|
20
56
|
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
&-container {
|
|
24
|
-
display: flex;
|
|
25
|
-
flex-direction: column;
|
|
26
|
-
width: 100%;
|
|
27
|
-
height: 340px;
|
|
28
|
-
overflow-x: auto;
|
|
29
57
|
}
|
|
30
58
|
|
|
31
59
|
&-item {
|
|
32
|
-
display: flex;
|
|
33
|
-
align-items: center;
|
|
34
|
-
height: 56px;
|
|
35
|
-
border-bottom: 1px solid $border-color;
|
|
36
60
|
cursor: move;
|
|
37
61
|
|
|
38
62
|
&-icon {
|
|
39
63
|
display: flex;
|
|
40
64
|
justify-content: center;
|
|
41
65
|
align-items: center;
|
|
42
|
-
width: 64px;
|
|
43
66
|
height: 56px;
|
|
44
67
|
}
|
|
45
68
|
|
|
@@ -47,8 +70,7 @@ $border-color: #cdddee;
|
|
|
47
70
|
color: #6A7888;
|
|
48
71
|
}
|
|
49
72
|
|
|
50
|
-
&-
|
|
51
|
-
flex-grow: 1;
|
|
73
|
+
&-prop {
|
|
52
74
|
padding: 8px 16px;
|
|
53
75
|
font-size: 15px;
|
|
54
76
|
color: #556271;
|
|
@@ -58,6 +80,18 @@ $border-color: #cdddee;
|
|
|
58
80
|
display: flex;
|
|
59
81
|
margin: 0 16px;
|
|
60
82
|
border-color: $border-color !important;
|
|
83
|
+
|
|
84
|
+
&-btn-tooltip::v-deep {
|
|
85
|
+
& .tooltip-inner {
|
|
86
|
+
background-color: #EBEEF2 !important;
|
|
87
|
+
color: #444444 !important;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
& .arrow:before {
|
|
91
|
+
border-top-color: #EBEEF2 !important;
|
|
92
|
+
border-bottom-color: #EBEEF2 !important;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
61
95
|
}
|
|
62
96
|
|
|
63
97
|
&-vr {
|
|
@@ -65,9 +99,16 @@ $border-color: #cdddee;
|
|
|
65
99
|
margin: 9px 0;
|
|
66
100
|
border-right: 1px solid $border-color;
|
|
67
101
|
}
|
|
102
|
+
|
|
103
|
+
&-disabled > .sortable-item-prop {
|
|
104
|
+
color: rgba(85, 98, 113, 0.5);
|
|
105
|
+
}
|
|
68
106
|
}
|
|
69
107
|
}
|
|
70
108
|
|
|
71
109
|
.dragging {
|
|
72
110
|
box-shadow: 0 1px 5px 0 rgba(86, 104, 119, 0.4);
|
|
111
|
+
cursor: move;
|
|
112
|
+
cursor: -webkit-grab;
|
|
113
|
+
cursor: -moz-grab;
|
|
73
114
|
}
|