Skip to content

Commit

Permalink
fix: small improvements on file uploader
Browse files Browse the repository at this point in the history
  • Loading branch information
r0b1n committed Jan 31, 2025
1 parent 65ae55a commit 326e4d4
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@

<property key="createFileAction" type="action">
<caption>Action to create new files</caption>
<description>Action that creates an associated file object and commits it.</description>
<description>Nanoflow that creates a file document object, associates it to the current object and commits it.</description>
</property>

<property key="createImageAction" type="action">
<caption>Action to create new images</caption>
<description>Action that creates an associated image object and commits it.</description>
<description>Nanoflow that creates an image document object, associates it to the current object and commits it.</description>
</property>

<property key="allowedFileFormats" type="object" isList="true" required="false">
Expand Down Expand Up @@ -167,7 +167,7 @@
</property>

<property key="unavailableCreateActionMessage" type="textTemplate">
<caption>Action to create new files is not available</caption>
<caption>Action to create new files is not available or failed</caption>
<description />
<translations>
<translation lang="en_US">Can't upload files at this time. Please contact your system administrator.</translation>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const FileEntryContainer = observer(({ store }: FileEntryContainerProps):
errorMessage={store.errorDescription}
canRemove={store.canRemove}
onRemove={onRemove}
canDownload={store.canDownload}
downloadUrl={store.downloadUrl}
/>
);
Expand All @@ -44,13 +45,14 @@ interface FileEntryProps {
canRemove: boolean;
onRemove: () => void;

canDownload: boolean;
downloadUrl?: string;
}

function FileEntry(props: FileEntryProps): ReactElement {
const translations = useTranslationsStore();

const { downloadUrl, onRemove } = props;
const { canDownload, downloadUrl, onRemove } = props;

const onViewClick = useCallback(
(e: MouseEvent<HTMLDivElement>) => {
Expand Down Expand Up @@ -86,9 +88,9 @@ function FileEntry(props: FileEntryProps): ReactElement {
removed: props.fileStatus === "removedFile",
invalid: props.fileStatus === "validationError"
})}
tabIndex={0}
onClick={onViewClick}
onKeyDown={onKeyDown}
tabIndex={canDownload ? 0 : undefined}
onClick={canDownload ? onViewClick : undefined}
onKeyDown={canDownload ? onKeyDown : undefined}
>
<div className={"entry-details"}>
<div
Expand All @@ -109,7 +111,7 @@ function FileEntry(props: FileEntryProps): ReactElement {
</div>

<div className={"entry-details-actions"}>
<div className={"download-icon"} />
{downloadUrl && <div className={"download-icon"} />}
<button
className={classNames("action-button", {
disabled: !props.canRemove
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ export class FileStore {
return this.fileStatus === "existingFile" || this.fileStatus === "done";
}

get canDownload(): boolean {
return this.fileStatus === "done" || this.fileStatus === "existingFile";
}

async remove(): Promise<void> {
if (!this.canRemove || !this._objectItem) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ import { FileRejection } from "react-dropzone";
import { FileCheckFormat } from "../utils/predefinedFormats";
import { TranslationsStore } from "./TranslationsStore";

const ITEM_CREATION_TIMEOUT_SECONDS = 10;

export class FileUploaderStore {
files: FileStore[] = [];
lastSeenItems: Set<ObjectItem["id"]> = new Set<ObjectItem["id"]>();
currentWaiting: Array<(v: ObjectItem) => void> = [];
currentWaiting: Array<(v: ObjectItem | undefined) => void> = [];
itemCreationTimeout?: number = undefined;

existingItemsLoaded = false;

Expand Down Expand Up @@ -101,9 +104,7 @@ export class FileUploaderStore {

this.lastSeenItems.add(item.id);

if (this.currentWaiting.length) {
this._createObjectAction!.execute();
}
this.executeFileObjectCreation();
}

get allowedFormatsDescription(): string {
Expand All @@ -119,28 +120,53 @@ export class FileUploaderStore {
return this.existingItemsLoaded && !!this._createObjectAction;
}

requestFileObject(): Promise<ObjectItem> {
requestFileObject(): Promise<ObjectItem | undefined> {
if (!this.canRequestFile) {
throw new Error("Can't request file");
}

return new Promise<ObjectItem>(resolve => {
return new Promise<ObjectItem | undefined>(resolve => {
this.currentWaiting.push(resolve);

if (this.currentWaiting.length === 1) {
this._createObjectAction!.execute();
}
this.executeFileObjectCreation();
});
}

executeFileObjectCreation(): void {
if (!this.canRequestFile) {
throw new Error("Can't request file");
}

this.itemCreationTimeout = undefined;

if (!this.currentWaiting.length) {
return;
}
// we need to check if creation is taking too much time
// start the timer to measure how long it takes,
// if a threshold is reached, declare it a failure
// this means the action is probably misconfigured.
this.itemCreationTimeout = setTimeout(() => {
console.error(
`Looks like the 'Action to create new files/images' action did not create any objects within ${ITEM_CREATION_TIMEOUT_SECONDS} seconds. Please check if '${this._widgetName}' widget is configured correctly.`
);
// fail all waiting
while (this.currentWaiting.length) {
this.currentWaiting.shift()?.(undefined);
}
}, ITEM_CREATION_TIMEOUT_SECONDS * 1000) as any as number;

this._createObjectAction!.execute();
}

setMessage(msg?: string): void {
this.errorMessage = msg;
}

processDrop(acceptedFiles: File[], fileRejections: FileRejection[]): void {
if (!this._createObjectAction || !this._createObjectAction.canExecute) {
console.error(
`'Action to create new files' is not available or can't be executed. Please check if '${this._widgetName}' widget is configured correctly.`
`'Action to create new files/images' is not available or can't be executed. Please check if '${this._widgetName}' widget is configured correctly.`
);
this.setMessage(this.translations.get("unavailableCreateActionMessage"));
return;
Expand Down

0 comments on commit 326e4d4

Please sign in to comment.