Skip to content

Commit 28b4552

Browse files
committed
feat: upload events
1 parent fa440fb commit 28b4552

File tree

9 files changed

+92
-19
lines changed

9 files changed

+92
-19
lines changed

packages/pluggableWidgets/file-uploader-web/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66

77
## [Unreleased]
88

9+
### Added
10+
11+
- We added configuration options to execute actions after both successful and unsuccessful file uploads.
12+
913
## [2.3.0] - 2025-08-15
1014

1115
### Fixed

packages/pluggableWidgets/file-uploader-web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@mendix/file-uploader-web",
33
"widgetName": "FileUploader",
4-
"version": "2.3.0",
4+
"version": "2.4.0",
55
"description": "Upload files via drag-and-drop or file dialog. Supports multiple file uploads and image preview thumbnails.",
66
"copyright": "© Mendix Technology BV 2025. All rights reserved.",
77
"license": "Apache-2.0",

packages/pluggableWidgets/file-uploader-web/src/FileUploader.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,23 @@
195195
<caption>Object creation timeout</caption>
196196
<description>Consider uploads unsuccessful if the Action to create new files/images does not create new objects within the configured amount of seconds.</description>
197197
</property>
198+
<property key="onUploadSuccessFile" type="action" dataSource="associatedFiles">
199+
<caption>On upload success</caption>
200+
<description>The action to be called if file content uploaded successfully.</description>
201+
</property>
202+
<property key="onUploadSuccessImage" type="action" dataSource="associatedImages">
203+
<caption>On upload success</caption>
204+
<description>The action to be called if image content uploaded successfully.</description>
205+
</property>
206+
<property key="onUploadFailureFile" type="action" dataSource="associatedFiles">
207+
<caption>On upload failure</caption>
208+
<description>The action to be called if file content upload was not successful.</description>
209+
</property>
210+
211+
<property key="onUploadFailureImage" type="action" dataSource="associatedImages">
212+
<caption>On upload failure</caption>
213+
<description>The action to be called if image content upload was not successful.</description>
214+
</property>
198215
<property key="enableCustomButtons" type="boolean" defaultValue="false">
199216
<caption>Enable custom buttons</caption>
200217
<description />

packages/pluggableWidgets/file-uploader-web/src/package.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8" ?>
22
<package xmlns="http://www.mendix.com/package/1.0/">
3-
<clientModule name="FileUploader" version="2.3.0" xmlns="http://www.mendix.com/clientModule/1.0/">
3+
<clientModule name="FileUploader" version="2.4.0" xmlns="http://www.mendix.com/clientModule/1.0/">
44
<widgetFiles>
55
<widgetFile path="FileUploader.xml" />
66
</widgetFiles>

packages/pluggableWidgets/file-uploader-web/src/stores/FileStore.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,18 +102,30 @@ export class FileStore {
102102
this.fileStatus = "uploading";
103103
});
104104

105+
// create object
105106
try {
106-
// request object item
107107
this._objectItem = await this._rootStore.objectCreationHelper.request();
108+
} catch (_e: unknown) {
109+
runInAction(() => {
110+
this.fileStatus = "uploadingError";
111+
this._rootStore.objectCreationHelper.reportCreationFailure();
112+
});
113+
return;
114+
}
115+
116+
// upload content to object
117+
try {
108118
await saveFile(this._objectItem, this._file!);
109119
await this.fetchMxObject();
110120

111121
runInAction(() => {
112122
this.fileStatus = "done";
123+
this._rootStore.objectCreationHelper.reportUploadSuccess(this._objectItem!);
113124
});
114125
} catch (_e: unknown) {
115126
runInAction(() => {
116127
this.fileStatus = "uploadingError";
128+
this._rootStore.objectCreationHelper.reportUploadFailure(this._objectItem!);
117129
});
118130
}
119131
}

packages/pluggableWidgets/file-uploader-web/src/stores/FileUploaderStore.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DynamicValue, ListValue, ObjectItem } from "mendix";
1+
import { DynamicValue, ObjectItem } from "mendix";
22
import { FileUploaderContainerProps, UploadModeEnum } from "../../typings/FileUploaderProps";
33
import { action, computed, makeObservable, observable } from "mobx";
44
import { Big } from "big.js";
@@ -26,7 +26,6 @@ export class FileUploaderStore {
2626
_uploadMode: UploadModeEnum;
2727
_maxFileSizeMiB = 0;
2828
_maxFileSize = 0;
29-
_ds?: ListValue;
3029
_maxFilesPerUpload: DynamicValue<Big>;
3130

3231
errorMessage?: string = undefined;
@@ -90,19 +89,15 @@ export class FileUploaderStore {
9089
}
9190

9291
updateProps(props: FileUploaderContainerProps): void {
93-
if (props.uploadMode === "files") {
94-
this.objectCreationHelper.updateProps(props.createFileAction);
95-
this._ds = props.associatedFiles;
96-
} else {
97-
this.objectCreationHelper.updateProps(props.createImageAction);
98-
this._ds = props.associatedImages;
99-
}
92+
this.objectCreationHelper.updateProps(props);
10093

10194
// Update max files properties
10295
this._maxFilesPerUpload = props.maxFilesPerUpload;
10396

10497
this.translations.updateProps(props);
105-
this.updateProcessor.processUpdate(this._ds);
98+
this.updateProcessor.processUpdate(
99+
props.uploadMode === "files" ? props.associatedFiles : props.associatedImages
100+
);
106101
}
107102

108103
processExistingFileItem(item: ObjectItem): void {

packages/pluggableWidgets/file-uploader-web/src/utils/ObjectCreationHelper.ts

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
1-
import { ActionValue, ObjectItem } from "mendix";
1+
import { ActionValue, ListActionValue, ObjectItem } from "mendix";
2+
import { executeAction } from "@mendix/widget-plugin-platform/framework/execute-action";
3+
import { FileUploaderContainerProps } from "../../typings/FileUploaderProps";
4+
5+
type UpdateProps = Pick<
6+
FileUploaderContainerProps,
7+
| "uploadMode"
8+
| "createFileAction"
9+
| "createImageAction"
10+
| "onUploadFailureFile"
11+
| "onUploadSuccessFile"
12+
| "onUploadFailureImage"
13+
| "onUploadSuccessImage"
14+
>;
215

316
export class ObjectCreationHelper {
417
private objectCreationAction?: ActionValue;
18+
private onUploadFailure?: ListActionValue;
19+
private onUploadSuccess?: ListActionValue;
520
private requestingEnabled = false;
621
private currentWaiting: Array<[(v: ObjectItem) => void, (e: Error) => void]> = [];
722
private itemCreationTimer?: number = undefined;
@@ -25,8 +40,16 @@ export class ObjectCreationHelper {
2540
}
2641
}
2742

28-
updateProps(createAction?: ActionValue): void {
29-
this.objectCreationAction = createAction;
43+
updateProps(props: UpdateProps): void {
44+
if (props.uploadMode === "files") {
45+
this.objectCreationAction = props.createFileAction;
46+
this.onUploadFailure = props.onUploadFailureFile;
47+
this.onUploadSuccess = props.onUploadSuccessFile;
48+
} else {
49+
this.objectCreationAction = props.createImageAction;
50+
this.onUploadFailure = props.onUploadFailureImage;
51+
this.onUploadSuccess = props.onUploadSuccessImage;
52+
}
3053
}
3154

3255
request(): Promise<ObjectItem> {
@@ -55,6 +78,20 @@ export class ObjectCreationHelper {
5578
this.executeCreation();
5679
}
5780

81+
reportCreationFailure(): void {
82+
console.warn(`File object creation has failed.`);
83+
}
84+
85+
reportUploadFailure(item: ObjectItem): void {
86+
console.warn(`Uploading file content to ${item.id} has failed.`);
87+
executeAction(this.onUploadFailure?.get(item));
88+
}
89+
90+
reportUploadSuccess(item: ObjectItem): void {
91+
console.warn(`Uploading file content to ${item.id} has succeeded.`);
92+
executeAction(this.onUploadSuccess?.get(item));
93+
}
94+
5895
private executeCreation(): void {
5996
if (!this.requestingEnabled) {
6097
// we are not yet able to create objects, wait till next run

packages/pluggableWidgets/file-uploader-web/src/utils/__tests__/ObjectCreationHelper.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ describe("ObjectCreationHelper", () => {
66
jest.useFakeTimers();
77
const createAction = actionValue(true, false);
88
const helper = new ObjectCreationHelper("grid1", 10);
9-
helper.updateProps(createAction);
9+
helper.updateProps({ uploadMode: "files", createFileAction: createAction });
1010
helper.enable();
1111
const req1 = helper.request();
1212
const req2 = helper.request();
@@ -34,7 +34,7 @@ describe("ObjectCreationHelper", () => {
3434
jest.useFakeTimers();
3535
const helper = new ObjectCreationHelper("grid1", 10);
3636
const createAction = actionValue(true, false);
37-
helper.updateProps(createAction);
37+
helper.updateProps({ uploadMode: "files", createFileAction: createAction });
3838
helper.enable();
3939
const req1 = helper.request();
4040
const req2 = helper.request();
@@ -48,7 +48,7 @@ describe("ObjectCreationHelper", () => {
4848
jest.useFakeTimers();
4949
const helper = new ObjectCreationHelper("grid1", 10);
5050
const createAction = actionValue(true, false);
51-
helper.updateProps(createAction);
51+
helper.updateProps({ uploadMode: "files", createFileAction: createAction });
5252
const req1 = helper.request();
5353
const req2 = helper.request();
5454
jest.advanceTimersByTime(1000);

packages/pluggableWidgets/file-uploader-web/typings/FileUploaderProps.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ export interface FileUploaderContainerProps {
7676
removeSuccessMessage: DynamicValue<string>;
7777
removeErrorMessage: DynamicValue<string>;
7878
objectCreationTimeout: number;
79+
onUploadSuccessFile?: ListActionValue;
80+
onUploadSuccessImage?: ListActionValue;
81+
onUploadFailureFile?: ListActionValue;
82+
onUploadFailureImage?: ListActionValue;
7983
enableCustomButtons: boolean;
8084
customButtons: CustomButtonsType[];
8185
}
@@ -115,6 +119,10 @@ export interface FileUploaderPreviewProps {
115119
removeSuccessMessage: string;
116120
removeErrorMessage: string;
117121
objectCreationTimeout: number | null;
122+
onUploadSuccessFile: {} | null;
123+
onUploadSuccessImage: {} | null;
124+
onUploadFailureFile: {} | null;
125+
onUploadFailureImage: {} | null;
118126
enableCustomButtons: boolean;
119127
customButtons: CustomButtonsPreviewType[];
120128
}

0 commit comments

Comments
 (0)