디렉터리 페이지에서의 네트워크 호출 최적화

This commit is contained in:
static
2025-12-30 17:21:54 +09:00
parent cdb652cacf
commit 409ae09f4f
25 changed files with 507 additions and 560 deletions

View File

@@ -1,19 +1,10 @@
<script lang="ts">
import { get } from "svelte/store";
import { FullscreenDiv } from "$lib/components/atoms";
import { TopBar } from "$lib/components/molecules";
import { fileUploadStatusStore, isFileUploading } from "$lib/stores";
import { getUploadingFiles, clearUploadedFiles } from "$lib/modules/file";
import File from "./File.svelte";
let uploadingFiles = $derived(
$fileUploadStatusStore.filter((status) => isFileUploading(get(status).status)),
);
$effect(() => () => {
$fileUploadStatusStore = $fileUploadStatusStore.filter((status) =>
isFileUploading(get(status).status),
);
});
$effect(() => clearUploadedFiles);
</script>
<svelte:head>
@@ -23,8 +14,8 @@
<TopBar />
<FullscreenDiv>
<div class="space-y-2 pb-4">
{#each uploadingFiles as status}
<File {status} />
{#each getUploadingFiles() as file}
<File state={file} />
{/each}
</div>
</FullscreenDiv>

View File

@@ -1,6 +1,5 @@
<script lang="ts">
import type { Writable } from "svelte/store";
import type { FileUploadStatus } from "$lib/stores";
import type { FileUploadState } from "$lib/modules/file";
import { formatNetworkSpeed } from "$lib/utils";
import IconPending from "~icons/material-symbols/pending";
@@ -11,45 +10,45 @@
import IconError from "~icons/material-symbols/error";
interface Props {
status: Writable<FileUploadStatus>;
state: FileUploadState;
}
let { status }: Props = $props();
let { state }: Props = $props();
</script>
<div class="flex h-14 items-center gap-x-4 p-2">
<div class="flex-shrink-0 text-lg text-gray-600">
{#if $status.status === "encryption-pending"}
{#if state.status === "encryption-pending"}
<IconPending />
{:else if $status.status === "encrypting"}
{:else if state.status === "encrypting"}
<IconLockClock />
{:else if $status.status === "upload-pending"}
{:else if state.status === "upload-pending"}
<IconCloud />
{:else if $status.status === "uploading"}
{:else if state.status === "uploading"}
<IconCloudUpload />
{:else if $status.status === "uploaded"}
{:else if state.status === "uploaded"}
<IconCloudDone class="text-blue-500" />
{:else if $status.status === "error"}
{:else if state.status === "error"}
<IconError class="text-red-500" />
{/if}
</div>
<div class="flex-grow overflow-hidden">
<p title={$status.name} class="truncate font-medium">
{$status.name}
<p title={state.name} class="truncate font-medium">
{state.name}
</p>
<p class="text-xs text-gray-800">
{#if $status.status === "encryption-pending"}
{#if state.status === "encryption-pending"}
준비 중
{:else if $status.status === "encrypting"}
{:else if state.status === "encrypting"}
암호화하는 중
{:else if $status.status === "upload-pending"}
{:else if state.status === "upload-pending"}
업로드를 기다리는 중
{:else if $status.status === "uploading"}
{:else if state.status === "uploading"}
전송됨
{Math.floor(($status.progress ?? 0) * 100)}% · {formatNetworkSpeed(($status.rate ?? 0) * 8)}
{:else if $status.status === "uploaded"}
{Math.floor((state.progress ?? 0) * 100)}% · {formatNetworkSpeed((state.rate ?? 0) * 8)}
{:else if state.status === "uploaded"}
업로드 완료
{:else if $status.status === "error"}
{:else if state.status === "error"}
업로드 실패
{/if}
</p>

View File

@@ -1,11 +1,10 @@
<script lang="ts">
import { onMount } from "svelte";
import type { Writable } from "svelte/store";
import { goto } from "$app/navigation";
import { page } from "$app/state";
import { FloatingButton } from "$lib/components/atoms";
import { TopBar } from "$lib/components/molecules";
import { getDirectoryInfo, type DirectoryInfo } from "$lib/modules/filesystem";
import { getDirectoryInfo, type DirectoryInfo } from "$lib/modules/filesystem2.svelte";
import { masterKeyStore, hmacSecretStore } from "$lib/stores";
import DirectoryCreateModal from "./DirectoryCreateModal.svelte";
import DirectoryEntries from "./DirectoryEntries";
@@ -30,7 +29,7 @@
let { data } = $props();
let context = createContext();
let info: Writable<DirectoryInfo | null> | undefined = $state();
let infoPromise: Promise<DirectoryInfo> | undefined = $state();
let fileInput: HTMLInputElement | undefined = $state();
let duplicatedFile: File | undefined = $state();
let resolveForDuplicateFileModal: ((res: boolean) => void) | undefined = $state();
@@ -61,7 +60,7 @@
.then((res) => {
if (!res) return;
// TODO: FIXME
info = getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!);
infoPromise = getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!);
})
.catch((e: Error) => {
// TODO: FIXME
@@ -79,7 +78,7 @@
});
$effect(() => {
info = getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!);
infoPromise = getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!);
});
</script>
@@ -89,106 +88,106 @@
<input bind:this={fileInput} onchange={uploadFile} type="file" multiple class="hidden" />
<div class="flex h-full flex-col">
{#if showTopBar}
<TopBar title={$info?.name} class="flex-shrink-0" />
{/if}
{#if $info}
<div class={["flex flex-grow flex-col px-4 pb-4", !showTopBar && "pt-4"]}>
<div class="flex gap-x-2">
<UploadStatusCard onclick={() => goto("/file/uploads")} />
<DownloadStatusCard onclick={() => goto("/file/downloads")} />
</div>
{#key $info}
{#await infoPromise then info}
{#if info}
<div class="flex h-full flex-col">
{#if showTopBar}
<TopBar title={info.name} class="flex-shrink-0" />
{/if}
<div class={["flex flex-grow flex-col px-4 pb-4", !showTopBar && "pt-4"]}>
<div class="flex gap-x-2">
<UploadStatusCard onclick={() => goto("/file/uploads")} />
<DownloadStatusCard onclick={() => goto("/file/downloads")} />
</div>
<DirectoryEntries
info={$info}
{info}
onEntryClick={({ type, id }) => goto(`/${type}/${id}`)}
onEntryMenuClick={(entry) => {
context.selectedEntry = entry;
isEntryMenuBottomSheetOpen = true;
}}
showParentEntry={isFromFilePage && $info.parentId !== undefined}
showParentEntry={isFromFilePage && info.parentId !== undefined}
onParentClick={() =>
goto(
$info.parentId === "root"
info.parentId === "root"
? "/directory?from=file"
: `/directory/${$info.parentId}?from=file`,
: `/directory/${info.parentId}?from=file`,
)}
/>
{/key}
</div>
</div>
<FloatingButton
icon={IconAdd}
onclick={() => {
isEntryCreateBottomSheetOpen = true;
}}
class="bottom-24 right-4"
/>
<EntryCreateBottomSheet
bind:isOpen={isEntryCreateBottomSheetOpen}
onDirectoryCreateClick={() => {
isEntryCreateBottomSheetOpen = false;
isDirectoryCreateModalOpen = true;
}}
onFileUploadClick={() => {
isEntryCreateBottomSheetOpen = false;
fileInput?.click();
}}
/>
<DirectoryCreateModal
bind:isOpen={isDirectoryCreateModalOpen}
onCreateClick={async (name) => {
if (await requestDirectoryCreation(name, data.id, $masterKeyStore?.get(1)!)) {
infoPromise = getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
return true;
}
return false;
}}
/>
<DuplicateFileModal
bind:isOpen={isDuplicateFileModalOpen}
file={duplicatedFile}
onbeforeclose={() => {
resolveForDuplicateFileModal?.(false);
isDuplicateFileModalOpen = false;
}}
onUploadClick={() => {
resolveForDuplicateFileModal?.(true);
isDuplicateFileModalOpen = false;
}}
/>
<EntryMenuBottomSheet
bind:isOpen={isEntryMenuBottomSheetOpen}
onRenameClick={() => {
isEntryMenuBottomSheetOpen = false;
isEntryRenameModalOpen = true;
}}
onDeleteClick={() => {
isEntryMenuBottomSheetOpen = false;
isEntryDeleteModalOpen = true;
}}
/>
<EntryRenameModal
bind:isOpen={isEntryRenameModalOpen}
onRenameClick={async (newName: string) => {
if (await requestEntryRename(context.selectedEntry!, newName)) {
infoPromise = getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
return true;
}
return false;
}}
/>
<EntryDeleteModal
bind:isOpen={isEntryDeleteModalOpen}
onDeleteClick={async () => {
if (await requestEntryDeletion(context.selectedEntry!)) {
infoPromise = getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
return true;
}
return false;
}}
/>
{/if}
</div>
<FloatingButton
icon={IconAdd}
onclick={() => {
isEntryCreateBottomSheetOpen = true;
}}
class="bottom-24 right-4"
/>
<EntryCreateBottomSheet
bind:isOpen={isEntryCreateBottomSheetOpen}
onDirectoryCreateClick={() => {
isEntryCreateBottomSheetOpen = false;
isDirectoryCreateModalOpen = true;
}}
onFileUploadClick={() => {
isEntryCreateBottomSheetOpen = false;
fileInput?.click();
}}
/>
<DirectoryCreateModal
bind:isOpen={isDirectoryCreateModalOpen}
onCreateClick={async (name) => {
if (await requestDirectoryCreation(name, data.id, $masterKeyStore?.get(1)!)) {
info = getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
return true;
}
return false;
}}
/>
<DuplicateFileModal
bind:isOpen={isDuplicateFileModalOpen}
file={duplicatedFile}
onbeforeclose={() => {
resolveForDuplicateFileModal?.(false);
isDuplicateFileModalOpen = false;
}}
onUploadClick={() => {
resolveForDuplicateFileModal?.(true);
isDuplicateFileModalOpen = false;
}}
/>
<EntryMenuBottomSheet
bind:isOpen={isEntryMenuBottomSheetOpen}
onRenameClick={() => {
isEntryMenuBottomSheetOpen = false;
isEntryRenameModalOpen = true;
}}
onDeleteClick={() => {
isEntryMenuBottomSheetOpen = false;
isEntryDeleteModalOpen = true;
}}
/>
<EntryRenameModal
bind:isOpen={isEntryRenameModalOpen}
onRenameClick={async (newName: string) => {
if (await requestEntryRename(context.selectedEntry!, newName)) {
info = getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
return true;
}
return false;
}}
/>
<EntryDeleteModal
bind:isOpen={isEntryDeleteModalOpen}
onDeleteClick={async () => {
if (await requestEntryDeletion(context.selectedEntry!)) {
info = getDirectoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
return true;
}
return false;
}}
/>
{/await}

View File

@@ -1,21 +1,9 @@
<script lang="ts">
import { untrack } from "svelte";
import { get, type Writable } from "svelte/store";
import { ActionEntryButton, RowVirtualizer } from "$lib/components/atoms";
import { DirectoryEntryLabel } from "$lib/components/molecules";
import {
getDirectoryInfo,
getFileInfo,
type DirectoryInfo,
type FileInfo,
} from "$lib/modules/filesystem";
import {
fileUploadStatusStore,
isFileUploading,
masterKeyStore,
type FileUploadStatus,
} from "$lib/stores";
import { SortBy, sortEntries } from "$lib/utils";
import { getUploadingFiles, type LiveFileUploadState } from "$lib/modules/file";
import type { DirectoryInfo } from "$lib/modules/filesystem2.svelte";
import { sortEntries } from "$lib/utils";
import File from "./File.svelte";
import SubDirectory from "./SubDirectory.svelte";
import UploadingFile from "./UploadingFile.svelte";
@@ -27,7 +15,6 @@
onEntryMenuClick: (entry: SelectedEntry) => void;
onParentClick?: () => void;
showParentEntry?: boolean;
sortBy?: SortBy;
}
let {
@@ -36,85 +23,29 @@
onEntryMenuClick,
onParentClick,
showParentEntry = false,
sortBy = SortBy.NAME_ASC,
}: Props = $props();
interface DirectoryEntry {
name?: string;
info: Writable<DirectoryInfo | null>;
}
type FileEntry =
| {
type: "file";
name?: string;
info: Writable<FileInfo | null>;
}
| {
type: "uploading-file";
name: string;
info: Writable<FileUploadStatus>;
};
| { type: "file"; name: string; details: (typeof info.files)[number] }
| { type: "uploading-file"; name: string; details: LiveFileUploadState };
let subDirectories: DirectoryEntry[] = $state([]);
let files: FileEntry[] = $state([]);
$effect(() => {
// TODO: Fix duplicated requests
subDirectories = info.subDirectoryIds.map((id) => {
const info = getDirectoryInfo(id, $masterKeyStore?.get(1)?.key!);
return { name: get(info)?.name, info };
const toFileEntry =
<T extends FileEntry["type"]>(type: T) =>
(details: Extract<FileEntry, { type: T }>["details"]) => ({
type,
name: details.name,
details,
});
files = info.fileIds
.map((id): FileEntry => {
const info = getFileInfo(id, $masterKeyStore?.get(1)?.key!);
return {
type: "file",
name: get(info)?.name,
info,
};
})
.concat(
$fileUploadStatusStore
.filter((statusStore) => {
const { parentId, status } = get(statusStore);
return parentId === info.id && isFileUploading(status);
})
.map((status) => ({
type: "uploading-file",
name: get(status).name,
info: status,
})),
);
const sort = () => {
sortEntries(subDirectories, sortBy);
sortEntries(files, sortBy);
};
return untrack(() => {
sort();
const unsubscribes = subDirectories
.map((subDirectory) =>
subDirectory.info.subscribe((value) => {
if (subDirectory.name === value?.name) return;
subDirectory.name = value?.name;
sort();
}),
)
.concat(
files.map((file) =>
file.info.subscribe((value) => {
if (file.name === value?.name) return;
file.name = value?.name;
sort();
}),
),
);
return () => unsubscribes.forEach((unsubscribe) => unsubscribe());
});
});
const subDirectories = $derived(
sortEntries(structuredClone($state.snapshot(info.subDirectories))),
);
const files = $derived(
sortEntries<FileEntry>([
...info.files.map(toFileEntry("file")),
...getUploadingFiles(info.id).map(toFileEntry("uploading-file")),
]),
);
</script>
{#if subDirectories.length + files.length > 0 || showParentEntry}
@@ -124,8 +55,8 @@
<DirectoryEntryLabel type="parent-directory" name=".." />
</ActionEntryButton>
{/if}
{#each subDirectories as { info }}
<SubDirectory {info} onclick={onEntryClick} onOpenMenuClick={onEntryMenuClick} />
{#each subDirectories as subDirectory}
<SubDirectory info={subDirectory} onclick={onEntryClick} onOpenMenuClick={onEntryMenuClick} />
{/each}
{#if files.length > 0}
<RowVirtualizer
@@ -136,9 +67,9 @@
{@const file = files[index]!}
<div class={index + 1 < files.length ? "pb-1" : ""}>
{#if file.type === "file"}
<File info={file.info} onclick={onEntryClick} onOpenMenuClick={onEntryMenuClick} />
<File info={file.details} onclick={onEntryClick} onOpenMenuClick={onEntryMenuClick} />
{:else}
<UploadingFile status={file.info} />
<UploadingFile state={file.details} />
{/if}
</div>
{/snippet}

View File

@@ -1,66 +1,46 @@
<script lang="ts">
import type { Writable } from "svelte/store";
import { browser } from "$app/environment";
import { ActionEntryButton } from "$lib/components/atoms";
import { DirectoryEntryLabel } from "$lib/components/molecules";
import type { FileInfo } from "$lib/modules/filesystem";
import type { SummarizedFileInfo } from "$lib/modules/filesystem2.svelte";
import { requestFileThumbnailDownload } from "$lib/services/file";
import { formatDateTime } from "$lib/utils";
import { requestFileThumbnailDownload } from "./service";
import type { SelectedEntry } from "../service.svelte";
import IconMoreVert from "~icons/material-symbols/more-vert";
interface Props {
info: Writable<FileInfo | null>;
onclick: (selectedEntry: SelectedEntry) => void;
onOpenMenuClick: (selectedEntry: SelectedEntry) => void;
info: SummarizedFileInfo;
onclick: (entry: SelectedEntry) => void;
onOpenMenuClick: (entry: SelectedEntry) => void;
}
let { info, onclick, onOpenMenuClick }: Props = $props();
let thumbnail: string | undefined = $state();
let showThumbnail = $derived(
browser && (info.contentType.startsWith("image/") || info.contentType.startsWith("video/")),
);
let thumbnailPromise = $derived(
showThumbnail ? requestFileThumbnailDownload(info.id, info.dataKey?.key) : null,
);
const openFile = () => {
const { id, dataKey, dataKeyVersion, name } = $info!;
if (!dataKey || !dataKeyVersion) return; // TODO: Error handling
onclick({ type: "file", id, dataKey, dataKeyVersion, name });
const action = (callback: typeof onclick) => {
callback({ type: "file", id: info.id, dataKey: info.dataKey, name: info.name });
};
const openMenu = () => {
const { id, dataKey, dataKeyVersion, name } = $info!;
if (!dataKey || !dataKeyVersion) return; // TODO: Error handling
onOpenMenuClick({ type: "file", id, dataKey, dataKeyVersion, name });
};
$effect(() => {
if ($info) {
requestFileThumbnailDownload($info.id, $info.dataKey)
.then((thumbnailUrl) => {
thumbnail = thumbnailUrl ?? undefined;
})
.catch(() => {
// TODO: Error Handling
thumbnail = undefined;
});
} else {
thumbnail = undefined;
}
});
</script>
{#if $info}
<ActionEntryButton
class="h-14"
onclick={openFile}
actionButtonIcon={IconMoreVert}
onActionButtonClick={openMenu}
>
<ActionEntryButton
class="h-14"
onclick={() => action(onclick)}
actionButtonIcon={IconMoreVert}
onActionButtonClick={() => action(onOpenMenuClick)}
>
{#await thumbnailPromise then thumbnail}
<DirectoryEntryLabel
type="file"
{thumbnail}
name={$info.name}
subtext={formatDateTime($info.createdAt ?? $info.lastModifiedAt)}
thumbnail={thumbnail ?? undefined}
name={info.name}
subtext={formatDateTime(info.createdAt ?? info.lastModifiedAt)}
/>
</ActionEntryButton>
{/if}
{/await}
</ActionEntryButton>

View File

@@ -1,44 +1,29 @@
<script lang="ts">
import type { Writable } from "svelte/store";
import { ActionEntryButton } from "$lib/components/atoms";
import { DirectoryEntryLabel } from "$lib/components/molecules";
import type { DirectoryInfo } from "$lib/modules/filesystem";
import type { SubDirectoryInfo } from "$lib/modules/filesystem2.svelte";
import type { SelectedEntry } from "../service.svelte";
import IconMoreVert from "~icons/material-symbols/more-vert";
type SubDirectoryInfo = DirectoryInfo & { id: number };
interface Props {
info: Writable<DirectoryInfo | null>;
onclick: (selectedEntry: SelectedEntry) => void;
onOpenMenuClick: (selectedEntry: SelectedEntry) => void;
info: SubDirectoryInfo;
onclick: (entry: SelectedEntry) => void;
onOpenMenuClick: (entry: SelectedEntry) => void;
}
let { info, onclick, onOpenMenuClick }: Props = $props();
const openDirectory = () => {
const { id, dataKey, dataKeyVersion, name } = $info as SubDirectoryInfo;
if (!dataKey || !dataKeyVersion) return; // TODO: Error handling
onclick({ type: "directory", id, dataKey, dataKeyVersion, name });
};
const openMenu = () => {
const { id, dataKey, dataKeyVersion, name } = $info as SubDirectoryInfo;
if (!dataKey || !dataKeyVersion) return; // TODO: Error handling
onOpenMenuClick({ type: "directory", id, dataKey, dataKeyVersion, name });
const action = (callback: typeof onclick) => {
callback({ type: "directory", id: info.id, dataKey: info.dataKey, name: info.name });
};
</script>
{#if $info}
<ActionEntryButton
class="h-14"
onclick={openDirectory}
actionButtonIcon={IconMoreVert}
onActionButtonClick={openMenu}
>
<DirectoryEntryLabel type="directory" name={$info.name!} />
</ActionEntryButton>
{/if}
<ActionEntryButton
class="h-14"
onclick={() => action(onclick)}
actionButtonIcon={IconMoreVert}
onActionButtonClick={() => action(onOpenMenuClick)}
>
<DirectoryEntryLabel type="directory" name={info.name} />
</ActionEntryButton>

View File

@@ -1,38 +1,35 @@
<script lang="ts">
import type { Writable } from "svelte/store";
import { isFileUploading, type FileUploadStatus } from "$lib/stores";
import type { LiveFileUploadState } from "$lib/modules/file";
import { formatNetworkSpeed } from "$lib/utils";
import IconDraft from "~icons/material-symbols/draft";
interface Props {
status: Writable<FileUploadStatus>;
state: LiveFileUploadState;
}
let { status }: Props = $props();
let { state }: Props = $props();
</script>
{#if isFileUploading($status.status)}
<div class="flex h-14 gap-x-4 p-2">
<div class="flex h-10 w-10 flex-shrink-0 items-center justify-center text-xl">
<IconDraft class="text-gray-600" />
</div>
<div class="flex flex-grow flex-col overflow-hidden text-gray-800">
<p title={$status.name} class="truncate font-medium">
{$status.name}
</p>
<p class="text-xs">
{#if $status.status === "encryption-pending"}
준비 중
{:else if $status.status === "encrypting"}
암호화하는 중
{:else if $status.status === "upload-pending"}
업로드를 기다리는 중
{:else if $status.status === "uploading"}
전송됨 {Math.floor(($status.progress ?? 0) * 100)}% ·
{formatNetworkSpeed(($status.rate ?? 0) * 8)}
{/if}
</p>
</div>
<div class="flex h-14 gap-x-4 p-2">
<div class="flex h-10 w-10 flex-shrink-0 items-center justify-center text-xl">
<IconDraft class="text-gray-600" />
</div>
{/if}
<div class="flex flex-grow flex-col overflow-hidden text-gray-800">
<p title={state.name} class="truncate font-medium">
{state.name}
</p>
<p class="text-xs">
{#if state.status === "encryption-pending"}
준비 중
{:else if state.status === "encrypting"}
암호화하는 중
{:else if state.status === "upload-pending"}
업로드를 기다리는 중
{:else if state.status === "uploading"}
전송됨 {Math.floor((state.progress ?? 0) * 100)}% ·
{formatNetworkSpeed((state.rate ?? 0) * 8)}
{/if}
</p>
</div>
</div>

View File

@@ -1 +0,0 @@
export { requestFileThumbnailDownload } from "$lib/services/file";

View File

@@ -1,7 +1,5 @@
<script lang="ts">
import { untrack } from "svelte";
import { get, type Writable } from "svelte/store";
import { fileUploadStatusStore, isFileUploading, type FileUploadStatus } from "$lib/stores";
import { getUploadingFiles } from "$lib/modules/file";
interface Props {
onclick: () => void;
@@ -9,21 +7,7 @@
let { onclick }: Props = $props();
let uploadingFiles: Writable<FileUploadStatus>[] = $state([]);
$effect(() => {
uploadingFiles = $fileUploadStatusStore.filter((status) => isFileUploading(get(status).status));
return untrack(() => {
const unsubscribes = uploadingFiles.map((uploadingFile) =>
uploadingFile.subscribe(({ status }) => {
if (!isFileUploading(status)) {
uploadingFiles = uploadingFiles.filter((file) => file !== uploadingFile);
}
}),
);
return () => unsubscribes.forEach((unsubscribe) => unsubscribe());
});
});
let uploadingFiles = $derived(getUploadingFiles());
</script>
{#if uploadingFiles.length > 0}

View File

@@ -14,8 +14,7 @@ import { trpc } from "$trpc/client";
export interface SelectedEntry {
type: "directory" | "file";
id: number;
dataKey: CryptoKey;
dataKeyVersion: Date;
dataKey: { key: CryptoKey; version: Date } | undefined;
name: string;
}
@@ -97,20 +96,26 @@ export const requestFileUpload = async (
};
export const requestEntryRename = async (entry: SelectedEntry, newName: string) => {
const newNameEncrypted = await encryptString(newName, entry.dataKey);
if (!entry.dataKey) {
// TODO: Error Handling
console.log("hi");
return false;
}
const newNameEncrypted = await encryptString(newName, entry.dataKey.key);
try {
if (entry.type === "directory") {
await trpc().directory.rename.mutate({
id: entry.id,
dekVersion: entry.dataKeyVersion,
dekVersion: entry.dataKey.version,
name: newNameEncrypted.ciphertext,
nameIv: newNameEncrypted.iv,
});
} else {
await trpc().file.rename.mutate({
id: entry.id,
dekVersion: entry.dataKeyVersion,
dekVersion: entry.dataKey.version,
name: newNameEncrypted.ciphertext,
nameIv: newNameEncrypted.iv,
});

View File

@@ -2,10 +2,9 @@
import { onMount } from "svelte";
import { get } from "svelte/store";
import { goto as svelteGoto } from "$app/navigation";
import { getUploadingFiles } from "$lib/modules/file";
import {
fileUploadStatusStore,
fileDownloadStatusStore,
isFileUploading,
isFileDownloading,
clientKeyStore,
masterKeyStore,
@@ -16,7 +15,7 @@
const protectFileUploadAndDownload = (e: BeforeUnloadEvent) => {
if (
$fileUploadStatusStore.some((status) => isFileUploading(get(status).status)) ||
getUploadingFiles().length > 0 ||
$fileDownloadStatusStore.some((status) => isFileDownloading(get(status).status))
) {
e.preventDefault();