@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
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClipboardManager class to handle saving to and loading from
|
|
3
|
+
* localStorage and the server.
|
|
4
|
+
*/
|
|
5
|
+
class ClipboardManager {
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Callable property function that loads the clipboard from server.
|
|
9
|
+
*/
|
|
10
|
+
static loadFromServerFn = null;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Callable property function that saves the clipboard to server.
|
|
14
|
+
*/
|
|
15
|
+
static saveToServerFn = null;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Saves the clipboard items to localStorage.
|
|
19
|
+
* @param {Array} clipboard - The clipboard items to save.
|
|
20
|
+
*/
|
|
21
|
+
static saveToLocalStorage(clipboard) {
|
|
22
|
+
localStorage.setItem('clipboard', JSON.stringify(clipboard));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Loads the clipboard items from localStorage.
|
|
27
|
+
* @returns {Array} The clipboard items.
|
|
28
|
+
*/
|
|
29
|
+
static loadFromLocalStorage() {
|
|
30
|
+
const clipboardData = localStorage.getItem('clipboard');
|
|
31
|
+
if (clipboardData) {
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(clipboardData);
|
|
34
|
+
} catch (e) {
|
|
35
|
+
console.error('Failed to parse clipboard data from localStorage:', e);
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Saves the clipboard items to the server via POST /clipboard/create_or_update.
|
|
45
|
+
* @param {Array} clipboard - The clipboard items to save.
|
|
46
|
+
* @returns {Promise}
|
|
47
|
+
*/
|
|
48
|
+
static saveToServer(clipboard) {
|
|
49
|
+
// return axios.post('/clipboard/create_or_update', { clipboard });
|
|
50
|
+
if (!ClipboardManager.saveToServerFn) {
|
|
51
|
+
return Promise.resolve();
|
|
52
|
+
}
|
|
53
|
+
return ClipboardManager.saveToServerFn(clipboard);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Loads the clipboard items from the server via GET /clipboard/get_by_user.
|
|
58
|
+
* @returns {Promise<Array>} The clipboard items.
|
|
59
|
+
*/
|
|
60
|
+
static loadFromServer() {
|
|
61
|
+
if (!ClipboardManager.loadFromServerFn) {
|
|
62
|
+
return Promise.resolve([]);
|
|
63
|
+
}
|
|
64
|
+
return ClipboardManager.loadFromServerFn()
|
|
65
|
+
.then(clipboard => {
|
|
66
|
+
if (Array.isArray(clipboard)) {
|
|
67
|
+
return clipboard;
|
|
68
|
+
} else {
|
|
69
|
+
throw new Error('Invalid server response: Expected array for clipboard content');
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
.catch(error => {
|
|
73
|
+
console.error('Failed to load clipboard from server:', error);
|
|
74
|
+
return [];
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export default ClipboardManager;
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
+
import ClipboardManager from './ClipboardManager';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Vuex module for managing clipboard state with localStorage synchronization.
|
|
6
|
+
*/
|
|
7
|
+
const clipboardModule = {
|
|
8
|
+
/**
|
|
9
|
+
* Indicates that this module is namespaced, which means
|
|
10
|
+
* all its state, mutations, actions, and getters will be
|
|
11
|
+
* scoped to this module.
|
|
12
|
+
*/
|
|
13
|
+
namespaced: true,
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The state of the clipboard module.
|
|
17
|
+
* @returns {Object} The initial state of the clipboard.
|
|
18
|
+
*/
|
|
19
|
+
state() {
|
|
20
|
+
return {
|
|
21
|
+
/**
|
|
22
|
+
* @type {Array} Array to store clipboard items.
|
|
23
|
+
*/
|
|
24
|
+
clipboard: [],
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Getters provide read-only access to the state.
|
|
30
|
+
*/
|
|
31
|
+
getters: {
|
|
32
|
+
/**
|
|
33
|
+
* Returns all items in the clipboard.
|
|
34
|
+
* @param {Object} state - The state of the module.
|
|
35
|
+
* @returns {Array} The array of clipboard items.
|
|
36
|
+
*/
|
|
37
|
+
clipboardItems: state => state.clipboard,
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Checks if an item with a specific uuid is present in the clipboard.
|
|
41
|
+
* @param {Object} state - The state of the module.
|
|
42
|
+
* @returns {Function} Function to check item presence.
|
|
43
|
+
*/
|
|
44
|
+
isInClipboard: state => item => {
|
|
45
|
+
if (!item || !item.uuid) {
|
|
46
|
+
// If the item is invalid or doesn't have an uuid, return false
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return state.clipboard.some(clipboardItem => clipboardItem.uuid === item.uuid);
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Mutations are used to modify the state.
|
|
55
|
+
*/
|
|
56
|
+
mutations: {
|
|
57
|
+
/**
|
|
58
|
+
* Sets the entire clipboard state.
|
|
59
|
+
* @param {Object} state - The state of the module.
|
|
60
|
+
* @param {Array} clipboard - The new clipboard array.
|
|
61
|
+
*/
|
|
62
|
+
SET_CLIPBOARD(state, clipboard) {
|
|
63
|
+
if (!Array.isArray(clipboard)) {
|
|
64
|
+
throw new Error('Clipboard content must be an array');
|
|
65
|
+
}
|
|
66
|
+
state.clipboard.splice(0, state.clipboard.length, ...clipboard);
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Adds items to the clipboard.
|
|
71
|
+
* @param {Object} state - The state of the module.
|
|
72
|
+
* @param {any} items - The items to add.
|
|
73
|
+
*/
|
|
74
|
+
ADD_TO_CLIPBOARD(state, items) {
|
|
75
|
+
const itemsToAdd = Array.isArray(items) ? items : [items];
|
|
76
|
+
itemsToAdd.forEach(item => {
|
|
77
|
+
if (!item.uuid) {
|
|
78
|
+
item.uuid = uuidv4();
|
|
79
|
+
}
|
|
80
|
+
if (!state.clipboard.some(clipboardItem => clipboardItem.uuid === item.uuid)) {
|
|
81
|
+
state.clipboard.push(item);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Removes a specific item from the clipboard.
|
|
88
|
+
* @param {Object} state - The state of the module.
|
|
89
|
+
* @param {any} item - The item to remove.
|
|
90
|
+
*/
|
|
91
|
+
REMOVE_FROM_CLIPBOARD(state, item) {
|
|
92
|
+
if (!item || !item.uuid) {
|
|
93
|
+
console.error('Item or item uuid is missing');
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const index = state.clipboard.findIndex(clipboardItem => clipboardItem.uuid === item.uuid);
|
|
97
|
+
if (index !== -1) {
|
|
98
|
+
state.clipboard.splice(index, 1);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Clears all items from the clipboard.
|
|
104
|
+
* @param {Object} state - The state of the module.
|
|
105
|
+
*/
|
|
106
|
+
CLEAR_CLIPBOARD(state) {
|
|
107
|
+
state.clipboard.splice(0, state.clipboard.length);
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Actions are used to commit mutations and can contain asynchronous operations.
|
|
113
|
+
*/
|
|
114
|
+
actions: {
|
|
115
|
+
/**
|
|
116
|
+
* Initializes the clipboard by loading from localStorage and server,
|
|
117
|
+
* and setting up the storage event listener.
|
|
118
|
+
* @param {Object} context - The Vuex context.
|
|
119
|
+
*/
|
|
120
|
+
initializeClipboard({ commit }) {
|
|
121
|
+
// Load from localStorage
|
|
122
|
+
const clipboard = ClipboardManager.loadFromLocalStorage();
|
|
123
|
+
commit('SET_CLIPBOARD', clipboard);
|
|
124
|
+
|
|
125
|
+
// Load from server and update state
|
|
126
|
+
ClipboardManager.loadFromServer().then(serverClipboard => {
|
|
127
|
+
if (serverClipboard.length > 0) {
|
|
128
|
+
commit('SET_CLIPBOARD', serverClipboard);
|
|
129
|
+
ClipboardManager.saveToLocalStorage(serverClipboard);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Set up storage event listener
|
|
134
|
+
window.addEventListener('storage', event => {
|
|
135
|
+
if (event.key === 'clipboard') {
|
|
136
|
+
const clipboard = ClipboardManager.loadFromLocalStorage();
|
|
137
|
+
commit('SET_CLIPBOARD', clipboard);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Setup saveToServerFn
|
|
144
|
+
* @param {Object} context - The Vuex context.
|
|
145
|
+
* @param {Function} saveToServerFn - The function to save the clipboard to the server.
|
|
146
|
+
*/
|
|
147
|
+
setupSaveToServerFn({ commit }, saveToServerFn) {
|
|
148
|
+
ClipboardManager.saveToServerFn = saveToServerFn;
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Setup loadFromServerFn
|
|
153
|
+
* @param {Object} context - The Vuex context.
|
|
154
|
+
* @param {Function} loadFromServerFn - The function to load the clipboard from the server.
|
|
155
|
+
*/
|
|
156
|
+
setupLoadFromServerFn({ commit }, loadFromServerFn) {
|
|
157
|
+
ClipboardManager.loadFromServerFn = loadFromServerFn;
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Adds an item to the clipboard.
|
|
162
|
+
* Updates localStorage and the server.
|
|
163
|
+
* @param {Object} context - The Vuex context.
|
|
164
|
+
* @param {any} item - The item to add.
|
|
165
|
+
*/
|
|
166
|
+
addToClipboard({ commit, state }, item) {
|
|
167
|
+
if (!item) {
|
|
168
|
+
throw new Error('Item is missing');
|
|
169
|
+
}
|
|
170
|
+
commit('ADD_TO_CLIPBOARD', item);
|
|
171
|
+
// Save to localStorage and server
|
|
172
|
+
ClipboardManager.saveToLocalStorage(state.clipboard);
|
|
173
|
+
ClipboardManager.saveToServer(state.clipboard);
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
pushState({ commit, state }, clipboard) {
|
|
177
|
+
commit('SET_CLIPBOARD', clipboard);
|
|
178
|
+
// Save to localStorage and server
|
|
179
|
+
ClipboardManager.saveToLocalStorage(state.clipboard);
|
|
180
|
+
ClipboardManager.saveToServer(state.clipboard);
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Removes an item from the clipboard.
|
|
185
|
+
* Updates localStorage and the server.
|
|
186
|
+
* @param {Object} context - The Vuex context.
|
|
187
|
+
* @param {any} item - The item to remove.
|
|
188
|
+
*/
|
|
189
|
+
removeFromClipboard({ commit, state }, item) {
|
|
190
|
+
commit('REMOVE_FROM_CLIPBOARD', item);
|
|
191
|
+
// Save to localStorage and server
|
|
192
|
+
ClipboardManager.saveToLocalStorage(state.clipboard);
|
|
193
|
+
ClipboardManager.saveToServer(state.clipboard);
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Clears all items from the clipboard.
|
|
198
|
+
* Updates localStorage and the server.
|
|
199
|
+
* @param {Object} context - The Vuex context.
|
|
200
|
+
*/
|
|
201
|
+
clearClipboard({ commit, state }) {
|
|
202
|
+
commit('CLEAR_CLIPBOARD');
|
|
203
|
+
// Save to localStorage and server
|
|
204
|
+
ClipboardManager.saveToLocalStorage(state.clipboard);
|
|
205
|
+
ClipboardManager.saveToServer(state.clipboard);
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
export default clipboardModule;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import ClipboardButton from '../components/ClipboardButton.vue';
|
|
2
|
+
import { within, userEvent, expect } from "@storybook/test";
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'Components/ClipboardButton',
|
|
6
|
+
tags: ["autodocs"],
|
|
7
|
+
component: ClipboardButton,
|
|
8
|
+
argTypes: {
|
|
9
|
+
isInClipboard: { control: 'boolean' },
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const Template = (args) => ({
|
|
14
|
+
components: { ClipboardButton },
|
|
15
|
+
setup() {
|
|
16
|
+
return { args };
|
|
17
|
+
},
|
|
18
|
+
template: '<ClipboardButton v-bind="args" @addToClipboard="args.addToClipboard" @removeFromClipboard="args.removeFromClipboard"/>',
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Story for when the item is in the clipboard
|
|
22
|
+
export const InClipboard = Template.bind({});
|
|
23
|
+
InClipboard.args = {
|
|
24
|
+
isInClipboard: true,
|
|
25
|
+
index: 1,
|
|
26
|
+
addTitle: 'Add to clipboard',
|
|
27
|
+
removeTitle: 'Remove from clipboard',
|
|
28
|
+
addToClipboard: () => {},
|
|
29
|
+
removeFromClipboard: () => {},
|
|
30
|
+
};
|
|
31
|
+
InClipboard.play = async ({ canvasElement }) => {
|
|
32
|
+
const canvas = within(canvasElement);
|
|
33
|
+
|
|
34
|
+
// Expect the "Remove from clipboard" button to be rendered
|
|
35
|
+
const removeButton = await canvas.getByRole('button', { name: /Remove from clipboard/i });
|
|
36
|
+
expect(removeButton).toBeInTheDocument();
|
|
37
|
+
|
|
38
|
+
// Simulate a click on the remove button
|
|
39
|
+
await userEvent.click(removeButton);
|
|
40
|
+
|
|
41
|
+
// Ensure that the button remains visible after interaction
|
|
42
|
+
expect(removeButton).toBeVisible();
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Story for when the item is not in the clipboard
|
|
46
|
+
export const NotInClipboard = Template.bind({});
|
|
47
|
+
NotInClipboard.args = {
|
|
48
|
+
isInClipboard: false,
|
|
49
|
+
index: 1,
|
|
50
|
+
addToClipboard: () => {},
|
|
51
|
+
removeFromClipboard: () => {},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
NotInClipboard.play = async ({ canvasElement }) => {
|
|
55
|
+
const canvas = within(canvasElement);
|
|
56
|
+
|
|
57
|
+
// Expect the "Add to clipboard" button to be rendered
|
|
58
|
+
const addButton = await canvas.getByRole('button', { name: /Add to clipboard/i });
|
|
59
|
+
expect(addButton).toBeInTheDocument();
|
|
60
|
+
|
|
61
|
+
// Simulate a click on the add button
|
|
62
|
+
await userEvent.click(addButton);
|
|
63
|
+
|
|
64
|
+
// Ensure that the button remains visible after interaction
|
|
65
|
+
expect(addButton).toBeVisible();
|
|
66
|
+
};
|
|
@@ -17,6 +17,7 @@ export default {
|
|
|
17
17
|
@addPage="onAddPage"
|
|
18
18
|
@clickPage="onClick"
|
|
19
19
|
@seeAllPages="onSeeAllPages"
|
|
20
|
+
@clipboard="onClipboard"
|
|
20
21
|
/>
|
|
21
22
|
`,
|
|
22
23
|
data() {
|
|
@@ -31,7 +32,10 @@ export default {
|
|
|
31
32
|
},
|
|
32
33
|
onClick(index) {
|
|
33
34
|
console.log("Click page item:", index);
|
|
34
|
-
}
|
|
35
|
+
},
|
|
36
|
+
onClipboard() {
|
|
37
|
+
console.log("Open clipboard");
|
|
38
|
+
},
|
|
35
39
|
}
|
|
36
40
|
})
|
|
37
41
|
};
|
|
@@ -104,8 +108,8 @@ export const ClickInCreatePage = {
|
|
|
104
108
|
await selectorAddPage.click(selectorAddPage);
|
|
105
109
|
}
|
|
106
110
|
};
|
|
107
|
-
// Open the
|
|
108
|
-
export const
|
|
111
|
+
// Open the Clipboard
|
|
112
|
+
export const ClickInClipboard = {
|
|
109
113
|
args: {
|
|
110
114
|
data: [{ name: "Page 1" }]
|
|
111
115
|
},
|
|
@@ -114,19 +118,18 @@ export const ClickInSeeAllPages = {
|
|
|
114
118
|
const selector = canvasElement.querySelector(
|
|
115
119
|
"[data-test=page-dropdown] button"
|
|
116
120
|
);
|
|
117
|
-
const
|
|
118
|
-
"[data-test=
|
|
121
|
+
const clipboardOption = canvasElement.querySelector(
|
|
122
|
+
"[data-test=clipboard]"
|
|
119
123
|
);
|
|
120
|
-
console.log(selectorAddPage);
|
|
121
124
|
await selector.click(selector);
|
|
122
125
|
await waitFor(
|
|
123
126
|
() => {
|
|
124
127
|
expect(canvas.getByTestId("page-dropdown")).toContainHTML(
|
|
125
|
-
"
|
|
128
|
+
"Clipboard"
|
|
126
129
|
);
|
|
127
130
|
},
|
|
128
131
|
{ timeout: 1000 }
|
|
129
132
|
);
|
|
130
|
-
await
|
|
133
|
+
await clipboardOption.click(clipboardOption);
|
|
131
134
|
}
|
|
132
135
|
};
|