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.
- package/dist/danx.es.js +7127 -6615
- package/dist/danx.es.js.map +1 -1
- package/dist/danx.umd.js +11 -5
- package/dist/danx.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +3 -1
- package/src/components/ActionTable/ActionTable.vue +28 -41
- package/src/components/ActionTable/Columns/ActionTableColumn.vue +19 -18
- package/src/components/ActionTable/Filters/CollapsableFiltersSidebar.vue +6 -6
- package/src/components/ActionTable/Filters/{FilterFieldList.vue → FilterList.vue} +26 -26
- package/src/components/ActionTable/Filters/FilterableField.vue +28 -31
- package/src/components/ActionTable/Filters/index.ts +2 -2
- package/src/components/ActionTable/Form/Fields/EditOnClickTextField.vue +71 -0
- package/src/components/ActionTable/Form/Fields/FieldLabel.vue +8 -13
- package/src/components/ActionTable/Form/Fields/MultiFileField.vue +48 -44
- package/src/components/ActionTable/Form/Fields/SelectField.vue +24 -38
- package/src/components/ActionTable/Form/Fields/SelectWithChildrenField.vue +28 -33
- package/src/components/ActionTable/Form/Fields/SingleFileField.vue +15 -15
- package/src/components/ActionTable/Form/Fields/SliderNumberField.vue +45 -0
- package/src/components/ActionTable/Form/Fields/TextField.vue +47 -66
- package/src/components/ActionTable/Form/Fields/index.ts +2 -0
- package/src/components/ActionTable/Form/RenderedForm.vue +50 -9
- package/src/components/ActionTable/Form/Utilities/MaxLengthCounter.vue +17 -0
- package/src/components/ActionTable/Form/Utilities/index.ts +1 -0
- package/src/components/ActionTable/Form/index.ts +1 -0
- package/src/components/ActionTable/Layouts/ActionTableLayout.vue +16 -15
- package/src/components/ActionTable/Toolbars/ActionToolbar.vue +6 -6
- package/src/components/ActionTable/listControls.ts +104 -166
- package/src/components/ActionTable/listHelpers.ts +2 -3
- package/src/components/ActionTable/tableColumns.ts +3 -27
- package/src/components/AuditHistory/AuditHistoryItemValue.vue +26 -26
- package/src/components/PanelsDrawer/PanelsDrawer.vue +17 -4
- package/src/components/PanelsDrawer/PanelsDrawerPanels.vue +6 -11
- package/src/components/PanelsDrawer/PanelsDrawerTabs.vue +20 -20
- package/src/components/Utility/Dialogs/ConfirmActionDialog.vue +39 -0
- package/src/components/Utility/Dialogs/ConfirmDialog.vue +10 -24
- package/src/components/Utility/Dialogs/DialogLayout.vue +10 -28
- package/src/components/Utility/Dialogs/FullscreenCarouselDialog.vue +42 -36
- package/src/components/Utility/Dialogs/index.ts +1 -0
- package/src/components/Utility/Files/FilePreview.vue +76 -73
- package/src/components/Utility/Layouts/ContentDrawer.vue +24 -31
- package/src/components/Utility/Tools/ActionVnode.vue +3 -3
- package/src/components/Utility/Tools/RenderVnode.vue +1 -1
- package/src/components/Utility/Transitions/MaxHeightTransition.vue +26 -0
- package/src/components/Utility/Transitions/index.ts +1 -0
- package/src/config/index.ts +36 -31
- package/src/helpers/FileUpload.ts +295 -297
- package/src/helpers/FlashMessages.ts +80 -71
- package/src/helpers/actions.ts +102 -82
- package/src/helpers/download.ts +189 -189
- package/src/helpers/downloadPdf.ts +55 -52
- package/src/helpers/formats.ts +151 -109
- package/src/helpers/index.ts +2 -0
- package/src/helpers/multiFileUpload.ts +72 -58
- package/src/helpers/objectStore.ts +52 -0
- package/src/helpers/request.ts +70 -51
- package/src/helpers/routes.ts +29 -0
- package/src/helpers/storage.ts +7 -3
- package/src/helpers/utils.ts +47 -29
- package/src/styles/quasar-reset.scss +16 -1
- package/src/styles/themes/danx/dialogs.scss +4 -0
- package/src/types/actions.d.ts +43 -0
- package/src/types/config.d.ts +15 -0
- package/src/types/controls.d.ts +99 -0
- package/src/types/dialogs.d.ts +32 -0
- package/src/types/fields.d.ts +20 -0
- package/src/types/files.d.ts +54 -0
- package/src/types/formats.d.ts +4 -0
- package/src/{components/ActionTable/Form/form.d.ts → types/forms.d.ts} +6 -0
- package/src/types/index.d.ts +12 -0
- package/src/types/requests.d.ts +13 -0
- package/src/types/shared.d.ts +15 -0
- package/src/types/tables.d.ts +27 -0
- package/types/index.d.ts +1 -1
- /package/src/components/ActionTable/Filters/{FilterFieldItem.vue → FilterItem.vue} +0 -0
package/src/helpers/formats.ts
CHANGED
@@ -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
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
88
|
-
|
91
|
+
dateTime: string | DateTime | null = null,
|
92
|
+
{ format = "M/d/yy h:mma", empty = "- -" }: fDateOptions = {}
|
89
93
|
) {
|
90
|
-
|
91
|
-
|
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
|
-
|
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
|
-
|
112
|
-
|
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
|
-
|
123
|
-
|
124
|
-
|
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
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
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
|
-
|
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
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
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
|
-
|
171
|
-
|
172
|
-
|
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
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
}
|
192
|
-
|
193
|
-
|
194
|
-
export function fPhone(value) {
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
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
|
}
|
package/src/helpers/index.ts
CHANGED
@@ -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 {
|
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
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
33
|
-
|
34
|
-
|
46
|
+
const onDrop = (e: InputEvent) => {
|
47
|
+
onFilesSelected({ target: { files: e.dataTransfer?.files } });
|
48
|
+
};
|
35
49
|
|
36
|
-
|
37
|
-
|
38
|
-
|
50
|
+
const onFilesChange = (cb: OnFilesChangeCallback) => {
|
51
|
+
onFilesChangeCb.value = cb;
|
52
|
+
};
|
39
53
|
|
40
|
-
|
41
|
-
|
42
|
-
|
54
|
+
const onComplete = (cb: VoidCallback) => {
|
55
|
+
onCompleteCb.value = cb;
|
56
|
+
};
|
43
57
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
+
}
|