@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.
Files changed (48) hide show
  1. package/dist/vue-form-builder.css +1 -1
  2. package/dist/vue-form-builder.es.js +9091 -7132
  3. package/dist/vue-form-builder.es.js.map +1 -1
  4. package/dist/vue-form-builder.umd.js +53 -53
  5. package/dist/vue-form-builder.umd.js.map +1 -1
  6. package/package.json +2 -1
  7. package/src/App.vue +14 -2
  8. package/src/DataProvider.js +42 -1
  9. package/src/VariableDataTypeProperties.js +1 -1
  10. package/src/components/ClipboardButton.vue +77 -0
  11. package/src/components/CssIcon.vue +21 -0
  12. package/src/components/ScreenTemplateCard.vue +257 -0
  13. package/src/components/ScreenTemplates.vue +216 -0
  14. package/src/components/ScreenToolbar.vue +24 -2
  15. package/src/components/SelectUserGroup.vue +274 -0
  16. package/src/components/TabsBar.vue +47 -1
  17. package/src/components/accordions.js +7 -1
  18. package/src/components/editor/loop.vue +22 -1
  19. package/src/components/editor/multi-column.vue +22 -2
  20. package/src/components/editor/pagesDropdown.vue +20 -2
  21. package/src/components/index.js +7 -1
  22. package/src/components/inspector/collection-data-source.vue +200 -0
  23. package/src/components/inspector/collection-display-mode.vue +87 -0
  24. package/src/components/inspector/collection-records-list.vue +156 -0
  25. package/src/components/inspector/column-setup.vue +123 -7
  26. package/src/components/inspector/encrypted-config.vue +78 -0
  27. package/src/components/inspector/index.js +4 -0
  28. package/src/components/inspector/page-select.vue +1 -0
  29. package/src/components/renderer/file-upload.vue +136 -3
  30. package/src/components/renderer/form-collection-record-control.vue +248 -0
  31. package/src/components/renderer/form-collection-view-control.vue +236 -0
  32. package/src/components/renderer/form-masked-input.vue +194 -9
  33. package/src/components/renderer/form-record-list.vue +271 -69
  34. package/src/components/renderer/index.js +2 -0
  35. package/src/components/screen-renderer.vue +2 -0
  36. package/src/components/task.vue +2 -1
  37. package/src/components/vue-form-builder.vue +156 -22
  38. package/src/components/vue-form-renderer.vue +10 -2
  39. package/src/form-builder-controls.js +168 -21
  40. package/src/global-properties.js +8 -0
  41. package/src/main.js +60 -1
  42. package/src/mixins/Clipboard.js +153 -0
  43. package/src/mixins/ScreenBase.js +7 -1
  44. package/src/mixins/index.js +1 -0
  45. package/src/store/modules/ClipboardManager.js +79 -0
  46. package/src/store/modules/clipboardModule.js +210 -0
  47. package/src/stories/ClipboardButton.stories.js +66 -0
  48. 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 See all Pages
108
- export const ClickInSeeAllPages = {
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 selectorAddPage = canvasElement.querySelector(
118
- "[data-test=see-all-pages]"
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
- "See all pages"
128
+ "Clipboard"
126
129
  );
127
130
  },
128
131
  { timeout: 1000 }
129
132
  );
130
- await selectorAddPage.click(selectorAddPage);
133
+ await clipboardOption.click(clipboardOption);
131
134
  }
132
135
  };