@processmaker/screen-builder 2.99.3 → 3.0.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/dist/vue-form-builder.css +1 -1
- package/dist/vue-form-builder.es.js +9091 -7132
- package/dist/vue-form-builder.es.js.map +1 -1
- package/dist/vue-form-builder.umd.js +53 -53
- package/dist/vue-form-builder.umd.js.map +1 -1
- package/package.json +2 -1
- package/src/App.vue +14 -2
- package/src/DataProvider.js +42 -1
- package/src/VariableDataTypeProperties.js +1 -1
- package/src/components/ClipboardButton.vue +77 -0
- package/src/components/CssIcon.vue +21 -0
- package/src/components/ScreenTemplateCard.vue +257 -0
- package/src/components/ScreenTemplates.vue +216 -0
- package/src/components/ScreenToolbar.vue +24 -2
- package/src/components/SelectUserGroup.vue +274 -0
- package/src/components/TabsBar.vue +47 -1
- package/src/components/accordions.js +7 -1
- package/src/components/editor/loop.vue +22 -1
- package/src/components/editor/multi-column.vue +22 -2
- package/src/components/editor/pagesDropdown.vue +20 -2
- package/src/components/index.js +7 -1
- package/src/components/inspector/collection-data-source.vue +200 -0
- package/src/components/inspector/collection-display-mode.vue +87 -0
- package/src/components/inspector/collection-records-list.vue +156 -0
- package/src/components/inspector/column-setup.vue +123 -7
- package/src/components/inspector/encrypted-config.vue +78 -0
- package/src/components/inspector/index.js +4 -0
- package/src/components/inspector/page-select.vue +1 -0
- package/src/components/renderer/file-upload.vue +136 -3
- package/src/components/renderer/form-collection-record-control.vue +248 -0
- package/src/components/renderer/form-collection-view-control.vue +236 -0
- package/src/components/renderer/form-masked-input.vue +194 -9
- package/src/components/renderer/form-record-list.vue +271 -69
- package/src/components/renderer/index.js +2 -0
- package/src/components/screen-renderer.vue +2 -0
- package/src/components/task.vue +2 -1
- package/src/components/vue-form-builder.vue +156 -22
- package/src/components/vue-form-renderer.vue +10 -2
- package/src/form-builder-controls.js +168 -21
- package/src/global-properties.js +8 -0
- package/src/main.js +60 -1
- package/src/mixins/Clipboard.js +153 -0
- package/src/mixins/ScreenBase.js +7 -1
- package/src/mixins/index.js +1 -0
- package/src/store/modules/ClipboardManager.js +79 -0
- package/src/store/modules/clipboardModule.js +210 -0
- package/src/stories/ClipboardButton.stories.js +66 -0
- package/src/stories/PagesDropdown.stories.js +11 -8
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<b-button
|
|
5
5
|
class="screen-toolbar-button"
|
|
6
6
|
variant="link"
|
|
7
|
-
:disabled="!canUndo"
|
|
7
|
+
:disabled="!canUndo || disabled"
|
|
8
8
|
data-cy="toolbar-undo"
|
|
9
9
|
@click="$emit('undo')"
|
|
10
10
|
>
|
|
@@ -14,17 +14,27 @@
|
|
|
14
14
|
<b-button
|
|
15
15
|
class="screen-toolbar-button"
|
|
16
16
|
variant="link"
|
|
17
|
-
:disabled="!canRedo"
|
|
17
|
+
:disabled="!canRedo || disabled"
|
|
18
18
|
data-cy="toolbar-redo"
|
|
19
19
|
@click="$emit('redo')"
|
|
20
20
|
>
|
|
21
21
|
<i class="fas fa-redo" />
|
|
22
22
|
{{ $t("Redo") }}
|
|
23
23
|
</b-button>
|
|
24
|
+
<b-button
|
|
25
|
+
class="screen-toolbar-button"
|
|
26
|
+
variant="link"
|
|
27
|
+
data-cy="screen-templates"
|
|
28
|
+
@click="$emit('open-templates')"
|
|
29
|
+
>
|
|
30
|
+
<i class="fas fa-palette" />
|
|
31
|
+
{{ $t("Templates") }}
|
|
32
|
+
</b-button>
|
|
24
33
|
<b-button
|
|
25
34
|
type="button"
|
|
26
35
|
class="screen-toolbar-button"
|
|
27
36
|
variant="link"
|
|
37
|
+
:disabled="disabled"
|
|
28
38
|
:title="$t('Calculated Properties')"
|
|
29
39
|
data-cy="topbar-calcs"
|
|
30
40
|
@click="$emit('open-calc')"
|
|
@@ -36,6 +46,7 @@
|
|
|
36
46
|
type="button"
|
|
37
47
|
class="screen-toolbar-button"
|
|
38
48
|
variant="link"
|
|
49
|
+
:disabled="disabled"
|
|
39
50
|
:title="$t('Custom CSS')"
|
|
40
51
|
data-cy="topbar-css"
|
|
41
52
|
@click="$emit('open-customCss')"
|
|
@@ -47,6 +58,7 @@
|
|
|
47
58
|
type="button"
|
|
48
59
|
class="screen-toolbar-button"
|
|
49
60
|
variant="link"
|
|
61
|
+
:disabled="disabled"
|
|
50
62
|
:title="$t('Watchers')"
|
|
51
63
|
data-cy="topbar-watchers"
|
|
52
64
|
@click="$emit('open-watchers')"
|
|
@@ -58,6 +70,7 @@
|
|
|
58
70
|
type="button"
|
|
59
71
|
class="screen-toolbar-button"
|
|
60
72
|
variant="outlined-secondary"
|
|
73
|
+
:disabled="disabled"
|
|
61
74
|
:popper-opts="{ placement: 'bottom-end' }"
|
|
62
75
|
data-cy="topbar-options"
|
|
63
76
|
>
|
|
@@ -77,6 +90,15 @@
|
|
|
77
90
|
|
|
78
91
|
<script>
|
|
79
92
|
export default {
|
|
93
|
+
props: {
|
|
94
|
+
/**
|
|
95
|
+
* Whether the toolbar is disabled or not
|
|
96
|
+
*/
|
|
97
|
+
disabled: {
|
|
98
|
+
type: Boolean,
|
|
99
|
+
default: false
|
|
100
|
+
}
|
|
101
|
+
},
|
|
80
102
|
data() {
|
|
81
103
|
return {
|
|
82
104
|
showToolbar: true
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="form-group">
|
|
3
|
+
<label v-if="label">{{ label }}</label>
|
|
4
|
+
<multiselect
|
|
5
|
+
:id="'category-select-' + _uid"
|
|
6
|
+
v-model="content"
|
|
7
|
+
track-by="id"
|
|
8
|
+
label="fullname"
|
|
9
|
+
group-values="items"
|
|
10
|
+
group-label="type"
|
|
11
|
+
:class="{'border border-danger':error}"
|
|
12
|
+
:loading="loading"
|
|
13
|
+
:placeholder="placeholder ? placeholder : $t('type here to search')"
|
|
14
|
+
:options="options"
|
|
15
|
+
:multiple="multiple"
|
|
16
|
+
:show-labels="false"
|
|
17
|
+
:searchable="true"
|
|
18
|
+
:internal-search="false"
|
|
19
|
+
@open="load(null)"
|
|
20
|
+
@input="updateSeletected"
|
|
21
|
+
@search-change="load">
|
|
22
|
+
|
|
23
|
+
<template slot="noResult">
|
|
24
|
+
<slot name="noResult">{{ $t("No elements found. Consider changing the search query.") }}</slot>
|
|
25
|
+
</template>
|
|
26
|
+
<template slot="noOptions">
|
|
27
|
+
<slot name="noOptions">{{ $t("No Data Available") }}</slot>
|
|
28
|
+
</template>
|
|
29
|
+
</multiselect>
|
|
30
|
+
|
|
31
|
+
<small v-if="error" class="text-danger">{{ error }}</small>
|
|
32
|
+
<small v-if="helper" class="form-text text-muted">{{ $t(helper) }}</small>
|
|
33
|
+
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<script>
|
|
39
|
+
export default {
|
|
40
|
+
props: {
|
|
41
|
+
value: null,
|
|
42
|
+
label: {
|
|
43
|
+
type: String,
|
|
44
|
+
default: ""
|
|
45
|
+
},
|
|
46
|
+
multiple: {
|
|
47
|
+
type: Boolean,
|
|
48
|
+
default: true
|
|
49
|
+
},
|
|
50
|
+
hideUsers: {
|
|
51
|
+
type: Boolean,
|
|
52
|
+
default: false
|
|
53
|
+
},
|
|
54
|
+
hideGroups: {
|
|
55
|
+
type: Boolean,
|
|
56
|
+
default: false
|
|
57
|
+
},
|
|
58
|
+
error: String,
|
|
59
|
+
helper: String,
|
|
60
|
+
placeholder: String,
|
|
61
|
+
},
|
|
62
|
+
data () {
|
|
63
|
+
return {
|
|
64
|
+
loading: false,
|
|
65
|
+
selected: {
|
|
66
|
+
users: [],
|
|
67
|
+
groups: []
|
|
68
|
+
},
|
|
69
|
+
options: [],
|
|
70
|
+
results: [],
|
|
71
|
+
lastEmitted: "",
|
|
72
|
+
labelUsers: this.$t("Users"),
|
|
73
|
+
labelGroups: this.$t("Groups"),
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
computed: {
|
|
77
|
+
content: {
|
|
78
|
+
get () {
|
|
79
|
+
if (this.loading) {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
return this.selected.users.map(user => {
|
|
83
|
+
let uid;
|
|
84
|
+
if (typeof user === 'number') {
|
|
85
|
+
uid = user;
|
|
86
|
+
} else {
|
|
87
|
+
uid = user.id;
|
|
88
|
+
}
|
|
89
|
+
return this.results.find(item => item.id === uid);
|
|
90
|
+
})
|
|
91
|
+
.concat(this.selected.groups.map(group => {
|
|
92
|
+
let gid;
|
|
93
|
+
if (typeof group == 'number') {
|
|
94
|
+
gid = "group-" + group;
|
|
95
|
+
} else {
|
|
96
|
+
gid = group.id;
|
|
97
|
+
}
|
|
98
|
+
return this.results.find(item => item.id === gid);
|
|
99
|
+
|
|
100
|
+
}));
|
|
101
|
+
},
|
|
102
|
+
set (value) {
|
|
103
|
+
this.selected.users = [];
|
|
104
|
+
this.selected.groups = [];
|
|
105
|
+
if (value === null) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// If it is array (this happens when the Select User/Group is selected)
|
|
110
|
+
// add value just if it is not empty
|
|
111
|
+
if (Array.isArray(value) && value.length) {
|
|
112
|
+
value.forEach(item => {
|
|
113
|
+
this.results.push(item);
|
|
114
|
+
if (typeof item.id === "number") {
|
|
115
|
+
this.selected.users.push(item.id);
|
|
116
|
+
} else {
|
|
117
|
+
this.selected.groups.push(parseInt(item.id.substr(6)));
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
//If an object arrives as value (this happens with Self Service and assign by expression)
|
|
123
|
+
if (!Array.isArray(value) && value)
|
|
124
|
+
{
|
|
125
|
+
this.results.push(value);
|
|
126
|
+
if (typeof value.id === "number") {
|
|
127
|
+
this.selected.users.push(value);
|
|
128
|
+
} else {
|
|
129
|
+
this.selected.groups.push(value);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
watch: {
|
|
137
|
+
value: {
|
|
138
|
+
immediate: true,
|
|
139
|
+
deep: true,
|
|
140
|
+
handler (value) {
|
|
141
|
+
if (!value) {
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
if (value.users.length === 0 && value.groups.length === 0) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (JSON.stringify(value) == this.lastEmitted) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
this.loading = true;
|
|
151
|
+
let results = [];
|
|
152
|
+
|
|
153
|
+
let usersPromise = Promise.all(
|
|
154
|
+
value.users.map(item => {
|
|
155
|
+
if (typeof item == 'number' || typeof item == 'string') {
|
|
156
|
+
return ProcessMaker.apiClient.get("users/" + item);
|
|
157
|
+
} else {
|
|
158
|
+
if (item.assignee) {
|
|
159
|
+
let id = item.assignee;
|
|
160
|
+
return ProcessMaker.apiClient.get("users/" + id);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
})
|
|
164
|
+
)
|
|
165
|
+
.then(items => {
|
|
166
|
+
items.forEach(item => {
|
|
167
|
+
results.push(this.addUsernameToFullName(item.data));
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
let groupsPromise = Promise.all(
|
|
172
|
+
value.groups.map(item => {
|
|
173
|
+
if (typeof item == 'number' || typeof item == 'string' ) {
|
|
174
|
+
return ProcessMaker.apiClient.get("groups/" + item);
|
|
175
|
+
} else {
|
|
176
|
+
if (item.assignee) {
|
|
177
|
+
let id = this.unformatGroup(item.assignee);
|
|
178
|
+
return ProcessMaker.apiClient.get("groups/" + id);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
})
|
|
182
|
+
)
|
|
183
|
+
.then(items => {
|
|
184
|
+
items.forEach(item => {
|
|
185
|
+
results.push(this.formatGroup(item.data));
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
Promise.all([usersPromise, groupsPromise])
|
|
190
|
+
.then(() => {
|
|
191
|
+
this.content = results;
|
|
192
|
+
this.loading = false;
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
methods: {
|
|
198
|
+
updateSeletected() {
|
|
199
|
+
this.lastEmitted = JSON.stringify(this.selected);
|
|
200
|
+
this.$emit("input", this.selected);
|
|
201
|
+
},
|
|
202
|
+
addUsernameToFullName(user) {
|
|
203
|
+
if (!user.fullname || ! user.username)
|
|
204
|
+
{
|
|
205
|
+
return user;
|
|
206
|
+
}
|
|
207
|
+
let status = '';
|
|
208
|
+
if (user.status === 'INACTIVE') {
|
|
209
|
+
status = " - " + this.$t('Inactive');
|
|
210
|
+
}
|
|
211
|
+
return {...user, fullname: `${user.fullname} (${user.username}${status})`};
|
|
212
|
+
},
|
|
213
|
+
load (filter) {
|
|
214
|
+
this.options = [];
|
|
215
|
+
if (!this.hideUsers) {
|
|
216
|
+
this.loadUsers(filter);
|
|
217
|
+
}
|
|
218
|
+
if (!this.hideGroups) {
|
|
219
|
+
this.loadGroups(filter);
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
loadUsers (filter) {
|
|
223
|
+
ProcessMaker.apiClient
|
|
224
|
+
.get("users" + (typeof filter === "string" ? "?filter=" + filter : ""))
|
|
225
|
+
.then(response => {
|
|
226
|
+
const users = response.data.data.map(user => this.addUsernameToFullName(user));
|
|
227
|
+
this.users = users;
|
|
228
|
+
|
|
229
|
+
if (response.data.data) {
|
|
230
|
+
this.options.push({
|
|
231
|
+
"type": this.labelUsers,
|
|
232
|
+
"items": users,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
},
|
|
237
|
+
loadGroups (filter) {
|
|
238
|
+
ProcessMaker.apiClient
|
|
239
|
+
.get("groups" + (typeof filter === "string" ? "?filter=" + filter : ""))
|
|
240
|
+
.then(response => {
|
|
241
|
+
let groups = response.data.data.map(item => {
|
|
242
|
+
return this.formatGroup(item);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
if (groups) {
|
|
246
|
+
this.options.push({
|
|
247
|
+
"type": this.labelGroups,
|
|
248
|
+
"items": groups
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
},
|
|
253
|
+
formatGroup (item) {
|
|
254
|
+
if (item && typeof item.id == 'number') {
|
|
255
|
+
item.id = "group-" + item.id;
|
|
256
|
+
}
|
|
257
|
+
item.fullname = item.name;
|
|
258
|
+
if (item.status === 'INACTIVE') {
|
|
259
|
+
item.fullname += " (" + this.$t('Inactive') + ")";
|
|
260
|
+
}
|
|
261
|
+
return item;
|
|
262
|
+
},
|
|
263
|
+
unformatGroup(groupId) {
|
|
264
|
+
if (typeof groupId == 'number') {
|
|
265
|
+
return groupId;
|
|
266
|
+
} else {
|
|
267
|
+
let id = groupId.replace('group-', "");
|
|
268
|
+
return id;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
</script>
|
|
@@ -58,6 +58,29 @@
|
|
|
58
58
|
</div>
|
|
59
59
|
</template>
|
|
60
60
|
</b-tab>
|
|
61
|
+
<b-tab
|
|
62
|
+
v-if="showClipboard"
|
|
63
|
+
ref="clipboard"
|
|
64
|
+
class="h-100 w-100"
|
|
65
|
+
name="clipboard"
|
|
66
|
+
>
|
|
67
|
+
<template #title>
|
|
68
|
+
{{ $t('Clipboard') }}
|
|
69
|
+
<span
|
|
70
|
+
:data-test="`close-clipboard-tab`"
|
|
71
|
+
class="close-tab"
|
|
72
|
+
role="link"
|
|
73
|
+
@click.stop="closeClipboard"
|
|
74
|
+
>
|
|
75
|
+
<i class="fas fa-times" />
|
|
76
|
+
</span>
|
|
77
|
+
</template>
|
|
78
|
+
<template #default>
|
|
79
|
+
<div class="h-100 w-100" data-test="tab-content">
|
|
80
|
+
<slot :current-page="clipboardPageIndex" />
|
|
81
|
+
</div>
|
|
82
|
+
</template>
|
|
83
|
+
</b-tab>
|
|
61
84
|
<template #tabs-end>
|
|
62
85
|
<div
|
|
63
86
|
v-if="tabsListOverflow"
|
|
@@ -115,6 +138,13 @@ export default {
|
|
|
115
138
|
isMultiPage: {
|
|
116
139
|
type: Boolean,
|
|
117
140
|
default: true
|
|
141
|
+
},
|
|
142
|
+
/**
|
|
143
|
+
* Show clipboard tab
|
|
144
|
+
*/
|
|
145
|
+
showClipboard: {
|
|
146
|
+
type: Boolean,
|
|
147
|
+
default: false
|
|
118
148
|
}
|
|
119
149
|
},
|
|
120
150
|
data() {
|
|
@@ -128,6 +158,9 @@ export default {
|
|
|
128
158
|
};
|
|
129
159
|
},
|
|
130
160
|
computed: {
|
|
161
|
+
clipboardPageIndex() {
|
|
162
|
+
return this.pages.length;
|
|
163
|
+
},
|
|
131
164
|
validLocalOpenedPages() {
|
|
132
165
|
return this.localOpenedPages.filter((page) => this.pages[page]);
|
|
133
166
|
}
|
|
@@ -170,9 +203,22 @@ export default {
|
|
|
170
203
|
this.checkTabsOverflow();
|
|
171
204
|
},
|
|
172
205
|
methods: {
|
|
206
|
+
openClipboard() {
|
|
207
|
+
if (this.$refs.clipboard) {
|
|
208
|
+
this.$refs.clipboard.activate();
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
closeClipboard() {
|
|
212
|
+
this.$emit('close-clipboard');
|
|
213
|
+
},
|
|
173
214
|
tabOpened() {
|
|
174
215
|
const pageIndex = this.localOpenedPages[this.activeTab];
|
|
175
|
-
this.$
|
|
216
|
+
const isInClipboard = (this.activeTab === this.$refs.tabs.tabs.length - 1) && this.showClipboard;
|
|
217
|
+
if (isInClipboard) {
|
|
218
|
+
this.$emit("tab-opened", this.clipboardPageIndex);
|
|
219
|
+
} else {
|
|
220
|
+
this.$emit("tab-opened", pageIndex);
|
|
221
|
+
}
|
|
176
222
|
},
|
|
177
223
|
pageNumber(index) {
|
|
178
224
|
return index + 1;
|
|
@@ -13,7 +13,11 @@ export default [
|
|
|
13
13
|
'initiallyChecked',
|
|
14
14
|
'screen',
|
|
15
15
|
'multipleUpload',
|
|
16
|
-
'linkUrl'
|
|
16
|
+
'linkUrl',
|
|
17
|
+
'collection',
|
|
18
|
+
'record',
|
|
19
|
+
'collectionmode',
|
|
20
|
+
'submitCollectionCheck',
|
|
17
21
|
],
|
|
18
22
|
open: true,
|
|
19
23
|
},
|
|
@@ -47,6 +51,7 @@ export default [
|
|
|
47
51
|
},
|
|
48
52
|
fields: [
|
|
49
53
|
'fields',
|
|
54
|
+
'paginationOption',
|
|
50
55
|
{ name: 'options', hideFor: 'FormMultiColumn' },
|
|
51
56
|
],
|
|
52
57
|
open: false,
|
|
@@ -80,6 +85,7 @@ export default [
|
|
|
80
85
|
{name: 'tabindex', showFor: 'FormSelectList'},
|
|
81
86
|
{name: 'tabindex', showFor: 'FormButton'},
|
|
82
87
|
{name: 'tabindex', showFor: 'FormTextArea'},
|
|
88
|
+
{name: 'encryptedConfig', showFor: 'FormInput'},
|
|
83
89
|
],
|
|
84
90
|
open: false,
|
|
85
91
|
},
|
|
@@ -28,6 +28,15 @@
|
|
|
28
28
|
/>
|
|
29
29
|
{{ element.config.name || $t("Variable Name") }}
|
|
30
30
|
<div class="ml-auto">
|
|
31
|
+
<clipboard-button
|
|
32
|
+
:index="index"
|
|
33
|
+
:config="element.config"
|
|
34
|
+
:isInClipboard="isInClipboard(items[index])"
|
|
35
|
+
:addTitle="$t('Add to clipboard')"
|
|
36
|
+
:removeTitle="$t('Remove from clipboard')"
|
|
37
|
+
@addToClipboard="addToClipboard(items[index])"
|
|
38
|
+
@removeFromClipboard="removeFromClipboard(items[index])"
|
|
39
|
+
/>
|
|
31
40
|
<button
|
|
32
41
|
v-if="isAiSection(element) && aiPreview(element)"
|
|
33
42
|
class="btn btn-sm btn-primary mr-2"
|
|
@@ -83,6 +92,15 @@
|
|
|
83
92
|
/>
|
|
84
93
|
{{ element.config.name || $t("Variable Name") }}
|
|
85
94
|
<div class="ml-auto">
|
|
95
|
+
<clipboard-button
|
|
96
|
+
:index="index"
|
|
97
|
+
:config="element.config"
|
|
98
|
+
:isInClipboard="isInClipboard(items[index])"
|
|
99
|
+
:addTitle="$t('Add to clipboard')"
|
|
100
|
+
:removeTitle="$t('Remove from clipboard')"
|
|
101
|
+
@addToClipboard="addToClipboard(items[index])"
|
|
102
|
+
@removeFromClipboard="removeFromClipboard(items[index])"
|
|
103
|
+
/>
|
|
86
104
|
<button
|
|
87
105
|
class="btn btn-sm btn-secondary mr-2"
|
|
88
106
|
:title="$t('Copy Control')"
|
|
@@ -136,6 +154,8 @@ import {
|
|
|
136
154
|
FormTextArea
|
|
137
155
|
} from "@processmaker/vue-form-elements";
|
|
138
156
|
import { HasColorProperty } from "@/mixins";
|
|
157
|
+
import { Clipboard } from "@/mixins";
|
|
158
|
+
import ClipboardButton from '../ClipboardButton.vue';
|
|
139
159
|
import * as renderer from "@/components/renderer";
|
|
140
160
|
|
|
141
161
|
export default {
|
|
@@ -149,9 +169,10 @@ export default {
|
|
|
149
169
|
FormDatePicker,
|
|
150
170
|
FormHtmlEditor,
|
|
151
171
|
FormHtmlViewer,
|
|
172
|
+
ClipboardButton,
|
|
152
173
|
...renderer
|
|
153
174
|
},
|
|
154
|
-
mixins: [HasColorProperty],
|
|
175
|
+
mixins: [HasColorProperty, Clipboard],
|
|
155
176
|
props: ["value", "name", "config", "selected", "validationErrors"],
|
|
156
177
|
data() {
|
|
157
178
|
return {
|
|
@@ -43,6 +43,15 @@
|
|
|
43
43
|
/>
|
|
44
44
|
{{ element.config.name || $t("Variable Name") }}
|
|
45
45
|
<div class="ml-auto">
|
|
46
|
+
<clipboard-button
|
|
47
|
+
:index="index"
|
|
48
|
+
:config="element.config"
|
|
49
|
+
:isInClipboard="isInClipboard(element)"
|
|
50
|
+
:addTitle="$t('Add to clipboard')"
|
|
51
|
+
:removeTitle="$t('Remove from clipboard')"
|
|
52
|
+
@addToClipboard="addToClipboard(element)"
|
|
53
|
+
@removeFromClipboard="removeFromClipboard(element)"
|
|
54
|
+
/>
|
|
46
55
|
<button
|
|
47
56
|
v-if="isAiSection(element) && aiPreview(element)"
|
|
48
57
|
class="btn btn-sm btn-primary mr-2"
|
|
@@ -100,6 +109,15 @@
|
|
|
100
109
|
/>
|
|
101
110
|
{{ element.config.name || $t("Variable Name") }}
|
|
102
111
|
<div class="ml-auto">
|
|
112
|
+
<clipboard-button
|
|
113
|
+
:index="index"
|
|
114
|
+
:config="element.config"
|
|
115
|
+
:isInClipboard="isInClipboard(element)"
|
|
116
|
+
:addTitle="$t('Add to clipboard')"
|
|
117
|
+
:removeTitle="$t('Remove from clipboard')"
|
|
118
|
+
@addToClipboard="addToClipboard(element)"
|
|
119
|
+
@removeFromClipboard="removeFromClipboard(element)"
|
|
120
|
+
/>
|
|
103
121
|
<button
|
|
104
122
|
class="btn btn-sm btn-secondary mr-2"
|
|
105
123
|
:title="$t('Copy Control')"
|
|
@@ -156,8 +174,9 @@ import {
|
|
|
156
174
|
FormTextArea
|
|
157
175
|
} from "@processmaker/vue-form-elements";
|
|
158
176
|
import { HasColorProperty } from "@/mixins";
|
|
177
|
+
import { Clipboard } from "@/mixins";
|
|
159
178
|
import * as renderer from "@/components/renderer";
|
|
160
|
-
|
|
179
|
+
import ClipboardButton from '../ClipboardButton.vue';
|
|
161
180
|
const defaultColumnWidth = 1;
|
|
162
181
|
|
|
163
182
|
export default {
|
|
@@ -171,9 +190,10 @@ export default {
|
|
|
171
190
|
FormDatePicker,
|
|
172
191
|
FormHtmlEditor,
|
|
173
192
|
FormHtmlViewer,
|
|
193
|
+
ClipboardButton,
|
|
174
194
|
...renderer
|
|
175
195
|
},
|
|
176
|
-
mixins: [HasColorProperty],
|
|
196
|
+
mixins: [HasColorProperty, Clipboard],
|
|
177
197
|
props: ["value", "name", "config", "selected", "validationErrors"],
|
|
178
198
|
data() {
|
|
179
199
|
return {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
<!-- Option to add a new page -->
|
|
20
20
|
<b-dropdown-item data-test="add-page" @click="onAddPage">
|
|
21
21
|
<!-- Icon for adding a new page -->
|
|
22
|
-
<i class="
|
|
22
|
+
<i class="fas fa-plus platform-dropdown-item-icon text-dark w-icon text-center"></i>
|
|
23
23
|
<!-- Text for adding a new page -->
|
|
24
24
|
{{ $t("Create Page") }}
|
|
25
25
|
</b-dropdown-item>
|
|
@@ -27,11 +27,19 @@
|
|
|
27
27
|
<!-- Option to see all pages -->
|
|
28
28
|
<b-dropdown-item data-test="see-all-pages" @click="onSeeAllPages">
|
|
29
29
|
<!-- Icon for seeing all pages -->
|
|
30
|
-
<i class="
|
|
30
|
+
<i class="far fa-eye platform-dropdown-item-icon text-dark w-icon text-center"></i>
|
|
31
31
|
<!-- Text for seeing all pages -->
|
|
32
32
|
{{ $t("See all pages") }}
|
|
33
33
|
</b-dropdown-item>
|
|
34
34
|
|
|
35
|
+
<!-- Option to open Clipboard page -->
|
|
36
|
+
<b-dropdown-item data-test="clipboard" @click="onClipboard" class="d-flex">
|
|
37
|
+
<!-- Icon for clipboard -->
|
|
38
|
+
<i class="far fa-clipboard platform-dropdown-item-icon text-dark w-icon text-center"></i>
|
|
39
|
+
<!-- Text for clipboard -->
|
|
40
|
+
{{ $t("Clipboard") }}
|
|
41
|
+
</b-dropdown-item>
|
|
42
|
+
|
|
35
43
|
<!-- Divider between adding and viewing options -->
|
|
36
44
|
<b-dropdown-divider></b-dropdown-divider>
|
|
37
45
|
|
|
@@ -100,6 +108,13 @@ export default {
|
|
|
100
108
|
this.$emit("seeAllPages");
|
|
101
109
|
},
|
|
102
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Handle when user clicks on "Clipboard
|
|
113
|
+
*/
|
|
114
|
+
onClipboard() {
|
|
115
|
+
this.$emit("clipboard");
|
|
116
|
+
},
|
|
117
|
+
|
|
103
118
|
/**
|
|
104
119
|
* Handler for when a specific page is clicked.
|
|
105
120
|
* Emits the "clickPage" event with the selected page.
|
|
@@ -122,4 +137,7 @@ export default {
|
|
|
122
137
|
// Style for the icons in dropdown items.
|
|
123
138
|
color: #1572c2;
|
|
124
139
|
}
|
|
140
|
+
.w-icon {
|
|
141
|
+
width: 1.25rem;
|
|
142
|
+
}
|
|
125
143
|
</style>
|
package/src/components/index.js
CHANGED
|
@@ -29,6 +29,7 @@ import { LRUCache } from "lru-cache";
|
|
|
29
29
|
import Vuex from "vuex";
|
|
30
30
|
import globalErrorsModule from "../store/modules/globalErrorsModule";
|
|
31
31
|
import undoRedoModule from "../store/modules/undoRedoModule";
|
|
32
|
+
import clipboardModule from "../store/modules/clipboardModule";
|
|
32
33
|
import BasicSearch from "./basic-search.vue";
|
|
33
34
|
import ComputedProperties from "./computed-properties.vue";
|
|
34
35
|
import CustomCSS from "./custom-css.vue";
|
|
@@ -49,6 +50,8 @@ import accordions from "@/components/accordions";
|
|
|
49
50
|
import VariableNameGenerator from "@/components/VariableNameGenerator";
|
|
50
51
|
import { LinkButton } from "./renderer";
|
|
51
52
|
import "../assets/css/tabs.css";
|
|
53
|
+
import FormCollectionRecordControl from "./renderer/form-collection-record-control.vue";
|
|
54
|
+
import FormCollectionViewControl from "./renderer/form-collection-view-control.vue";
|
|
52
55
|
|
|
53
56
|
const rendererComponents = {
|
|
54
57
|
...renderer,
|
|
@@ -163,11 +166,14 @@ export default {
|
|
|
163
166
|
Vue.use(Vuex);
|
|
164
167
|
Vue.component("FormListTable", FormListTable);
|
|
165
168
|
Vue.component("LinkButton", LinkButton);
|
|
169
|
+
Vue.component("FormCollectionRecordControl", FormCollectionRecordControl);
|
|
170
|
+
Vue.component("FormCollectionViewControl", FormCollectionViewControl);
|
|
166
171
|
const store = new Vuex.Store({
|
|
167
172
|
modules: {
|
|
168
173
|
globalErrorsModule,
|
|
169
174
|
// @todo Improve how to load this module, it is used only in the form builder, not used in the form renderer.
|
|
170
|
-
undoRedoModule
|
|
175
|
+
undoRedoModule,
|
|
176
|
+
clipboardModule
|
|
171
177
|
}
|
|
172
178
|
});
|
|
173
179
|
Vue.mixin({ store });
|