Skip to content

Commit bac1ee2

Browse files
committed
🚸 (bot) Improve error message on failed file upload
1 parent 43a3eb5 commit bac1ee2

File tree

6 files changed

+60
-40
lines changed

6 files changed

+60
-40
lines changed

apps/viewer/src/features/fileUpload/api/generateUploadUrl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export const generateUploadUrl = publicProcedure
112112
)
113113
throw new TRPCError({
114114
code: "BAD_REQUEST",
115-
message: "File type not allowed",
115+
message: `File type ${fileType} not allowed`,
116116
});
117117

118118
const { visibility, maxFileSize } = parseFileUploadParams(block);

packages/embeds/js/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@typebot.io/js",
3-
"version": "0.8.14",
3+
"version": "0.8.15",
44
"description": "Javascript library to display typebots on your website",
55
"license": "FSL-1.1-ALv2",
66
"type": "module",

packages/embeds/js/src/features/blocks/inputs/fileUpload/components/FileUploadForm.tsx

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export const FileUploadForm = (props: Props) => {
6767

6868
const startSingleFileUpload = async (file: File) => {
6969
setIsUploading(true);
70-
const urls = await uploadFiles({
70+
const result = await uploadFiles({
7171
apiHost:
7272
props.context.apiHost ?? guessApiHost({ ignoreChatApiUrl: true }),
7373
files: [
@@ -82,29 +82,30 @@ export const FileUploadForm = (props: Props) => {
8282
],
8383
});
8484
setIsUploading(false);
85-
if (urls.length && urls[0])
85+
if (result.type === "success" && result.urls.length && result.urls[0])
8686
return props.onSubmit({
8787
type: "text",
8888
label:
8989
props.block.options?.labels?.success?.single ??
9090
defaultFileInputOptions.labels.success.single,
91-
value: urls[0] ? encodeUrl(urls[0].url) : "",
91+
value: result.urls[0] ? encodeUrl(result.urls[0].url) : "",
9292
attachments: [
9393
{
9494
type: file.type,
95-
url: urls[0]!.url,
95+
url: result.urls[0]!.url,
9696
blobUrl: URL.createObjectURL(file),
9797
},
9898
],
9999
});
100-
toaster.create({
101-
description: fileUploadErrorMessage,
102-
});
100+
if (result.type === "error")
101+
toaster.create({
102+
description: result.error,
103+
});
103104
};
104105

105106
const startFilesUpload = async (files: File[]) => {
106107
setIsUploading(true);
107-
const urls = await uploadFiles({
108+
const result = await uploadFiles({
108109
apiHost:
109110
props.context.apiHost ?? guessApiHost({ ignoreChatApiUrl: true }),
110111
files: files.map((file) => ({
@@ -119,25 +120,25 @@ export const FileUploadForm = (props: Props) => {
119120
});
120121
setIsUploading(false);
121122
setUploadProgressPercent(0);
122-
if (urls.length !== files.length)
123+
if (result.type === "error")
123124
return toaster.create({
124-
description: fileUploadErrorMessage,
125+
description: result.error,
125126
});
126127
props.onSubmit({
127128
type: "text",
128129
label:
129-
urls.length > 1
130+
result.urls.length > 1
130131
? (
131132
props.block.options?.labels?.success?.multiple ??
132133
defaultFileInputOptions.labels.success.multiple
133-
).replaceAll("{total}", urls.length.toString())
134+
).replaceAll("{total}", result.urls.length.toString())
134135
: (props.block.options?.labels?.success?.single ??
135136
defaultFileInputOptions.labels.success.single),
136-
value: urls
137+
value: result.urls
137138
.filter(isDefined)
138139
.map(({ url }) => encodeUrl(url))
139140
.join(", "),
140-
attachments: urls
141+
attachments: result.urls
141142
.map((urls, index) =>
142143
urls
143144
? {

packages/embeds/js/src/features/blocks/inputs/fileUpload/helpers/uploadFiles.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,17 @@ export const uploadFiles = async ({
2222
apiHost,
2323
files,
2424
onUploadProgress,
25-
}: UploadFileProps): Promise<UrlList> => {
25+
}: UploadFileProps): Promise<
26+
{ type: "success"; urls: UrlList } | { type: "error"; error: string }
27+
> => {
2628
const urls: UrlList = [];
29+
const errors: string[] = [];
2730
let i = 0;
2831
for (const { input, file } of files) {
2932
onUploadProgress &&
3033
onUploadProgress({ progress: (i / files.length) * 100, fileIndex: i });
3134
i += 1;
32-
const { data } = await sendRequest<{
35+
const { data, error } = await sendRequest<{
3336
presignedUrl: string;
3437
formData: Record<string, string>;
3538
fileUrl: string;
@@ -44,6 +47,11 @@ export const uploadFiles = async ({
4447
},
4548
});
4649

50+
if (error) {
51+
errors.push(error.message);
52+
continue;
53+
}
54+
4755
if (!data?.presignedUrl) continue;
4856
else {
4957
const formData = new FormData();
@@ -61,5 +69,7 @@ export const uploadFiles = async ({
6169
urls.push({ url: data.fileUrl, type: file.type });
6270
}
6371
}
64-
return urls;
72+
return errors.length > 0
73+
? { type: "error", error: errors.join(", ") }
74+
: { type: "success", urls };
6575
};

packages/embeds/js/src/features/blocks/inputs/textInput/components/TextInput.tsx

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export const TextInput = (props: Props) => {
6464
let attachments: Attachment[] | undefined;
6565
if (selectedFiles().length > 0) {
6666
setUploadProgress(undefined);
67-
const urls = await uploadFiles({
67+
const result = await uploadFiles({
6868
apiHost:
6969
props.context.apiHost ?? guessApiHost({ ignoreChatApiUrl: true }),
7070
files: selectedFiles().map((file) => ({
@@ -77,7 +77,13 @@ export const TextInput = (props: Props) => {
7777
})),
7878
onUploadProgress: setUploadProgress,
7979
});
80-
attachments = urls
80+
if (result.type === "error") {
81+
toaster.create({
82+
description: result.error,
83+
});
84+
return;
85+
}
86+
attachments = result.urls
8187
?.map((urls, index) =>
8288
urls
8389
? {
@@ -214,25 +220,28 @@ export const TextInput = (props: Props) => {
214220
);
215221

216222
setUploadProgress(undefined);
217-
const urls = (
218-
await uploadFiles({
219-
apiHost:
220-
props.context.apiHost ?? guessApiHost({ ignoreChatApiUrl: true }),
221-
files: [
222-
{
223-
file: audioFile,
224-
input: {
225-
blockId: props.block.id,
226-
sessionId: props.context.sessionId,
227-
fileName: audioFile.name,
228-
},
223+
const result = await uploadFiles({
224+
apiHost:
225+
props.context.apiHost ?? guessApiHost({ ignoreChatApiUrl: true }),
226+
files: [
227+
{
228+
file: audioFile,
229+
input: {
230+
blockId: props.block.id,
231+
sessionId: props.context.sessionId,
232+
fileName: audioFile.name,
229233
},
230-
],
231-
onUploadProgress: setUploadProgress,
232-
})
233-
)
234-
.filter(isDefined)
235-
.map((url) => url.url);
234+
},
235+
],
236+
onUploadProgress: setUploadProgress,
237+
});
238+
if (result.type === "error") {
239+
toaster.create({
240+
description: result.error,
241+
});
242+
return;
243+
}
244+
const urls = result.urls.filter(isDefined).map((url) => url.url);
236245
props.onSubmit({
237246
type: "recording",
238247
url: urls[0],

packages/embeds/react/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@typebot.io/react",
3-
"version": "0.8.14",
3+
"version": "0.8.15",
44
"description": "Convenient library to display typebots on your React app",
55
"license": "FSL-1.1-ALv2",
66
"type": "module",

0 commit comments

Comments
 (0)