Skip to content

Commit 2da924c

Browse files
merge in changes from #1077
1 parent 8356ec0 commit 2da924c

File tree

8 files changed

+89
-49
lines changed

8 files changed

+89
-49
lines changed

apps/desktop/src-tauri/src/api.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::web_api::ManagerExt;
99

1010
pub async fn upload_multipart_initiate(app: &AppHandle, video_id: &str) -> Result<String, String> {
1111
#[derive(Deserialize)]
12+
#[serde(rename_all = "camelCase")]
1213
pub struct Response {
1314
upload_id: String,
1415
}

apps/desktop/src-tauri/src/recording.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ pub async fn start_recording(
251251
match AuthStore::get(&app).ok().flatten() {
252252
Some(_) => {
253253
// Pre-create the video and get the shareable link
254-
if let Ok(s3_config) = create_or_get_video(
254+
let s3_config = create_or_get_video(
255255
&app,
256256
false,
257257
None,
@@ -262,18 +262,19 @@ pub async fn start_recording(
262262
None,
263263
)
264264
.await
265-
{
266-
let link = app.make_app_url(format!("/s/{}", s3_config.id)).await;
267-
info!("Pre-created shareable link: {}", link);
268-
269-
Some(VideoUploadInfo {
270-
id: s3_config.id.to_string(),
271-
link: link.clone(),
272-
config: s3_config,
273-
})
274-
} else {
275-
None
276-
}
265+
.map_err(|err| {
266+
error!("Error creating instant mode video: {err}");
267+
err
268+
})?;
269+
270+
let link = app.make_app_url(format!("/s/{}", s3_config.id)).await;
271+
info!("Pre-created shareable link: {}", link);
272+
273+
Some(VideoUploadInfo {
274+
id: s3_config.id.to_string(),
275+
link: link.clone(),
276+
config: s3_config,
277+
})
277278
}
278279
// Allow the recording to proceed without error for any signed-in user
279280
_ => {

apps/desktop/src/routes/(window-chrome)/settings/recordings.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { revealItemInDir } from "@tauri-apps/plugin-opener";
1313
import * as shell from "@tauri-apps/plugin-shell";
1414
import { cx } from "cva";
1515
import {
16+
createEffect,
1617
createMemo,
1718
createSignal,
1819
For,
@@ -133,6 +134,7 @@ export default function Recordings() {
133134
Number(e.payload.uploaded) / Number(e.payload.total),
134135
);
135136
});
137+
createEffect(() => console.log({ ...uploadProgress }));
136138

137139
return (
138140
<div class="flex relative flex-col p-4 space-y-4 w-full h-full">
@@ -187,9 +189,11 @@ export default function Recordings() {
187189
handleCopyVideoToClipboard(recording.path)
188190
}
189191
uploadProgress={
190-
recording.meta.sharing?.id
191-
? uploadProgress[recording.meta.sharing.id]
192-
: undefined
192+
// TODO: Fix this
193+
Object.values(uploadProgress)[0]
194+
// recording.meta.sharing?.id
195+
// ? uploadProgress[recording.meta.sharing.id]
196+
// : undefined
193197
}
194198
/>
195199
)}

apps/web/actions/video/upload.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ export async function createVideoAndGetUploadUrl({
164164
isScreenshot = false,
165165
isUpload = false,
166166
folderId,
167+
supportsUploadProgress = false,
167168
}: {
168169
videoId?: Video.VideoId;
169170
duration?: number;
@@ -173,17 +174,16 @@ export async function createVideoAndGetUploadUrl({
173174
isScreenshot?: boolean;
174175
isUpload?: boolean;
175176
folderId?: Folder.FolderId;
177+
// TODO: Remove this once we are happy with it's stability
178+
supportsUploadProgress?: boolean;
176179
}) {
177180
const user = await getCurrentUser();
178181

179-
if (!user) {
180-
throw new Error("Unauthorized");
181-
}
182+
if (!user) throw new Error("Unauthorized");
182183

183184
try {
184-
if (!userIsPro(user) && duration && duration > 300) {
185+
if (!userIsPro(user) && duration && duration > 300)
185186
throw new Error("upgrade_required");
186-
}
187187

188188
const [customBucket] = await db()
189189
.select()
@@ -237,9 +237,10 @@ export async function createVideoAndGetUploadUrl({
237237

238238
await db().insert(videos).values(videoData);
239239

240-
await db().insert(videoUploads).values({
241-
videoId: idToUse,
242-
});
240+
if (supportsUploadProgress)
241+
await db().insert(videoUploads).values({
242+
videoId: idToUse,
243+
});
243244

244245
const fileKey = `${user.id}/${idToUse}/${
245246
isScreenshot ? "screenshot/screen-capture.jpg" : "result.mp4"

apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ export const CapCard = ({
292292
onDragStart={handleDragStart}
293293
onDragEnd={handleDragEnd}
294294
className={clsx(
295-
"flex relative overflow-hidden transition-colors duration-200 flex-col gap-4 w-full h-full rounded-xl cursor-default bg-gray-1 border border-gray-3 group",
295+
"flex relative overflow-hidden transition-colors duration-200 flex-col gap-4 w-full h-full rounded-xl cursor-default bg-gray-1 border border-gray-3 group z-10",
296296
isSelected
297297
? "!border-blue-10"
298298
: anyCapSelected
@@ -314,7 +314,7 @@ export const CapCard = ({
314314
: isDropdownOpen
315315
? "opacity-100"
316316
: "opacity-0 group-hover:opacity-100",
317-
"top-2 right-2 flex-col gap-2 z-[20]",
317+
"top-2 right-2 flex-col gap-2 z-20",
318318
)}
319319
>
320320
<CapCardButton
@@ -363,7 +363,7 @@ export const CapCard = ({
363363
e.stopPropagation();
364364
handleDownload();
365365
}}
366-
disabled={downloadMutation.isPending}
366+
disabled={downloadMutation.isPending || cap.hasActiveUpload}
367367
className="delay-25"
368368
icon={() => {
369369
return downloadMutation.isPending ? (
@@ -421,7 +421,7 @@ export const CapCard = ({
421421
error: "Failed to duplicate cap",
422422
});
423423
}}
424-
disabled={duplicateMutation.isPending}
424+
disabled={duplicateMutation.isPending || cap.hasActiveUpload}
425425
className="flex gap-2 items-center rounded-lg"
426426
>
427427
<FontAwesomeIcon className="size-3" icon={faCopy} />
@@ -503,26 +503,53 @@ export const CapCard = ({
503503
anyCapSelected && "cursor-pointer pointer-events-none",
504504
)}
505505
onClick={(e) => {
506-
if (isDeleting) {
507-
e.preventDefault();
508-
}
506+
if (isDeleting) e.preventDefault();
509507
}}
510508
href={`/s/${cap.id}`}
511509
>
512-
<VideoThumbnail
513-
videoDuration={cap.duration}
514-
imageClass={clsx(
515-
anyCapSelected
516-
? "opacity-50"
517-
: isDropdownOpen
518-
? "opacity-30"
519-
: "group-hover:opacity-30",
520-
"transition-opacity duration-200",
521-
uploadProgress && "opacity-30",
522-
)}
523-
videoId={cap.id}
524-
alt={`${cap.name} Thumbnail`}
525-
/>
510+
{uploadProgress ? (
511+
<div className="overflow-hidden relative mx-auto w-full h-full rounded-t-xl border-b border-gray-3 aspect-video bg-black z-0">
512+
<div className="flex absolute inset-0 z-50 justify-center items-center rounded-t-xl">
513+
{uploadProgress.status === "failed" ? (
514+
<div className="flex flex-col items-center">
515+
<div className="flex justify-center items-center mb-2 w-8 h-8 bg-red-500 rounded-full">
516+
<FontAwesomeIcon
517+
icon={faVideo}
518+
className="text-white size-3"
519+
/>
520+
</div>
521+
<p className="text-[13px] text-center text-white">
522+
Upload failed
523+
</p>
524+
</div>
525+
) : (
526+
<div className="relative size-20 md:size-16">
527+
<ProgressCircle
528+
progressTextClassName="md:!text-[11px]"
529+
subTextClassName="!mt-0 md:!text-[7px] !text-[10px] mb-1"
530+
className="md:scale-[1.5] scale-[1.2]"
531+
progress={uploadProgress.progress}
532+
/>
533+
</div>
534+
)}
535+
</div>
536+
</div>
537+
) : (
538+
<VideoThumbnail
539+
videoDuration={cap.duration}
540+
imageClass={clsx(
541+
anyCapSelected
542+
? "opacity-50"
543+
: isDropdownOpen
544+
? "opacity-30"
545+
: "group-hover:opacity-30",
546+
"transition-opacity duration-200",
547+
// uploadProgress && "opacity-30",
548+
)}
549+
videoId={cap.id}
550+
alt={`${cap.name} Thumbnail`}
551+
/>
552+
)}
526553
</Link>
527554
{uploadProgress && (
528555
<div className="flex absolute inset-0 z-50 justify-center items-center bg-black rounded-t-xl">

apps/web/app/api/desktop/[...route]/video.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,14 @@ app.get(
8585
.from(videos)
8686
.where(eq(videos.id, Video.VideoId.make(videoId)));
8787

88-
if (video) {
88+
if (video)
8989
return c.json({
9090
id: video.id,
9191
// All deprecated
9292
user_id: user.id,
9393
aws_region: "n/a",
9494
aws_bucket: "n/a",
9595
});
96-
}
9796
}
9897

9998
const idToUse = Video.VideoId.make(nanoId());

packages/web-backend/src/Videos/VideosRepo.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,15 @@ export class VideosRepo extends Effect.Service<VideosRepo>()("VideosRepo", {
4545
});
4646

4747
const delete_ = (id: Video.VideoId) =>
48-
db.execute((db) => db.delete(Db.videos).where(Dz.eq(Db.videos.id, id)));
48+
db.execute(
49+
async (db) =>
50+
await Promise.all([
51+
db.delete(Db.videos).where(Dz.eq(Db.videos.id, id)),
52+
db
53+
.delete(Db.videoUploads)
54+
.where(Dz.eq(Db.videoUploads.videoId, id)),
55+
]),
56+
);
4957

5058
const create = (data: CreateVideoInput) =>
5159
Effect.gen(function* () {

packages/web-backend/src/Videos/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { Array, Effect, Option, pipe } from "effect";
55

66
import { Database } from "../Database.ts";
77
import { S3Buckets } from "../S3Buckets/index.ts";
8-
import { S3BucketAccess } from "../S3Buckets/S3BucketAccess.ts";
98
import { VideosPolicy } from "./VideosPolicy.ts";
109
import { VideosRepo } from "./VideosRepo.ts";
1110

0 commit comments

Comments
 (0)