Skip to content

Commit decb839

Browse files
authored
Merge pull request #518 from mfts/feat/bulk
chore(tus): misc, analytics and cleanup
2 parents 018a33b + 9add225 commit decb839

3 files changed

Lines changed: 52 additions & 26 deletions

File tree

components/upload-zone.tsx

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { useRouter } from "next/router";
2+
13
import { useCallback, useRef, useState } from "react";
24

35
import { useTeam } from "@/context/team-context";
@@ -11,9 +13,10 @@ import {
1113
Presentation as PresentationChartBarIcon,
1214
} from "lucide-react";
1315
import { useSession } from "next-auth/react";
14-
import { FileError, FileRejection, useDropzone } from "react-dropzone";
16+
import { FileRejection, useDropzone } from "react-dropzone";
1517
import { mutate } from "swr";
1618

19+
import { useAnalytics } from "@/lib/analytics";
1720
import { createDocument } from "@/lib/documents/create-document";
1821
import { resumableUpload } from "@/lib/files/tus-upload";
1922
import { usePlan } from "@/lib/swr/use-billing";
@@ -86,7 +89,9 @@ export default function UploadZone({
8689
>;
8790
folderPathName?: string;
8891
}) {
92+
const analytics = useAnalytics();
8993
const { plan, loading } = usePlan();
94+
const router = useRouter();
9095
const teamInfo = useTeam();
9196
const { data: session } = useSession();
9297
const maxSize = plan === "business" || plan === "datarooms" ? 100 : 30;
@@ -141,6 +146,16 @@ export default function UploadZone({
141146

142147
setProgress(Math.round(_progress / acceptedFiles.length));
143148
},
149+
onError: (error) => {
150+
setUploads((prev) =>
151+
prev.filter((upload) => upload.fileName !== file.name),
152+
);
153+
154+
setRejectedFiles((prev) => [
155+
{ fileName: file.name, message: "Error uploading file" },
156+
...prev,
157+
]);
158+
},
144159
ownerId: (session?.user as CustomUser).id,
145160
teamId: teamInfo?.currentTeam?.id as string,
146161
numPages,
@@ -174,6 +189,16 @@ export default function UploadZone({
174189
// update progress to 100%
175190
onUploadProgress(index, 100, document.id);
176191

192+
analytics.capture("Document Added", {
193+
documentId: document.id,
194+
name: document.name,
195+
numPages: document.numPages,
196+
path: router.asPath,
197+
type: document.type,
198+
teamId: teamInfo?.currentTeam?.id,
199+
bulkupload: true,
200+
});
201+
177202
return document;
178203
});
179204

lib/files/tus-upload.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { decodeBase64Url } from "../utils/decode-base64url";
55
type ResumableUploadParams = {
66
file: File;
77
onProgress?: (bytesUploaded: number, bytesTotal: number) => void;
8+
onError?: (error: Error | tus.DetailedError) => void;
89
ownerId: string;
910
teamId: string;
1011
numPages: number;
@@ -25,6 +26,7 @@ type UploadResult = {
2526
export function resumableUpload({
2627
file,
2728
onProgress,
29+
onError,
2830
ownerId,
2931
teamId,
3032
numPages,
@@ -54,9 +56,22 @@ export function resumableUpload({
5456
},
5557
chunkSize: 4 * 1024 * 1024,
5658
onError: (error) => {
59+
onError && onError(error);
5760
console.error("Failed because: " + error);
5861
reject(error);
5962
},
63+
onShouldRetry(error, retryAttempt, options) {
64+
console.error(`Should retry upload. Attempt ${retryAttempt}`);
65+
var status = error.originalResponse
66+
? error.originalResponse.getStatus()
67+
: 0;
68+
// Do not retry if the status is a 500.
69+
if (status === 500 || status === 403) {
70+
return false;
71+
}
72+
// For any other status code, we retry.
73+
return true;
74+
},
6075
onProgress,
6176
onSuccess: () => {
6277
console.log("Uploaded successfully");

pages/api/file/tus/[[...file]].ts

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { getServerSession } from "next-auth/next";
77
import path from "node:path";
88

99
import { newId } from "@/lib/id-helper";
10+
import { log } from "@/lib/utils";
1011

1112
import { authOptions } from "../../auth/[...nextauth]";
1213

@@ -19,10 +20,11 @@ export const config = {
1920
const tusServer = new Server({
2021
// `path` needs to match the route declared by the next file router
2122
path: "/api/file/tus",
22-
// maxSize: 1024 * 1024 * 1024 * 2, // 2 GiB
23-
// respectForwardedHeaders: true,
23+
maxSize: 1024 * 1024 * 1024 * 2, // 2 GiB
24+
respectForwardedHeaders: true,
2425
datastore: new S3Store({
2526
partSize: 8 * 1024 * 1024, // each uploaded part will have ~8MiB,
27+
// TODO: expirationPeriodInMilliseconds is not working due to a permissions issue
2628
// expirationPeriodInMilliseconds: 1000 * 60 * 60 * 3, // 3 hours
2729
s3ClientConfig: {
2830
bucket: process.env.NEXT_PRIVATE_UPLOAD_BUCKET as string,
@@ -47,39 +49,23 @@ const tusServer = new Server({
4749
generateUrl(req, { proto, host, path, id }) {
4850
// Encode the ID to be URL safe
4951
id = Buffer.from(id, "utf-8").toString("base64url");
50-
console.log("proto", proto);
51-
// INFO: hardcoding the protocol to https for now - https://github.com/tus/tus-node-server/issues/635
52-
proto = process.env.NODE_ENV === "development" ? "http" : "https";
5352
return `${proto}://${host}${path}/${id}`;
5453
},
5554
getFileIdFromRequest(req) {
5655
// Extract the ID from the URL
5756
const id = (req.url as string).split("/api/file/tus/")[1];
5857
return Buffer.from(id, "base64url").toString("utf-8");
5958
},
59+
onResponseError(req, res, err) {
60+
log({
61+
message: "Error uploading a file. Error: \n\n" + err,
62+
type: "error",
63+
});
64+
return { status_code: 500, body: "Internal Server Error" };
65+
},
6066
});
6167

6268
export default function handler(req: NextApiRequest, res: NextApiResponse) {
63-
// // Set CORS headers for all responses
64-
// res.setHeader(
65-
// "Access-Control-Allow-Methods",
66-
// "GET,POST,PUT,HEAD,DELETE,OPTIONS",
67-
// );
68-
// res.setHeader(
69-
// "Access-Control-Allow-Headers",
70-
// "Content-Type,Upload-Length,Upload-Offset,Upload-Metadata,Upload-Defer-Length,Upload-Concat",
71-
// );
72-
// res.setHeader(
73-
// "Access-Control-Expose-Headers",
74-
// "Upload-Offset,Upload-Length,Location",
75-
// );
76-
77-
// if (req.method === "OPTIONS") {
78-
// // Handle preflight requests
79-
// res.status(204).end();
80-
// return;
81-
// }
82-
8369
// Get the session
8470
const session = getServerSession(req, res, authOptions);
8571
if (!session) {

0 commit comments

Comments
 (0)