quasar-ui-danx 0.4.2 → 0.4.3

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 (75) hide show
  1. package/dist/danx.es.js +7127 -6615
  2. package/dist/danx.es.js.map +1 -1
  3. package/dist/danx.umd.js +11 -5
  4. package/dist/danx.umd.js.map +1 -1
  5. package/dist/style.css +1 -1
  6. package/package.json +3 -1
  7. package/src/components/ActionTable/ActionTable.vue +28 -41
  8. package/src/components/ActionTable/Columns/ActionTableColumn.vue +19 -18
  9. package/src/components/ActionTable/Filters/CollapsableFiltersSidebar.vue +6 -6
  10. package/src/components/ActionTable/Filters/{FilterFieldList.vue → FilterList.vue} +26 -26
  11. package/src/components/ActionTable/Filters/FilterableField.vue +28 -31
  12. package/src/components/ActionTable/Filters/index.ts +2 -2
  13. package/src/components/ActionTable/Form/Fields/EditOnClickTextField.vue +71 -0
  14. package/src/components/ActionTable/Form/Fields/FieldLabel.vue +8 -13
  15. package/src/components/ActionTable/Form/Fields/MultiFileField.vue +48 -44
  16. package/src/components/ActionTable/Form/Fields/SelectField.vue +24 -38
  17. package/src/components/ActionTable/Form/Fields/SelectWithChildrenField.vue +28 -33
  18. package/src/components/ActionTable/Form/Fields/SingleFileField.vue +15 -15
  19. package/src/components/ActionTable/Form/Fields/SliderNumberField.vue +45 -0
  20. package/src/components/ActionTable/Form/Fields/TextField.vue +47 -66
  21. package/src/components/ActionTable/Form/Fields/index.ts +2 -0
  22. package/src/components/ActionTable/Form/RenderedForm.vue +50 -9
  23. package/src/components/ActionTable/Form/Utilities/MaxLengthCounter.vue +17 -0
  24. package/src/components/ActionTable/Form/Utilities/index.ts +1 -0
  25. package/src/components/ActionTable/Form/index.ts +1 -0
  26. package/src/components/ActionTable/Layouts/ActionTableLayout.vue +16 -15
  27. package/src/components/ActionTable/Toolbars/ActionToolbar.vue +6 -6
  28. package/src/components/ActionTable/listControls.ts +104 -166
  29. package/src/components/ActionTable/listHelpers.ts +2 -3
  30. package/src/components/ActionTable/tableColumns.ts +3 -27
  31. package/src/components/AuditHistory/AuditHistoryItemValue.vue +26 -26
  32. package/src/components/PanelsDrawer/PanelsDrawer.vue +17 -4
  33. package/src/components/PanelsDrawer/PanelsDrawerPanels.vue +6 -11
  34. package/src/components/PanelsDrawer/PanelsDrawerTabs.vue +20 -20
  35. package/src/components/Utility/Dialogs/ConfirmActionDialog.vue +39 -0
  36. package/src/components/Utility/Dialogs/ConfirmDialog.vue +10 -24
  37. package/src/components/Utility/Dialogs/DialogLayout.vue +10 -28
  38. package/src/components/Utility/Dialogs/FullscreenCarouselDialog.vue +42 -36
  39. package/src/components/Utility/Dialogs/index.ts +1 -0
  40. package/src/components/Utility/Files/FilePreview.vue +76 -73
  41. package/src/components/Utility/Layouts/ContentDrawer.vue +24 -31
  42. package/src/components/Utility/Tools/ActionVnode.vue +3 -3
  43. package/src/components/Utility/Tools/RenderVnode.vue +1 -1
  44. package/src/components/Utility/Transitions/MaxHeightTransition.vue +26 -0
  45. package/src/components/Utility/Transitions/index.ts +1 -0
  46. package/src/config/index.ts +36 -31
  47. package/src/helpers/FileUpload.ts +295 -297
  48. package/src/helpers/FlashMessages.ts +80 -71
  49. package/src/helpers/actions.ts +102 -82
  50. package/src/helpers/download.ts +189 -189
  51. package/src/helpers/downloadPdf.ts +55 -52
  52. package/src/helpers/formats.ts +151 -109
  53. package/src/helpers/index.ts +2 -0
  54. package/src/helpers/multiFileUpload.ts +72 -58
  55. package/src/helpers/objectStore.ts +52 -0
  56. package/src/helpers/request.ts +70 -51
  57. package/src/helpers/routes.ts +29 -0
  58. package/src/helpers/storage.ts +7 -3
  59. package/src/helpers/utils.ts +47 -29
  60. package/src/styles/quasar-reset.scss +16 -1
  61. package/src/styles/themes/danx/dialogs.scss +4 -0
  62. package/src/types/actions.d.ts +43 -0
  63. package/src/types/config.d.ts +15 -0
  64. package/src/types/controls.d.ts +99 -0
  65. package/src/types/dialogs.d.ts +32 -0
  66. package/src/types/fields.d.ts +20 -0
  67. package/src/types/files.d.ts +54 -0
  68. package/src/types/formats.d.ts +4 -0
  69. package/src/{components/ActionTable/Form/form.d.ts → types/forms.d.ts} +6 -0
  70. package/src/types/index.d.ts +12 -0
  71. package/src/types/requests.d.ts +13 -0
  72. package/src/types/shared.d.ts +15 -0
  73. package/src/types/tables.d.ts +27 -0
  74. package/types/index.d.ts +1 -1
  75. /package/src/components/ActionTable/Filters/{FilterFieldItem.vue → FilterItem.vue} +0 -0
@@ -1,16 +1,20 @@
1
1
  import { DateTime, IANAZone } from "luxon";
2
+ import { ActionTargetItem, fDateOptions } from "../types";
3
+ import { isJSON } from "./utils";
2
4
 
3
5
  const SERVER_TZ = new IANAZone("America/Chicago");
4
6
 
7
+ export { DateTime, SERVER_TZ };
8
+
5
9
  /**
6
10
  * Converts a date string from the server's time zone to the user's time zone.
7
11
  * @param {String} dateTimeString
8
12
  * @returns {DateTime}
9
13
  */
10
- export function localizedDateTime(dateTimeString) {
11
- dateTimeString = dateTimeString?.replace("T", " ");
12
- // noinspection JSCheckFunctionSignatures
13
- return DateTime.fromSQL(dateTimeString, { zone: SERVER_TZ }).setZone("local");
14
+ export function localizedDateTime(dateTimeString: string) {
15
+ dateTimeString = dateTimeString?.replace("T", " ");
16
+ // noinspection JSCheckFunctionSignatures
17
+ return DateTime.fromSQL(dateTimeString, { zone: SERVER_TZ }).setZone("local");
14
18
  }
15
19
 
16
20
  /**
@@ -18,22 +22,22 @@ export function localizedDateTime(dateTimeString) {
18
22
  * @param dateTimeString
19
23
  * @returns {DateTime}
20
24
  */
21
- export function remoteDateTime(dateTimeString) {
22
- dateTimeString = dateTimeString?.replace("T", " ");
23
- // noinspection JSCheckFunctionSignatures
24
- return DateTime.fromSQL(dateTimeString, { zone: "local" }).setZone(SERVER_TZ);
25
+ export function remoteDateTime(dateTimeString: string) {
26
+ dateTimeString = dateTimeString?.replace("T", " ");
27
+ // noinspection JSCheckFunctionSignatures
28
+ return DateTime.fromSQL(dateTimeString, { zone: "local" }).setZone(SERVER_TZ);
25
29
  }
26
30
 
27
31
  /**
28
32
  * @param {DateTime|String} dateTime
29
33
  * @returns {DateTime|*}
30
34
  */
31
- export function parseDateTime(dateTime) {
32
- if (typeof dateTime === "string") {
33
- dateTime = dateTime.replace("T", " ").replace(/\//g, "-");
34
- return DateTime.fromSQL(dateTime);
35
- }
36
- return dateTime || DateTime.fromSQL("0000-00-00 00:00:00");
35
+ export function parseDateTime(dateTime: string | DateTime) {
36
+ if (typeof dateTime === "string") {
37
+ dateTime = dateTime.replace("T", " ").replace(/\//g, "-");
38
+ return DateTime.fromSQL(dateTime);
39
+ }
40
+ return dateTime || DateTime.fromSQL("0000-00-00 00:00:00");
37
41
  }
38
42
 
39
43
  /**
@@ -42,8 +46,8 @@ export function parseDateTime(dateTime) {
42
46
  * @param format
43
47
  * @returns {DateTime}
44
48
  */
45
- export function parseQDate(date, format = "yyyy/MM/dd") {
46
- return DateTime.fromFormat(date, format);
49
+ export function parseQDate(date: string, format = "yyyy/MM/dd") {
50
+ return DateTime.fromFormat(date, format);
47
51
  }
48
52
 
49
53
  /**
@@ -52,8 +56,8 @@ export function parseQDate(date, format = "yyyy/MM/dd") {
52
56
  * @param format
53
57
  * @returns {DateTime}
54
58
  */
55
- export function parseQDateTime(date, format = "yyyy/MM/dd HH:mm:ss") {
56
- return DateTime.fromFormat(date, format);
59
+ export function parseQDateTime(date: string, format = "yyyy/MM/dd HH:mm:ss") {
60
+ return DateTime.fromFormat(date, format);
57
61
  }
58
62
 
59
63
  /**
@@ -61,8 +65,8 @@ export function parseQDateTime(date, format = "yyyy/MM/dd HH:mm:ss") {
61
65
  * @param date
62
66
  * @returns {string}
63
67
  */
64
- export function fQDate(date) {
65
- return fDate(date, { format: "yyyy/MM/dd" });
68
+ export function fQDate(date: string) {
69
+ return fDate(date, { format: "yyyy/MM/dd" });
66
70
  }
67
71
 
68
72
  /**
@@ -71,8 +75,8 @@ export function fQDate(date) {
71
75
  * @param options
72
76
  * @returns {string}
73
77
  */
74
- export function fLocalizedDateTime(dateTimeString, options = {}) {
75
- return fDateTime(localizedDateTime(dateTimeString), options);
78
+ export function fLocalizedDateTime(dateTimeString: string, options = {}) {
79
+ return fDateTime(localizedDateTime(dateTimeString), options);
76
80
  }
77
81
 
78
82
  /**
@@ -84,11 +88,11 @@ export function fLocalizedDateTime(dateTimeString, options = {}) {
84
88
  * @returns {string}
85
89
  */
86
90
  export function fDateTime(
87
- dateTime = null,
88
- { format = "M/d/yy h:mma", empty = "- -" } = {}
91
+ dateTime: string | DateTime | null = null,
92
+ { format = "M/d/yy h:mma", empty = "- -" }: fDateOptions = {}
89
93
  ) {
90
- const formatted = (dateTime ? parseDateTime(dateTime) : DateTime.now()).toFormat(format).toLowerCase();
91
- return formatted === "invalid datetime" ? empty : formatted;
94
+ const formatted = (dateTime ? parseDateTime(dateTime) : DateTime.now()).toFormat(format).toLowerCase();
95
+ return formatted === "invalid datetime" ? empty : formatted;
92
96
  }
93
97
 
94
98
  /**
@@ -96,8 +100,8 @@ export function fDateTime(
96
100
  * @param dateTime
97
101
  * @returns {string}
98
102
  */
99
- export function dbDateTime(dateTime = null) {
100
- return fDateTime(dateTime, { format: "yyyy-MM-dd HH:mm:ss", empty: null });
103
+ export function dbDateTime(dateTime: string | DateTime | null = null) {
104
+ return fDateTime(dateTime, { format: "yyyy-MM-dd HH:mm:ss", empty: undefined });
101
105
  }
102
106
 
103
107
  /**
@@ -107,9 +111,9 @@ export function dbDateTime(dateTime = null) {
107
111
  * @param format
108
112
  * @returns {string}
109
113
  */
110
- export function fDate(dateTime, { empty = "--", format = "M/d/yy" } = {}) {
111
- const formatted = parseDateTime(dateTime).toFormat(format);
112
- return ["Invalid DateTime", "invalid datetime"].includes(formatted) ? empty : formatted;
114
+ export function fDate(dateTime: string, { empty = "--", format = "M/d/yy" }: fDateOptions = {}) {
115
+ const formatted = parseDateTime(dateTime).toFormat(format || "M/d/yy");
116
+ return ["Invalid DateTime", "invalid datetime"].includes(formatted) ? empty : formatted;
113
117
  }
114
118
 
115
119
  /**
@@ -118,22 +122,33 @@ export function fDate(dateTime, { empty = "--", format = "M/d/yy" } = {}) {
118
122
  * @param second
119
123
  * @returns {string}
120
124
  */
121
- export function fSecondsToTime(second) {
122
- const time = DateTime.now().setZone("UTC").startOf("year").set({ second });
123
- const hours = Math.floor(second / 3600);
124
- return (hours ? hours + ":" : "") + time.toFormat("mm:ss");
125
+ export function fSecondsToTime(second: number) {
126
+ const time = DateTime.now().setZone("UTC").startOf("year").set({ second });
127
+ const hours = Math.floor(second / 3600);
128
+ return (hours ? hours + ":" : "") + time.toFormat("mm:ss");
129
+ }
130
+
131
+ export function fElapsedTime(start: string, end?: string) {
132
+ const endDateTime = end ? parseDateTime(end) : DateTime.now();
133
+ const diff = endDateTime.diff(parseDateTime(start), ["hours", "minutes", "seconds"]);
134
+ if (!diff.isValid) {
135
+ return "-";
136
+ }
137
+ const hours = Math.floor(diff.hours);
138
+ const minutes = Math.floor(diff.minutes);
139
+ const seconds = Math.floor(diff.seconds);
140
+ return `${hours ? hours + "h " : ""}${minutes ? minutes + "m " : ""}${seconds}s`;
125
141
  }
126
142
 
127
143
  /**
128
144
  * Formats an amount into USD currency format
129
- * @param amount
130
- * @returns {string}
131
145
  */
132
- export function fCurrency(amount) {
133
- return new Intl.NumberFormat("en-US", {
134
- style: "currency",
135
- currency: "USD"
136
- }).format(amount);
146
+ export function fCurrency(amount: number, options?: object) {
147
+ return new Intl.NumberFormat("en-US", {
148
+ style: "currency",
149
+ currency: "USD",
150
+ ...options
151
+ }).format(amount);
137
152
  }
138
153
 
139
154
  /**
@@ -142,8 +157,8 @@ export function fCurrency(amount) {
142
157
  * @param options
143
158
  * @returns {string}
144
159
  */
145
- export function fNumber(number, options = {}) {
146
- return new Intl.NumberFormat("en-US", options).format(number);
160
+ export function fNumber(number: number, options = {}) {
161
+ return new Intl.NumberFormat("en-US", options).format(number);
147
162
  }
148
163
 
149
164
  /**
@@ -152,24 +167,24 @@ export function fNumber(number, options = {}) {
152
167
  * @param maxLength
153
168
  * @returns {string|*}
154
169
  */
155
- export function centerTruncate(str, maxLength) {
156
- if (str.length > maxLength) {
157
- const frontCharCount = Math.floor((maxLength - 3) / 2);
158
- const backCharCount = maxLength - frontCharCount - 3;
159
- return (
160
- str.substring(0, frontCharCount) +
161
- "..." +
162
- str.substring(str.length - backCharCount)
163
- );
164
- } else {
165
- return str;
166
- }
170
+ export function centerTruncate(str: string, maxLength: number) {
171
+ if (str.length > maxLength) {
172
+ const frontCharCount = Math.floor((maxLength - 3) / 2);
173
+ const backCharCount = maxLength - frontCharCount - 3;
174
+ return (
175
+ str.substring(0, frontCharCount) +
176
+ "..." +
177
+ str.substring(str.length - backCharCount)
178
+ );
179
+ } else {
180
+ return str;
181
+ }
167
182
  }
168
183
 
169
184
  interface FPercentOptions {
170
- multiplier?: number,
171
- maximumFractionDigits?: number,
172
- NaN?: string
185
+ multiplier?: number,
186
+ maximumFractionDigits?: number,
187
+ NaN?: string
173
188
  }
174
189
 
175
190
  /**
@@ -179,54 +194,81 @@ interface FPercentOptions {
179
194
  * @returns {string}
180
195
  */
181
196
  export function fPercent(num: string | number, options: FPercentOptions = {}) {
182
- options = { multiplier: 100, maximumFractionDigits: 1, NaN: "N/A", ...options };
183
-
184
- num = parseFloat("" + num);
185
-
186
- if (isNaN(num)) {
187
- return options.NaN;
188
- }
189
-
190
- return fNumber(num * (options.multiplier || 100), options) + "%";
191
- }
192
-
193
-
194
- export function fPhone(value) {
195
- if (!value || typeof value !== "string") {
196
- return value || "";
197
- }
198
-
199
- const input = value.replace(/\D/g, "").split("");
200
- let phone = "";
201
-
202
- const startsWithOne = input.length > 0 && input[0] === "1";
203
- const shift = startsWithOne ? 1 : 0;
204
-
205
- input.map((number, index) => {
206
- switch (index) {
207
- case shift:
208
- phone += "(";
209
- break;
210
- case shift + 3:
211
- phone += ") ";
212
- break;
213
- case shift + 6:
214
- phone += "-";
215
- break;
216
- case shift + 10:
217
- phone += " x";
218
- break;
219
- }
220
- if (index === 0 && number === "1") {
221
- phone += "+1 ";
222
- } else {
223
- phone += number;
224
- }
225
- });
226
-
227
- if (value === "+1 (") {
228
- return "";
229
- }
230
-
231
- return phone;
197
+ options = { multiplier: 100, maximumFractionDigits: 1, NaN: "N/A", ...options };
198
+
199
+ num = parseFloat("" + num);
200
+
201
+ if (isNaN(num)) {
202
+ return options.NaN;
203
+ }
204
+
205
+ return fNumber(num * (options.multiplier || 100), options) + "%";
206
+ }
207
+
208
+
209
+ export function fPhone(value: string | number) {
210
+ if (!value || typeof value !== "string") {
211
+ return value || "";
212
+ }
213
+
214
+ const input = value.replace(/\D/g, "").split("");
215
+ let phone = "";
216
+
217
+ const startsWithOne = input.length > 0 && input[0] === "1";
218
+ const shift = startsWithOne ? 1 : 0;
219
+
220
+ input.map((number, index) => {
221
+ switch (index) {
222
+ case shift:
223
+ phone += "(";
224
+ break;
225
+ case shift + 3:
226
+ phone += ") ";
227
+ break;
228
+ case shift + 6:
229
+ phone += "-";
230
+ break;
231
+ case shift + 10:
232
+ phone += " x";
233
+ break;
234
+ }
235
+ if (index === 0 && number === "1") {
236
+ phone += "+1 ";
237
+ } else {
238
+ phone += number;
239
+ }
240
+ });
241
+
242
+ if (value === "+1 (") {
243
+ return "";
244
+ }
245
+
246
+ return phone;
247
+ }
248
+
249
+ export function fNameOrCount(items: ActionTargetItem[] | ActionTargetItem, label: string) {
250
+ return Array.isArray(items) ? `${items?.length} ${label}` : `${items ? items.title || items.name || items.id : ""}`;
251
+ }
252
+
253
+ export function fJSON(string: string | object) {
254
+ if (!string) {
255
+ return string;
256
+ }
257
+
258
+ try {
259
+ if (typeof string === "object") {
260
+ return JSON.stringify(string, null, 2);
261
+ }
262
+ return JSON.stringify(JSON.parse(string), null, 2);
263
+ } catch (e) {
264
+ return string;
265
+ }
266
+ }
267
+
268
+ export function fMarkdownJSON(string: string | object): string {
269
+ if (isJSON(string)) {
270
+ return `\`\`\`json\n${fJSON(string)}\n\`\`\``;
271
+ }
272
+ // @ts-expect-error Guaranteed to only allow strings here using isJSON check
273
+ return string;
232
274
  }
@@ -10,7 +10,9 @@ export * from "./FlashMessages";
10
10
  export * from "./formats";
11
11
  export * from "./hotkeys";
12
12
  export * from "./multiFileUpload";
13
+ export * from "./objectStore";
13
14
  export * from "./request";
15
+ export * from "./routes";
14
16
  export * from "./singleFileUpload";
15
17
  export * from "./storage";
16
18
  export * from "./styles";
@@ -1,68 +1,82 @@
1
1
  import { Ref, ref } from "vue";
2
- import { FileUpload, FileUploadOptions, UploadedFile } from "./FileUpload";
2
+ import { FlashMessages } from "../helpers";
3
+ import {
4
+ FileUploadCompleteCallback,
5
+ FileUploadOptions,
6
+ OnFilesChangeCallback,
7
+ UploadedFile,
8
+ VoidCallback
9
+ } from "../types";
10
+ import { FileUpload } from "./FileUpload";
3
11
 
4
- export function useMultiFileUpload(options: FileUploadOptions) {
5
- const uploadedFiles: Ref<UploadedFile[]> = ref([]);
6
- const onCompleteCb: Ref<Function | null> = ref(null);
7
- const onFilesChangeCb: Ref<Function | null> = ref(null);
8
- const onFilesSelected = (e: any) => {
9
- uploadedFiles.value = [...uploadedFiles.value, ...e.target.files];
10
- new FileUpload(e.target.files, options)
11
- .onProgress(({ file }: { file: UploadedFile }) => {
12
- updateFileInList(file);
13
- })
14
- .onComplete(({ file, uploadedFile }: { file: UploadedFile, uploadedFile: UploadedFile }) => {
15
- updateFileInList(file, uploadedFile);
16
- })
17
- .onAllComplete(() => {
18
- onCompleteCb.value && onCompleteCb.value();
19
- onFilesChangeCb.value && onFilesChangeCb.value(uploadedFiles.value);
20
- })
21
- .upload();
22
- };
12
+ export function useMultiFileUpload(options?: FileUploadOptions) {
13
+ const uploadedFiles: Ref<UploadedFile[]> = ref([]);
14
+ const onCompleteCb: Ref<FileUploadCompleteCallback | null> = ref(null);
15
+ const onFilesChangeCb: Ref<OnFilesChangeCallback | null> = ref(null);
16
+ const onFilesSelected = (e: any) => {
17
+ uploadedFiles.value = [...uploadedFiles.value, ...e.target.files];
18
+ new FileUpload(e.target.files, options)
19
+ .onProgress(({ file }: { file: UploadedFile }) => {
20
+ updateFileInList(file);
21
+ })
22
+ .onComplete(({ file, uploadedFile }) => {
23
+ file && updateFileInList(file, uploadedFile);
24
+ })
25
+ .onError(({ file }: { file: UploadedFile }) => {
26
+ FlashMessages.error(`Failed to upload ${file.name}`);
27
+ })
28
+ .onAllComplete(() => {
29
+ onCompleteCb.value && onCompleteCb.value({
30
+ file: uploadedFiles.value[0],
31
+ uploadedFile: uploadedFiles.value[0]
32
+ });
33
+ onFilesChangeCb.value && onFilesChangeCb.value(uploadedFiles.value);
34
+ })
35
+ .upload();
36
+ };
23
37
 
24
- function updateFileInList(file: UploadedFile, replace: UploadedFile | null = null) {
25
- const index = uploadedFiles.value.findIndex(f => f.id === file.id);
26
- if (index !== -1) {
27
- uploadedFiles.value.splice(index, 1, replace || file);
28
- }
29
- onFilesChangeCb.value && onFilesChangeCb.value(uploadedFiles.value);
30
- }
38
+ function updateFileInList(file: UploadedFile, replace: UploadedFile | null = null) {
39
+ const index = uploadedFiles.value.findIndex(f => f.id === file.id);
40
+ if (index !== -1) {
41
+ uploadedFiles.value.splice(index, 1, replace || file);
42
+ }
43
+ onFilesChangeCb.value && onFilesChangeCb.value(uploadedFiles.value);
44
+ }
31
45
 
32
- const onDrop = (e: InputEvent) => {
33
- onFilesSelected({ target: { files: e.dataTransfer?.files } });
34
- };
46
+ const onDrop = (e: InputEvent) => {
47
+ onFilesSelected({ target: { files: e.dataTransfer?.files } });
48
+ };
35
49
 
36
- const onFilesChange = (cb: Function) => {
37
- onFilesChangeCb.value = cb;
38
- };
50
+ const onFilesChange = (cb: OnFilesChangeCallback) => {
51
+ onFilesChangeCb.value = cb;
52
+ };
39
53
 
40
- const onComplete = (cb: Function) => {
41
- onCompleteCb.value = cb;
42
- };
54
+ const onComplete = (cb: VoidCallback) => {
55
+ onCompleteCb.value = cb;
56
+ };
43
57
 
44
- const clearUploadedFiles = () => {
45
- uploadedFiles.value = [];
46
- onFilesChangeCb.value && onFilesChangeCb.value(uploadedFiles.value);
47
- onCompleteCb.value && onCompleteCb.value();
48
- };
58
+ const clearUploadedFiles = () => {
59
+ uploadedFiles.value = [];
60
+ onFilesChangeCb.value && onFilesChangeCb.value(uploadedFiles.value);
61
+ onCompleteCb.value && onCompleteCb.value({ file: null, uploadedFile: null });
62
+ };
49
63
 
50
- const onRemove = (file: UploadedFile) => {
51
- const index = uploadedFiles.value.findIndex(f => f.id === file.id);
52
- if (index !== -1) {
53
- uploadedFiles.value.splice(index, 1);
54
- }
55
- onFilesChangeCb.value && onFilesChangeCb.value(uploadedFiles.value);
56
- onCompleteCb.value && onCompleteCb.value();
57
- };
64
+ const onRemove = (file: UploadedFile) => {
65
+ const index = uploadedFiles.value.findIndex(f => f.id === file.id);
66
+ if (index !== -1) {
67
+ uploadedFiles.value.splice(index, 1);
68
+ }
69
+ onFilesChangeCb.value && onFilesChangeCb.value(uploadedFiles.value);
70
+ onCompleteCb.value && onCompleteCb.value({ file, uploadedFile: file });
71
+ };
58
72
 
59
- return {
60
- clearUploadedFiles,
61
- onRemove,
62
- onComplete,
63
- onFilesChange,
64
- onDrop,
65
- onFilesSelected,
66
- uploadedFiles
67
- };
73
+ return {
74
+ clearUploadedFiles,
75
+ onRemove,
76
+ onComplete,
77
+ onFilesChange,
78
+ onDrop,
79
+ onFilesSelected,
80
+ uploadedFiles
81
+ };
68
82
  }
@@ -0,0 +1,52 @@
1
+ import { reactive, UnwrapNestedRefs } from "vue";
2
+ import { TypedObject } from "../types";
3
+
4
+ const store = new Map<string, any>();
5
+
6
+ /**
7
+ * Store an object in the object store via type + id
8
+ * Returns the stored object that should be used instead of the passed object as the returned object is shared across the system
9
+ *
10
+ * @param {TypedObject} newObject
11
+ * @returns {TypedObject}
12
+ */
13
+ export function storeObject<T extends TypedObject>(newObject: T): UnwrapNestedRefs<T> {
14
+ const id = newObject.id || newObject.name;
15
+ const type = newObject.__type;
16
+ if (!id || !type) return reactive(newObject);
17
+
18
+ const objectKey = `${type}:${id}`;
19
+
20
+ const oldObject: UnwrapNestedRefs<T> | undefined = store.get(objectKey);
21
+
22
+ // Apply all properties from newObject to oldObject then store and return the updated object
23
+ if (oldObject) {
24
+ const oldTimestamp = oldObject.__timestamp || oldObject.updated_at;
25
+ const newTimestamp = newObject.__timestamp || newObject.updated_at;
26
+ // If the old object is newer, do not store the new object, just return the old
27
+ if (oldTimestamp && newTimestamp && newTimestamp < oldTimestamp) {
28
+ return oldObject;
29
+ }
30
+ }
31
+
32
+ // Recursively store all the children of the object as well
33
+ for (const key of Object.keys(newObject)) {
34
+ const value = newObject[key];
35
+ if (Array.isArray(value) && value.length > 0 && typeof value[0] === "object") {
36
+ for (const index in value) {
37
+ newObject[key][index] = storeObject(value[index]);
38
+ }
39
+ }
40
+ }
41
+
42
+ // Update the old object with the new object properties
43
+ if (oldObject) {
44
+ // If the new object is newer, apply all properties from the new object to the old object
45
+ Object.assign(oldObject, newObject);
46
+ return oldObject;
47
+ }
48
+
49
+ const reactiveObject = reactive(newObject);
50
+ store.set(objectKey, reactiveObject);
51
+ return reactiveObject;
52
+ }