@processmaker/screen-builder 2.83.10 → 2.84.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 +4502 -4042
- package/dist/vue-form-builder.es.js.map +1 -1
- package/dist/vue-form-builder.umd.js +52 -52
- package/dist/vue-form-builder.umd.js.map +1 -1
- package/package.json +18 -2
- package/src/App.vue +33 -56
- package/src/assets/css/custom.css +11 -0
- package/src/bootstrap.js +111 -0
- package/src/components/ScreenToolbar.vue +100 -0
- package/src/components/TabsBar.vue +354 -0
- package/src/components/editor/pagesDropdown.vue +125 -0
- package/src/components/inspector/color-select.vue +18 -1
- package/src/components/sortable/Sortable.vue +80 -0
- package/src/components/sortable/sortable.scss +25 -0
- package/src/components/sortable/sortableList/SortableList.vue +140 -0
- package/src/components/sortable/sortableList/sortableList.scss +73 -0
- package/src/components/vue-form-builder.vue +339 -253
- package/src/main.js +1 -2
- package/src/mixins/canOpenJsonFile.js +1 -1
- package/src/stories/ColorSelect.stories.js +79 -0
- package/src/stories/Configure.mdx +78 -0
- package/src/stories/DropdownAndPages.stories.js +112 -0
- package/src/stories/PageTabs.stories.js +338 -0
- package/src/stories/PagesDropdown.stories.js +132 -0
- package/src/stories/ScreenToolbar.stories.js +188 -0
- package/src/stories/Sortable.stories.js +225 -0
|
@@ -98,231 +98,192 @@
|
|
|
98
98
|
<!-- Renderer -->
|
|
99
99
|
<b-col
|
|
100
100
|
id="screen-container"
|
|
101
|
-
|
|
101
|
+
ref="screen-container"
|
|
102
|
+
class="overflow-auto mh-100 p-0 d-flex flex-column position-relative"
|
|
102
103
|
>
|
|
103
|
-
<
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
class="form-control"
|
|
108
|
-
data-cy="toolbar-page"
|
|
109
|
-
>
|
|
110
|
-
<option v-for="(data, page) in config" :key="page" :value="page">
|
|
111
|
-
{{ data.name }}
|
|
112
|
-
</option>
|
|
113
|
-
</b-form-select>
|
|
114
|
-
|
|
115
|
-
<div v-if="showToolbar">
|
|
116
|
-
<b-button
|
|
117
|
-
size="sm"
|
|
118
|
-
variant="secondary"
|
|
119
|
-
class="ml-1"
|
|
120
|
-
:title="$t('Edit Page Title')"
|
|
121
|
-
data-cy="toolbar-edit"
|
|
122
|
-
@click="openEditPageModal(currentPage)"
|
|
123
|
-
>
|
|
124
|
-
<i class="far fa-edit" />
|
|
125
|
-
</b-button>
|
|
126
|
-
|
|
127
|
-
<b-button
|
|
128
|
-
size="sm"
|
|
129
|
-
variant="danger"
|
|
130
|
-
class="ml-1"
|
|
131
|
-
:title="$t('Delete Page')"
|
|
132
|
-
:disabled="!displayDelete"
|
|
133
|
-
data-cy="toolbar-remove"
|
|
134
|
-
@click="confirmDelete()"
|
|
135
|
-
>
|
|
136
|
-
<i class="far fa-trash-alt" />
|
|
137
|
-
</b-button>
|
|
138
|
-
|
|
139
|
-
<b-button
|
|
140
|
-
v-b-modal.addPageModal
|
|
141
|
-
size="sm"
|
|
142
|
-
variant="secondary"
|
|
143
|
-
class="ml-1 mr-1"
|
|
144
|
-
:title="$t('Add New Page')"
|
|
145
|
-
data-cy="toolbar-add"
|
|
146
|
-
@click="originalPageName = null"
|
|
147
|
-
>
|
|
148
|
-
<i class="fas fa-plus" />
|
|
149
|
-
</b-button>
|
|
150
|
-
</div>
|
|
151
|
-
|
|
152
|
-
<b-button-group size="sm" class="ml-1 ml-auto">
|
|
153
|
-
<b-button :disabled="!canUndo" data-cy="toolbar-undo" @click="undo">{{
|
|
154
|
-
$t("Undo")
|
|
155
|
-
}}</b-button>
|
|
156
|
-
<b-button :disabled="!canRedo" data-cy="toolbar-redo" @click="redo">{{
|
|
157
|
-
$t("Redo")
|
|
158
|
-
}}</b-button>
|
|
159
|
-
</b-button-group>
|
|
160
|
-
|
|
161
|
-
<hr class="w-100" />
|
|
162
|
-
</b-input-group>
|
|
163
|
-
|
|
164
|
-
<div
|
|
165
|
-
v-if="isCurrentPageEmpty"
|
|
166
|
-
data-cy="screen-drop-zone"
|
|
167
|
-
class="d-flex justify-content-center align-items-center drag-placeholder text-center position-absolute rounded mt-4 flex-column"
|
|
104
|
+
<tabs-bar
|
|
105
|
+
ref="tabsBar"
|
|
106
|
+
:pages="config"
|
|
107
|
+
@tab-opened="currentPage = $event"
|
|
168
108
|
>
|
|
169
|
-
<
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
<path
|
|
177
|
-
d="M47.125 28.6562V0.5H5.71875C2.96523 0.5 0.75 2.71523 0.75 5.46875V101.531C0.75 104.285 2.96523 106.5 5.71875 106.5H75.2812C78.0348 106.5 80.25 104.285 80.25 101.531V33.625H52.0938C49.3609 33.625 47.125 31.3891 47.125 28.6562ZM60.375 77.5156C60.375 78.882 59.257 80 57.8906 80H23.1094C21.743 80 20.625 78.882 20.625 77.5156V75.8594C20.625 74.493 21.743 73.375 23.1094 73.375H57.8906C59.257 73.375 60.375 74.493 60.375 75.8594V77.5156ZM60.375 64.2656C60.375 65.632 59.257 66.75 57.8906 66.75H23.1094C21.743 66.75 20.625 65.632 20.625 64.2656V62.6094C20.625 61.243 21.743 60.125 23.1094 60.125H57.8906C59.257 60.125 60.375 61.243 60.375 62.6094V64.2656ZM60.375 49.3594V51.0156C60.375 52.382 59.257 53.5 57.8906 53.5H23.1094C21.743 53.5 20.625 52.382 20.625 51.0156V49.3594C20.625 47.993 21.743 46.875 23.1094 46.875H57.8906C59.257 46.875 60.375 47.993 60.375 49.3594ZM80.25 25.7371V27H53.75V0.5H55.0129C56.3379 0.5 57.6008 1.01758 58.5324 1.94922L78.8008 22.2383C79.7324 23.1699 80.25 24.4328 80.25 25.7371Z"
|
|
178
|
-
fill="#699CFF"
|
|
109
|
+
<template #tabs-start>
|
|
110
|
+
<pages-dropdown
|
|
111
|
+
v-if="showToolbar"
|
|
112
|
+
:data="config"
|
|
113
|
+
@addPage="$bvModal.show('addPageModal')"
|
|
114
|
+
@clickPage="onClick"
|
|
115
|
+
@seeAllPages="$bvModal.show('openSortable')"
|
|
179
116
|
/>
|
|
180
|
-
</
|
|
181
|
-
<
|
|
182
|
-
<p>
|
|
183
|
-
{{
|
|
184
|
-
$t(
|
|
185
|
-
"To begin creating a screen, drag and drop items from the Controls Menu on the left."
|
|
186
|
-
)
|
|
187
|
-
}}
|
|
188
|
-
</p>
|
|
189
|
-
<!-- {{ $t("Drag an element here") }} -->
|
|
190
|
-
</div>
|
|
191
|
-
|
|
192
|
-
<draggable
|
|
193
|
-
v-if="renderControls"
|
|
194
|
-
:key="editorContentKey"
|
|
195
|
-
data-cy="editor-content"
|
|
196
|
-
class="h-100"
|
|
197
|
-
ghost-class="form-control-ghost"
|
|
198
|
-
:value="config[currentPage].items"
|
|
199
|
-
v-bind="{
|
|
200
|
-
group: { name: 'controls' },
|
|
201
|
-
swapThreshold: 0.5
|
|
202
|
-
}"
|
|
203
|
-
@input="updateConfig"
|
|
204
|
-
>
|
|
205
|
-
<div
|
|
206
|
-
v-for="(element, index) in config[currentPage].items"
|
|
207
|
-
:key="index"
|
|
208
|
-
class="control-item mt-4 mb-4"
|
|
209
|
-
:class="{
|
|
210
|
-
selected: selected === element,
|
|
211
|
-
hasError: hasError(element)
|
|
212
|
-
}"
|
|
213
|
-
:selector="element.config.customCssSelector"
|
|
214
|
-
@click="inspect(element)"
|
|
215
|
-
>
|
|
117
|
+
</template>
|
|
118
|
+
<template #default>
|
|
216
119
|
<div
|
|
217
|
-
v-if="
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
data-cy="screen-element-container"
|
|
221
|
-
@click="inspect(element)"
|
|
120
|
+
v-if="isCurrentPageEmpty(currentPage)"
|
|
121
|
+
data-cy="screen-drop-zone"
|
|
122
|
+
class="d-flex justify-content-center align-items-center drag-placeholder text-center position-absolute rounded mt-4 flex-column"
|
|
222
123
|
>
|
|
223
|
-
<
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
124
|
+
<svg
|
|
125
|
+
width="81"
|
|
126
|
+
height="107"
|
|
127
|
+
viewBox="0 0 81 107"
|
|
128
|
+
fill="none"
|
|
129
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
227
130
|
>
|
|
228
|
-
<
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
:class="element.config.icon"
|
|
232
|
-
class="mr-2 ml-1"
|
|
131
|
+
<path
|
|
132
|
+
d="M47.125 28.6562V0.5H5.71875C2.96523 0.5 0.75 2.71523 0.75 5.46875V101.531C0.75 104.285 2.96523 106.5 5.71875 106.5H75.2812C78.0348 106.5 80.25 104.285 80.25 101.531V33.625H52.0938C49.3609 33.625 47.125 31.3891 47.125 28.6562ZM60.375 77.5156C60.375 78.882 59.257 80 57.8906 80H23.1094C21.743 80 20.625 78.882 20.625 77.5156V75.8594C20.625 74.493 21.743 73.375 23.1094 73.375H57.8906C59.257 73.375 60.375 74.493 60.375 75.8594V77.5156ZM60.375 64.2656C60.375 65.632 59.257 66.75 57.8906 66.75H23.1094C21.743 66.75 20.625 65.632 20.625 64.2656V62.6094C20.625 61.243 21.743 60.125 23.1094 60.125H57.8906C59.257 60.125 60.375 61.243 60.375 62.6094V64.2656ZM60.375 49.3594V51.0156C60.375 52.382 59.257 53.5 57.8906 53.5H23.1094C21.743 53.5 20.625 52.382 20.625 51.0156V49.3594C20.625 47.993 21.743 46.875 23.1094 46.875H57.8906C59.257 46.875 60.375 47.993 60.375 49.3594ZM80.25 25.7371V27H53.75V0.5H55.0129C56.3379 0.5 57.6008 1.01758 58.5324 1.94922L78.8008 22.2383C79.7324 23.1699 80.25 24.4328 80.25 25.7371Z"
|
|
133
|
+
fill="#699CFF"
|
|
233
134
|
/>
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
</button>
|
|
245
|
-
<button
|
|
246
|
-
v-if="!(isAiSection(element) && aiPreview(element))"
|
|
247
|
-
data-test="copy-control-btn"
|
|
248
|
-
class="btn btn-sm btn-secondary mr-2"
|
|
249
|
-
:title="$t('Copy Control')"
|
|
250
|
-
@click="duplicateItem(index)"
|
|
251
|
-
>
|
|
252
|
-
<i class="fas fa-copy text-light" />
|
|
253
|
-
</button>
|
|
254
|
-
<button
|
|
255
|
-
data-test="delete-control-btn"
|
|
256
|
-
class="btn btn-sm btn-danger"
|
|
257
|
-
:title="$t('Delete Control')"
|
|
258
|
-
@click="deleteItem(index)"
|
|
259
|
-
>
|
|
260
|
-
<i class="far fa-trash-alt text-light" />
|
|
261
|
-
</button>
|
|
262
|
-
</div>
|
|
263
|
-
</div>
|
|
264
|
-
<component
|
|
265
|
-
:is="element['editor-component']"
|
|
266
|
-
v-model="element.items"
|
|
267
|
-
:validation-errors="validationErrors"
|
|
268
|
-
class="card-body"
|
|
269
|
-
:class="elementCssClass(element)"
|
|
270
|
-
:selected="selected"
|
|
271
|
-
:config="element.config"
|
|
272
|
-
:ai-element="element"
|
|
273
|
-
@inspect="inspect"
|
|
274
|
-
@update-state="updateState"
|
|
275
|
-
/>
|
|
135
|
+
</svg>
|
|
136
|
+
<h3>{{ $t("Place your controls here.") }}</h3>
|
|
137
|
+
<p>
|
|
138
|
+
{{
|
|
139
|
+
$t(
|
|
140
|
+
"To begin creating a screen, drag and drop items from the Controls Menu on the left."
|
|
141
|
+
)
|
|
142
|
+
}}
|
|
143
|
+
</p>
|
|
144
|
+
<!-- {{ $t("Drag an element here") }} -->
|
|
276
145
|
</div>
|
|
277
146
|
|
|
278
|
-
<
|
|
147
|
+
<draggable
|
|
148
|
+
v-if="renderControls"
|
|
149
|
+
:key="editorContentKey"
|
|
150
|
+
data-cy="editor-content"
|
|
151
|
+
class="h-100"
|
|
152
|
+
ghost-class="form-control-ghost"
|
|
153
|
+
:value="config[currentPage].items"
|
|
154
|
+
v-bind="{
|
|
155
|
+
group: { name: 'controls' },
|
|
156
|
+
swapThreshold: 0.5
|
|
157
|
+
}"
|
|
158
|
+
@input="updateConfig"
|
|
159
|
+
>
|
|
279
160
|
<div
|
|
280
|
-
v-
|
|
281
|
-
|
|
161
|
+
v-for="(element, index) in config[currentPage].items"
|
|
162
|
+
:key="index"
|
|
163
|
+
class="control-item mt-4 mb-4"
|
|
164
|
+
:class="{
|
|
165
|
+
selected: selected === element,
|
|
166
|
+
hasError: hasError(element)
|
|
167
|
+
}"
|
|
168
|
+
:selector="element.config.customCssSelector"
|
|
169
|
+
@click="inspect(element)"
|
|
282
170
|
>
|
|
283
|
-
<
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
:class="element
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
class="
|
|
293
|
-
:
|
|
294
|
-
@click="duplicateItem(index)"
|
|
171
|
+
<div
|
|
172
|
+
v-if="element.container"
|
|
173
|
+
class="card container-lement"
|
|
174
|
+
:class="{ 'ai-section-card': isAiSection(element) }"
|
|
175
|
+
data-cy="screen-element-container"
|
|
176
|
+
@click="inspect(element)"
|
|
177
|
+
>
|
|
178
|
+
<div
|
|
179
|
+
v-if="selected === element"
|
|
180
|
+
class="card-header form-element-header d-flex align-items-center"
|
|
181
|
+
:class="{ pulse: isAiSection(element) && aiPreview(element) }"
|
|
295
182
|
>
|
|
296
|
-
<i class="fas fa-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
183
|
+
<i class="fas fa-arrows-alt-v mr-1 text-muted" />
|
|
184
|
+
<i
|
|
185
|
+
v-if="element.config.icon"
|
|
186
|
+
:class="element.config.icon"
|
|
187
|
+
class="mr-2 ml-1"
|
|
188
|
+
/>
|
|
189
|
+
{{ element.config.name || element.label || $t("Field Name") }}
|
|
190
|
+
<div class="ml-auto">
|
|
191
|
+
<button
|
|
192
|
+
v-if="isAiSection(element) && aiPreview(element)"
|
|
193
|
+
data-test="apply-ai-btn"
|
|
194
|
+
class="btn btn-sm btn-primary mr-2"
|
|
195
|
+
:title="$t('Apply Changes')"
|
|
196
|
+
@click="applyAiChanges(element)"
|
|
197
|
+
>
|
|
198
|
+
{{ $t("Apply Changes") }}
|
|
199
|
+
</button>
|
|
200
|
+
<button
|
|
201
|
+
v-if="!(isAiSection(element) && aiPreview(element))"
|
|
202
|
+
data-test="copy-control-btn"
|
|
203
|
+
class="btn btn-sm btn-secondary mr-2"
|
|
204
|
+
:title="$t('Copy Control')"
|
|
205
|
+
@click="duplicateItem(index)"
|
|
206
|
+
>
|
|
207
|
+
<i class="fas fa-copy text-light" />
|
|
208
|
+
</button>
|
|
209
|
+
<button
|
|
210
|
+
data-test="delete-control-btn"
|
|
211
|
+
class="btn btn-sm btn-danger"
|
|
212
|
+
:title="$t('Delete Control')"
|
|
213
|
+
@click="deleteItem(index)"
|
|
214
|
+
>
|
|
215
|
+
<i class="far fa-trash-alt text-light" />
|
|
216
|
+
</button>
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
<component
|
|
220
|
+
:is="element['editor-component']"
|
|
221
|
+
v-model="element.items"
|
|
222
|
+
:validation-errors="validationErrors"
|
|
223
|
+
class="card-body"
|
|
224
|
+
:class="elementCssClass(element)"
|
|
225
|
+
:selected="selected"
|
|
226
|
+
:config="element.config"
|
|
227
|
+
:ai-element="element"
|
|
228
|
+
@inspect="inspect"
|
|
229
|
+
@update-state="updateState"
|
|
230
|
+
/>
|
|
231
|
+
</div>
|
|
232
|
+
|
|
233
|
+
<div v-else class="card" data-cy="screen-element-container">
|
|
234
|
+
<div
|
|
235
|
+
v-if="selected === element"
|
|
236
|
+
class="card-header form-element-header d-flex align-items-center"
|
|
302
237
|
>
|
|
303
|
-
<i class="
|
|
304
|
-
|
|
238
|
+
<i class="fas fa-arrows-alt-v mr-1 text-muted" />
|
|
239
|
+
<i
|
|
240
|
+
v-if="element.config.icon"
|
|
241
|
+
:class="element.config.icon"
|
|
242
|
+
class="mr-2 ml-1"
|
|
243
|
+
/>
|
|
244
|
+
{{ element.config.name || $t("Variable Name") }}
|
|
245
|
+
<div class="ml-auto">
|
|
246
|
+
<button
|
|
247
|
+
class="btn btn-sm btn-secondary mr-2"
|
|
248
|
+
:title="$t('Copy Control')"
|
|
249
|
+
@click="duplicateItem(index)"
|
|
250
|
+
>
|
|
251
|
+
<i class="fas fa-copy text-light" />
|
|
252
|
+
</button>
|
|
253
|
+
<button
|
|
254
|
+
class="btn btn-sm btn-danger"
|
|
255
|
+
:title="$t('Delete Control')"
|
|
256
|
+
@click="deleteItem(index)"
|
|
257
|
+
>
|
|
258
|
+
<i class="far fa-trash-alt text-light" />
|
|
259
|
+
</button>
|
|
260
|
+
</div>
|
|
261
|
+
</div>
|
|
262
|
+
<component
|
|
263
|
+
v-bind="element.config"
|
|
264
|
+
:is="element['editor-component']"
|
|
265
|
+
:tabindex="element.config.interactive ? 0 : -1"
|
|
266
|
+
class="card-body m-0 pb-4 pt-4"
|
|
267
|
+
:class="[
|
|
268
|
+
elementCssClass(element),
|
|
269
|
+
{ 'prevent-interaction': !element.config.interactive }
|
|
270
|
+
]"
|
|
271
|
+
@input="
|
|
272
|
+
element.config.interactive
|
|
273
|
+
? (element.config.content = $event)
|
|
274
|
+
: null
|
|
275
|
+
"
|
|
276
|
+
@focusout.native="updateState"
|
|
277
|
+
/>
|
|
305
278
|
</div>
|
|
306
279
|
</div>
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
class="card-body m-0 pb-4 pt-4"
|
|
312
|
-
:class="[
|
|
313
|
-
elementCssClass(element),
|
|
314
|
-
{ 'prevent-interaction': !element.config.interactive }
|
|
315
|
-
]"
|
|
316
|
-
@input="
|
|
317
|
-
element.config.interactive
|
|
318
|
-
? (element.config.content = $event)
|
|
319
|
-
: null
|
|
320
|
-
"
|
|
321
|
-
@focusout.native="updateState"
|
|
322
|
-
/>
|
|
280
|
+
</draggable>
|
|
281
|
+
|
|
282
|
+
<div v-if="!isCurrentPageEmpty" data-cy="screen-drop-zone">
|
|
283
|
+
|
|
323
284
|
</div>
|
|
324
|
-
</
|
|
325
|
-
</
|
|
285
|
+
</template>
|
|
286
|
+
</tabs-bar>
|
|
326
287
|
</b-col>
|
|
327
288
|
|
|
328
289
|
<!-- Inspector -->
|
|
@@ -396,27 +357,61 @@
|
|
|
396
357
|
</b-col>
|
|
397
358
|
|
|
398
359
|
<!-- Modals -->
|
|
360
|
+
<b-modal
|
|
361
|
+
id="openSortable"
|
|
362
|
+
ref="openSortable"
|
|
363
|
+
header-close-content="×"
|
|
364
|
+
role="dialog"
|
|
365
|
+
size="lg"
|
|
366
|
+
:title="$t('Edit Pages')"
|
|
367
|
+
:ok-title="$t('DONE')"
|
|
368
|
+
ok-only
|
|
369
|
+
ok-variant="secondary"
|
|
370
|
+
header-class = "modal-header-custom"
|
|
371
|
+
>
|
|
372
|
+
<template #modal-title>
|
|
373
|
+
<h5 class="modal-title">{{ $t('Edit Pages') }}</h5>
|
|
374
|
+
<span class="modal-subtitle">{{ $t('Change pages order and name') }}</span>
|
|
375
|
+
</template>
|
|
376
|
+
<template #modal-header-close="{ close }">
|
|
377
|
+
<button type="button" aria-label="Close" class="close" @click="close()">×</button>
|
|
378
|
+
</template>
|
|
379
|
+
<Sortable
|
|
380
|
+
:items="config"
|
|
381
|
+
filter-key="name"
|
|
382
|
+
@item-edit="() => {}"
|
|
383
|
+
@item-delete="confirmDelete"
|
|
384
|
+
@add-page="$bvModal.show('addPageModal')"
|
|
385
|
+
/>
|
|
386
|
+
</b-modal>
|
|
387
|
+
|
|
399
388
|
<b-modal
|
|
400
389
|
id="addPageModal"
|
|
401
|
-
|
|
402
|
-
|
|
390
|
+
ref="addPageModal"
|
|
391
|
+
header-class="pb-2"
|
|
392
|
+
size="lg"
|
|
393
|
+
:ok-title="$t('SAVE')"
|
|
394
|
+
:cancel-title="$t('CANCEL')"
|
|
403
395
|
cancel-variant="btn btn-outline-secondary"
|
|
404
396
|
ok-variant="btn btn-secondary ml-2"
|
|
405
|
-
:title="$t('Add New Page')"
|
|
406
397
|
header-close-content="×"
|
|
407
398
|
data-cy="add-page-modal"
|
|
399
|
+
:ok-disabled="!addPageName || !!checkPageName(addPageName)"
|
|
408
400
|
@ok="addPage"
|
|
401
|
+
@show="addPageName = ''; showAddPageValidations=false;"
|
|
409
402
|
>
|
|
410
|
-
<
|
|
403
|
+
<template #modal-title>
|
|
404
|
+
<h5 class="modal-title">{{ $t('Create New Page') }}</h5>
|
|
405
|
+
<small class="modal-subtitle mb-n2">{{ $t('Create a new page in your screen') }}</small>
|
|
406
|
+
</template>
|
|
411
407
|
<form-input
|
|
412
408
|
ref="addPageInput"
|
|
413
409
|
v-model="addPageName"
|
|
414
410
|
:name="$t('Page Name')"
|
|
415
411
|
:label="$t('Page Name') + ' *'"
|
|
416
412
|
:helper="$t('The name of the new page to add')"
|
|
417
|
-
|
|
413
|
+
:error="checkPageName(addPageName)"
|
|
418
414
|
data-cy="add-page-name"
|
|
419
|
-
required
|
|
420
415
|
aria-required="true"
|
|
421
416
|
/>
|
|
422
417
|
</b-modal>
|
|
@@ -438,7 +433,8 @@
|
|
|
438
433
|
:name="$t('Page Name')"
|
|
439
434
|
:label="$t('Page Name') + ' *'"
|
|
440
435
|
:helper="$t('The new name of the page')"
|
|
441
|
-
validation="
|
|
436
|
+
validation="required"
|
|
437
|
+
:error="checkPageName(editPageName)"
|
|
442
438
|
required
|
|
443
439
|
aria-required="true"
|
|
444
440
|
/>
|
|
@@ -481,11 +477,14 @@ import "@processmaker/vue-form-elements/dist/vue-form-elements.css";
|
|
|
481
477
|
import accordions from "./accordions";
|
|
482
478
|
import { keyNameProperty } from "../form-control-common-properties";
|
|
483
479
|
import VariableNameGenerator from "@/components/VariableNameGenerator";
|
|
480
|
+
import PagesDropdown from "@/components/editor/pagesDropdown";
|
|
484
481
|
import testing from "@/mixins/testing";
|
|
485
482
|
import defaultValueEditor from "./inspector/default-value-editor";
|
|
486
483
|
import RequiredCheckbox from "./utils/required-checkbox";
|
|
487
484
|
import MultipleUploadsCheckbox from "./utils/multiple-uploads-checkbox";
|
|
488
485
|
import { formTypes } from "@/global-properties";
|
|
486
|
+
import TabsBar from "./TabsBar.vue";
|
|
487
|
+
import Sortable from './sortable/Sortable.vue';
|
|
489
488
|
|
|
490
489
|
// To include another language in the Validator with variable processmaker
|
|
491
490
|
const globalObject = typeof window === "undefined" ? global : window;
|
|
@@ -537,6 +536,7 @@ const DEFAULT_GROUP = "Advanced";
|
|
|
537
536
|
|
|
538
537
|
export default {
|
|
539
538
|
components: {
|
|
539
|
+
TabsBar,
|
|
540
540
|
draggable,
|
|
541
541
|
FormInput,
|
|
542
542
|
FormSelectList,
|
|
@@ -549,7 +549,9 @@ export default {
|
|
|
549
549
|
MultipleUploadsCheckbox,
|
|
550
550
|
defaultValueEditor,
|
|
551
551
|
...inspector,
|
|
552
|
-
...renderer
|
|
552
|
+
...renderer,
|
|
553
|
+
PagesDropdown,
|
|
554
|
+
Sortable,
|
|
553
555
|
},
|
|
554
556
|
mixins: [HasColorProperty, testing],
|
|
555
557
|
props: {
|
|
@@ -588,6 +590,8 @@ export default {
|
|
|
588
590
|
}
|
|
589
591
|
|
|
590
592
|
return {
|
|
593
|
+
showAddPageValidations: false,
|
|
594
|
+
openedPages: [0],
|
|
591
595
|
currentPage: 0,
|
|
592
596
|
selected: null,
|
|
593
597
|
display: "editor",
|
|
@@ -616,19 +620,13 @@ export default {
|
|
|
616
620
|
editorContentKey: 0,
|
|
617
621
|
cancelledJobs: [],
|
|
618
622
|
collapse: {},
|
|
619
|
-
groupOrder: {}
|
|
623
|
+
groupOrder: {}
|
|
620
624
|
};
|
|
621
625
|
},
|
|
622
626
|
computed: {
|
|
623
627
|
builder() {
|
|
624
628
|
return this;
|
|
625
629
|
},
|
|
626
|
-
canUndo() {
|
|
627
|
-
return this.$store.getters["undoRedoModule/canUndo"];
|
|
628
|
-
},
|
|
629
|
-
canRedo() {
|
|
630
|
-
return this.$store.getters["undoRedoModule/canRedo"];
|
|
631
|
-
},
|
|
632
630
|
displayDelete() {
|
|
633
631
|
return this.config.length > 1;
|
|
634
632
|
},
|
|
@@ -685,9 +683,6 @@ export default {
|
|
|
685
683
|
|
|
686
684
|
return grouped;
|
|
687
685
|
},
|
|
688
|
-
isCurrentPageEmpty() {
|
|
689
|
-
return this.config[this.currentPage].items.length === 0;
|
|
690
|
-
},
|
|
691
686
|
showToolbar() {
|
|
692
687
|
return this.screenType === formTypes.form;
|
|
693
688
|
}
|
|
@@ -732,16 +727,6 @@ export default {
|
|
|
732
727
|
}
|
|
733
728
|
},
|
|
734
729
|
created() {
|
|
735
|
-
Validator.register(
|
|
736
|
-
"unique-page-name",
|
|
737
|
-
(value) => {
|
|
738
|
-
const pageNames = this.config
|
|
739
|
-
.map((config) => config.name)
|
|
740
|
-
.filter((name) => name !== this.originalPageName);
|
|
741
|
-
return !pageNames.includes(value);
|
|
742
|
-
},
|
|
743
|
-
this.$t("Must be unique")
|
|
744
|
-
);
|
|
745
730
|
this.$store.dispatch("undoRedoModule/pushState", {
|
|
746
731
|
config: JSON.stringify(this.config),
|
|
747
732
|
currentPage: this.currentPage
|
|
@@ -775,6 +760,24 @@ export default {
|
|
|
775
760
|
this.setGroupOrder(defaultGroupOrder);
|
|
776
761
|
},
|
|
777
762
|
methods: {
|
|
763
|
+
isCurrentPageEmpty(currentPage) {
|
|
764
|
+
return this.config[currentPage]?.items?.length === 0;
|
|
765
|
+
},
|
|
766
|
+
onClick(page) {
|
|
767
|
+
this.$refs.tabsBar.openPageByIndex(page);
|
|
768
|
+
},
|
|
769
|
+
checkPageName(value, force = false) {
|
|
770
|
+
if (!force && !this.showAddPageValidations) {
|
|
771
|
+
return null;
|
|
772
|
+
}
|
|
773
|
+
if (!value.trim()) {
|
|
774
|
+
return this.$t("The Page Name field is required.");
|
|
775
|
+
}
|
|
776
|
+
const pageNames = this.config
|
|
777
|
+
.map((config) => config.name)
|
|
778
|
+
.filter((name) => name !== this.originalPageName);
|
|
779
|
+
return pageNames.includes(value) ? this.$t("Must be unique.") : "";
|
|
780
|
+
},
|
|
778
781
|
getGroupOrder(groupName) {
|
|
779
782
|
let order = _.get(this.groupOrder, groupName, Number.POSITIVE_INFINITY);
|
|
780
783
|
return order;
|
|
@@ -878,6 +881,10 @@ export default {
|
|
|
878
881
|
config.forEach((page) =>
|
|
879
882
|
this.removeDataVariableFromNestedScreens(page.items)
|
|
880
883
|
);
|
|
884
|
+
// add order attribute
|
|
885
|
+
config.forEach((page, index) => {
|
|
886
|
+
page.order = page.order || index + 1;
|
|
887
|
+
});
|
|
881
888
|
},
|
|
882
889
|
updateFieldNameValidation(items) {
|
|
883
890
|
items.forEach((item) => {
|
|
@@ -1043,23 +1050,25 @@ export default {
|
|
|
1043
1050
|
currentPage: this.currentPage
|
|
1044
1051
|
});
|
|
1045
1052
|
},
|
|
1046
|
-
undo() {
|
|
1053
|
+
async undo() {
|
|
1047
1054
|
this.inspect();
|
|
1048
1055
|
this.$store.dispatch("undoRedoModule/undo");
|
|
1049
1056
|
this.config = JSON.parse(
|
|
1050
1057
|
this.$store.getters["undoRedoModule/currentState"].config
|
|
1051
1058
|
);
|
|
1052
|
-
this
|
|
1059
|
+
await this.$nextTick();
|
|
1060
|
+
this.$refs.tabsBar.openPageByIndex(
|
|
1053
1061
|
this.$store.getters["undoRedoModule/currentState"].currentPage
|
|
1054
1062
|
);
|
|
1055
1063
|
},
|
|
1056
|
-
redo() {
|
|
1064
|
+
async redo() {
|
|
1057
1065
|
this.inspect();
|
|
1058
1066
|
this.$store.dispatch("undoRedoModule/redo");
|
|
1059
1067
|
this.config = JSON.parse(
|
|
1060
1068
|
this.$store.getters["undoRedoModule/currentState"].config
|
|
1061
1069
|
);
|
|
1062
|
-
this
|
|
1070
|
+
await this.$nextTick();
|
|
1071
|
+
this.$refs.tabsBar.openPageByIndex(
|
|
1063
1072
|
this.$store.getters["undoRedoModule/currentState"].currentPage
|
|
1064
1073
|
);
|
|
1065
1074
|
},
|
|
@@ -1072,7 +1081,7 @@ export default {
|
|
|
1072
1081
|
},
|
|
1073
1082
|
focusInspector(validation) {
|
|
1074
1083
|
this.showConfiguration = true;
|
|
1075
|
-
this.
|
|
1084
|
+
this.$refs.tabsBar.openPageByIndex(this.config.indexOf(validation.page));
|
|
1076
1085
|
this.$nextTick(() => {
|
|
1077
1086
|
this.inspect(validation.item);
|
|
1078
1087
|
this.$nextTick(() => {
|
|
@@ -1091,12 +1100,17 @@ export default {
|
|
|
1091
1100
|
});
|
|
1092
1101
|
});
|
|
1093
1102
|
},
|
|
1094
|
-
confirmDelete() {
|
|
1103
|
+
confirmDelete(item = this.config[this.currentPage]) {
|
|
1095
1104
|
this.confirmMessage = this.$t(
|
|
1096
1105
|
"Are you sure you want to delete {{item}}?",
|
|
1097
|
-
{ item:
|
|
1106
|
+
{ item: item.name }
|
|
1098
1107
|
);
|
|
1099
|
-
|
|
1108
|
+
const isLastPage = this.config.length === 1;
|
|
1109
|
+
if (isLastPage) {
|
|
1110
|
+
// can not delete the last page
|
|
1111
|
+
return;
|
|
1112
|
+
}
|
|
1113
|
+
this.pageDelete = this.config.indexOf(item);
|
|
1100
1114
|
this.$refs.confirm.show();
|
|
1101
1115
|
},
|
|
1102
1116
|
hideConfirmModal() {
|
|
@@ -1131,18 +1145,85 @@ export default {
|
|
|
1131
1145
|
this.updateState();
|
|
1132
1146
|
},
|
|
1133
1147
|
addPage(e) {
|
|
1134
|
-
|
|
1148
|
+
this.showAddPageValidations = true;
|
|
1149
|
+
const error = this.checkPageName(this.addPageName, true);
|
|
1150
|
+
if (error) {
|
|
1135
1151
|
e.preventDefault();
|
|
1136
1152
|
return;
|
|
1137
1153
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
1154
|
+
|
|
1155
|
+
const maxOrder = this.config.reduce((max, page) => {
|
|
1156
|
+
return page.order > max ? page.order : max;
|
|
1157
|
+
}, 0);
|
|
1158
|
+
|
|
1159
|
+
this.config.push({
|
|
1160
|
+
name: this.addPageName,
|
|
1161
|
+
order: maxOrder + 1,
|
|
1162
|
+
items: []
|
|
1163
|
+
});
|
|
1140
1164
|
this.addPageName = "";
|
|
1165
|
+
this.currentPage = this.config.length - 1;
|
|
1141
1166
|
this.updateState();
|
|
1167
|
+
|
|
1168
|
+
// open new page
|
|
1169
|
+
this.$refs.tabsBar.openPageByIndex(this.config.length - 1);
|
|
1170
|
+
},
|
|
1171
|
+
// This function is used to calculate the new index of the references
|
|
1172
|
+
calcNewIndexFor(index, referencedBy) {
|
|
1173
|
+
if (index === this.pageDelete) {
|
|
1174
|
+
throw new Error(
|
|
1175
|
+
`${this.$t(
|
|
1176
|
+
"Can not delete this page, it is referenced by"
|
|
1177
|
+
)}: ${referencedBy}`
|
|
1178
|
+
);
|
|
1179
|
+
}
|
|
1180
|
+
return index > this.pageDelete ? index - 1 : index;
|
|
1181
|
+
},
|
|
1182
|
+
// Update Record list references
|
|
1183
|
+
updateRecordListReferences() {
|
|
1184
|
+
this.config.forEach((page) => {
|
|
1185
|
+
page.items.forEach((item) => {
|
|
1186
|
+
if (item.component === "FormRecordList") {
|
|
1187
|
+
// eslint-disable-next-line no-param-reassign
|
|
1188
|
+
item.config.form = this.calcNewIndexFor(
|
|
1189
|
+
item.config.form * 1,
|
|
1190
|
+
item.config.label
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
1193
|
+
});
|
|
1194
|
+
});
|
|
1195
|
+
},
|
|
1196
|
+
// Update navigation buttons references
|
|
1197
|
+
updateNavigationButtonsReferences() {
|
|
1198
|
+
this.config.forEach((page) => {
|
|
1199
|
+
page.items.forEach((item) => {
|
|
1200
|
+
if (
|
|
1201
|
+
item.component === "FormButton" &&
|
|
1202
|
+
item.config.event === "pageNavigate"
|
|
1203
|
+
) {
|
|
1204
|
+
// eslint-disable-next-line no-param-reassign
|
|
1205
|
+
item.config.eventData = this.calcNewIndexFor(
|
|
1206
|
+
item.config.eventData * 1,
|
|
1207
|
+
item.config.label
|
|
1208
|
+
);
|
|
1209
|
+
}
|
|
1210
|
+
});
|
|
1211
|
+
});
|
|
1142
1212
|
},
|
|
1143
|
-
deletePage() {
|
|
1144
|
-
|
|
1145
|
-
|
|
1213
|
+
async deletePage() {
|
|
1214
|
+
const back = _.cloneDeep(this.config);
|
|
1215
|
+
try {
|
|
1216
|
+
this.updateRecordListReferences();
|
|
1217
|
+
this.updateNavigationButtonsReferences();
|
|
1218
|
+
this.$refs.tabsBar.closePageByIndex(this.pageDelete);
|
|
1219
|
+
this.$refs.tabsBar.updateTabsReferences(this.pageDelete);
|
|
1220
|
+
await this.$nextTick();
|
|
1221
|
+
this.config.splice(this.pageDelete, 1);
|
|
1222
|
+
} catch (error) {
|
|
1223
|
+
this.config = back;
|
|
1224
|
+
globalObject.ProcessMaker.alert(error.message, "danger");
|
|
1225
|
+
return;
|
|
1226
|
+
}
|
|
1146
1227
|
this.$store.dispatch("undoRedoModule/pushState", {
|
|
1147
1228
|
config: JSON.stringify(this.config),
|
|
1148
1229
|
currentPage: this.currentPage,
|
|
@@ -1282,12 +1363,13 @@ export default {
|
|
|
1282
1363
|
this.config[this.currentPage].items.push(clone);
|
|
1283
1364
|
this.updateState();
|
|
1284
1365
|
this.inspect(clone);
|
|
1285
|
-
}
|
|
1366
|
+
},
|
|
1367
|
+
|
|
1286
1368
|
}
|
|
1287
1369
|
};
|
|
1288
1370
|
</script>
|
|
1289
1371
|
|
|
1290
|
-
<style
|
|
1372
|
+
<style>
|
|
1291
1373
|
.custom-popover {
|
|
1292
1374
|
margin-right: -400px;
|
|
1293
1375
|
padding: 16px;
|
|
@@ -1445,4 +1527,8 @@ $side-bar-font-size: 0.875rem;
|
|
|
1445
1527
|
box-shadow: 0 0 0 13px rgba(0, 0, 0, 0);
|
|
1446
1528
|
}
|
|
1447
1529
|
}
|
|
1530
|
+
.modal-subtitle {
|
|
1531
|
+
font-size: 15px;
|
|
1532
|
+
font-weight: normal;
|
|
1533
|
+
}
|
|
1448
1534
|
</style>
|