카테고리 페이지에서의 네트워크 호출 최적화

This commit is contained in:
static
2025-12-30 20:53:20 +09:00
parent 1e57941f4c
commit b5522a4c6d
19 changed files with 416 additions and 521 deletions

View File

@@ -6,12 +6,7 @@
import { page } from "$app/state";
import { FullscreenDiv } from "$lib/components/atoms";
import { Categories, IconEntryButton, TopBar } from "$lib/components/molecules";
import {
getFileInfo,
getCategoryInfo,
type FileInfo,
type CategoryInfo,
} from "$lib/modules/filesystem";
import { getFileInfo, type FileInfo } from "$lib/modules/filesystem";
import { captureVideoThumbnail } from "$lib/modules/thumbnail";
import { fileDownloadStatusStore, isFileDownloading, masterKeyStore } from "$lib/stores";
import AddToCategoryBottomSheet from "./AddToCategoryBottomSheet.svelte";
@@ -32,7 +27,7 @@
let { data } = $props();
let info: Writable<FileInfo | null> | undefined = $state();
let categories: Writable<CategoryInfo | null>[] = $state([]);
// let categories: Writable<CategoryInfo | null>[] = $state([]);
let isMenuOpen = $state(false);
let isAddToCategoryBottomSheetOpen = $state(false);
@@ -90,10 +85,10 @@
viewerType = undefined;
});
$effect(() => {
categories =
$info?.categoryIds.map((id) => getCategoryInfo(id, $masterKeyStore?.get(1)?.key!)) ?? [];
});
// $effect(() => {
// categories =
// $info?.categoryIds.map((id) => getCategoryInfo(id, $masterKeyStore?.get(1)?.key!)) ?? [];
// });
$effect(() => {
if ($info && $info.dataKey && $info.contentIv) {
@@ -190,12 +185,12 @@
<div class="space-y-2">
<p class="text-lg font-bold">카테고리</p>
<div class="space-y-1">
<Categories
<!-- <Categories
{categories}
categoryMenuIcon={IconClose}
onCategoryClick={({ id }) => goto(`/category/${id}`)}
onCategoryMenuClick={({ id }) => removeFromCategory(id)}
/>
/> -->
<IconEntryButton
icon={IconAddCircle}
onclick={() => (isAddToCategoryBottomSheetOpen = true)}

View File

@@ -1,9 +1,8 @@
<script lang="ts">
import type { Writable } from "svelte/store";
import { BottomDiv, BottomSheet, Button, FullscreenDiv } from "$lib/components/atoms";
import { SubCategories } from "$lib/components/molecules";
import { CategoryCreateModal } from "$lib/components/organisms";
import { getCategoryInfo, type CategoryInfo } from "$lib/modules/filesystem";
import { getCategoryInfo, type CategoryInfo } from "$lib/modules/filesystem2.svelte";
import { masterKeyStore } from "$lib/stores";
import { requestCategoryCreation } from "./service";
@@ -14,46 +13,48 @@
let { onAddToCategoryClick, isOpen = $bindable() }: Props = $props();
let category: Writable<CategoryInfo | null> | undefined = $state();
let categoryInfoPromise: Promise<CategoryInfo | null> | undefined = $state();
let isCategoryCreateModalOpen = $state(false);
$effect(() => {
if (isOpen) {
category = getCategoryInfo("root", $masterKeyStore?.get(1)?.key!);
categoryInfoPromise = getCategoryInfo("root", $masterKeyStore?.get(1)?.key!);
}
});
</script>
{#if $category}
<BottomSheet bind:isOpen class="flex flex-col">
<FullscreenDiv>
<SubCategories
class="py-4"
info={$category}
onSubCategoryClick={({ id }) =>
(category = getCategoryInfo(id, $masterKeyStore?.get(1)?.key!))}
onSubCategoryCreateClick={() => (isCategoryCreateModalOpen = true)}
subCategoryCreatePosition="top"
/>
{#if $category.id !== "root"}
<BottomDiv>
<Button onclick={() => onAddToCategoryClick($category.id)} class="w-full">
이 카테고리에 추가하기
</Button>
</BottomDiv>
{/if}
</FullscreenDiv>
</BottomSheet>
{/if}
{#await categoryInfoPromise then categoryInfo}
{#if categoryInfo}
<BottomSheet bind:isOpen class="flex flex-col">
<FullscreenDiv>
<SubCategories
class="py-4"
info={categoryInfo}
onSubCategoryClick={({ id }) =>
(categoryInfoPromise = getCategoryInfo(id, $masterKeyStore?.get(1)?.key!))}
onSubCategoryCreateClick={() => (isCategoryCreateModalOpen = true)}
subCategoryCreatePosition="top"
/>
{#if categoryInfo.id !== "root"}
<BottomDiv>
<Button onclick={() => onAddToCategoryClick(categoryInfo.id)} class="w-full">
이 카테고리에 추가하기
</Button>
</BottomDiv>
{/if}
</FullscreenDiv>
</BottomSheet>
<CategoryCreateModal
bind:isOpen={isCategoryCreateModalOpen}
onCreateClick={async (name: string) => {
if (await requestCategoryCreation(name, $category!.id, $masterKeyStore?.get(1)!)) {
category = getCategoryInfo($category!.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
return true;
}
return false;
}}
/>
<CategoryCreateModal
bind:isOpen={isCategoryCreateModalOpen}
onCreateClick={async (name: string) => {
if (await requestCategoryCreation(name, categoryInfo.id, $masterKeyStore?.get(1)!)) {
categoryInfoPromise = getCategoryInfo(categoryInfo.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
return true;
}
return false;
}}
/>
{/if}
{/await}

View File

@@ -1,9 +1,8 @@
<script lang="ts">
import type { Writable } from "svelte/store";
import { goto } from "$app/navigation";
import { TopBar } from "$lib/components/molecules";
import { Category, CategoryCreateModal } from "$lib/components/organisms";
import { getCategoryInfo, updateCategoryInfo, type CategoryInfo } from "$lib/modules/filesystem";
import { getCategoryInfo, type CategoryInfo } from "$lib/modules/filesystem2.svelte";
import { masterKeyStore } from "$lib/stores";
import CategoryDeleteModal from "./CategoryDeleteModal.svelte";
import CategoryMenuBottomSheet from "./CategoryMenuBottomSheet.svelte";
@@ -19,9 +18,7 @@
let { data } = $props();
let context = createContext();
let info: Writable<CategoryInfo | null> | undefined = $state();
let isFileRecursive: boolean | undefined = $state();
let infoPromise: Promise<CategoryInfo> | undefined = $state();
let isCategoryCreateModalOpen = $state(false);
let isCategoryMenuBottomSheetOpen = $state(false);
@@ -29,20 +26,7 @@
let isCategoryDeleteModalOpen = $state(false);
$effect(() => {
info = getCategoryInfo(data.id, $masterKeyStore?.get(1)?.key!);
isFileRecursive = undefined;
});
$effect(() => {
if ($info && isFileRecursive === undefined) {
isFileRecursive = $info.isFileRecursive ?? false;
}
});
$effect(() => {
if (data.id !== "root" && $info?.isFileRecursive !== isFileRecursive) {
updateCategoryInfo(data.id as number, { isFileRecursive });
}
infoPromise = getCategoryInfo(data.id, $masterKeyStore?.get(1)?.key!);
});
</script>
@@ -50,68 +34,70 @@
<title>카테고리</title>
</svelte:head>
{#if data.id !== "root"}
<TopBar title={$info?.name} />
{/if}
<div class="min-h-full bg-gray-100 pb-[5.5em]">
{#if $info && isFileRecursive !== undefined}
<Category
bind:isFileRecursive
info={$info}
onFileClick={({ id }) => goto(`/file/${id}?from=category`)}
onFileRemoveClick={async ({ id }) => {
await requestFileRemovalFromCategory(id, data.id as number);
info = getCategoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
{#await infoPromise then info}
{#if info}
{#if info.id !== "root"}
<TopBar title={info.name} />
{/if}
<div class="min-h-full bg-gray-100 pb-[5.5em]">
<Category
bind:isFileRecursive={info.isFileRecursive}
{info}
onFileClick={({ id }) => goto(`/file/${id}?from=category`)}
onFileRemoveClick={async ({ id }) => {
await requestFileRemovalFromCategory(id, data.id as number);
infoPromise = getCategoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
}}
onSubCategoryClick={({ id }) => goto(`/category/${id}`)}
onSubCategoryCreateClick={() => (isCategoryCreateModalOpen = true)}
onSubCategoryMenuClick={(subCategory) => {
context.selectedCategory = subCategory;
isCategoryMenuBottomSheetOpen = true;
}}
/>
</div>
<CategoryCreateModal
bind:isOpen={isCategoryCreateModalOpen}
onCreateClick={async (name: string) => {
if (await requestCategoryCreation(name, data.id, $masterKeyStore?.get(1)!)) {
infoPromise = getCategoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
return true;
}
return false;
}}
onSubCategoryClick={({ id }) => goto(`/category/${id}`)}
onSubCategoryCreateClick={() => (isCategoryCreateModalOpen = true)}
onSubCategoryMenuClick={(subCategory) => {
context.selectedCategory = subCategory;
isCategoryMenuBottomSheetOpen = true;
/>
<CategoryMenuBottomSheet
bind:isOpen={isCategoryMenuBottomSheetOpen}
onRenameClick={() => {
isCategoryMenuBottomSheetOpen = false;
isCategoryRenameModalOpen = true;
}}
onDeleteClick={() => {
isCategoryMenuBottomSheetOpen = false;
isCategoryDeleteModalOpen = true;
}}
/>
<CategoryRenameModal
bind:isOpen={isCategoryRenameModalOpen}
onRenameClick={async (newName: string) => {
if (await requestCategoryRename(context.selectedCategory!, newName)) {
infoPromise = getCategoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
return true;
}
return false;
}}
/>
<CategoryDeleteModal
bind:isOpen={isCategoryDeleteModalOpen}
onDeleteClick={async () => {
if (await requestCategoryDeletion(context.selectedCategory!)) {
infoPromise = getCategoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
return true;
}
return false;
}}
/>
{/if}
</div>
<CategoryCreateModal
bind:isOpen={isCategoryCreateModalOpen}
onCreateClick={async (name: string) => {
if (await requestCategoryCreation(name, data.id, $masterKeyStore?.get(1)!)) {
info = getCategoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
return true;
}
return false;
}}
/>
<CategoryMenuBottomSheet
bind:isOpen={isCategoryMenuBottomSheetOpen}
onRenameClick={() => {
isCategoryMenuBottomSheetOpen = false;
isCategoryRenameModalOpen = true;
}}
onDeleteClick={() => {
isCategoryMenuBottomSheetOpen = false;
isCategoryDeleteModalOpen = true;
}}
/>
<CategoryRenameModal
bind:isOpen={isCategoryRenameModalOpen}
onRenameClick={async (newName: string) => {
if (await requestCategoryRename(context.selectedCategory!, newName)) {
info = getCategoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
return true;
}
return false;
}}
/>
<CategoryDeleteModal
bind:isOpen={isCategoryDeleteModalOpen}
onDeleteClick={async () => {
if (await requestCategoryDeletion(context.selectedCategory!)) {
info = getCategoryInfo(data.id, $masterKeyStore?.get(1)?.key!); // TODO: FIXME
return true;
}
return false;
}}
/>
{/await}

View File

@@ -17,12 +17,17 @@ export const useContext = () => {
};
export const requestCategoryRename = async (category: SelectedCategory, newName: string) => {
const newNameEncrypted = await encryptString(newName, category.dataKey);
if (!category.dataKey) {
// TODO: Error Handling
return false;
}
const newNameEncrypted = await encryptString(newName, category.dataKey.key);
try {
await trpc().category.rename.mutate({
id: category.id,
dekVersion: category.dataKeyVersion,
dekVersion: category.dataKey.version,
name: newNameEncrypted.ciphertext,
nameIv: newNameEncrypted.iv,
});

View File

@@ -39,7 +39,7 @@
details,
});
const entries = $derived([
let entries = $derived([
...(showParentEntry ? ([{ type: "parent" }] as const) : []),
...sortEntries(info.subDirectories.map(toEntry("directory"))),
...sortEntries([

View File

@@ -35,7 +35,13 @@
actionButtonIcon={IconMoreVert}
onActionButtonClick={() => action(onOpenMenuClick)}
>
{#await thumbnailPromise then thumbnail}
{#await thumbnailPromise}
<DirectoryEntryLabel
type="file"
name={info.name}
subtext={formatDateTime(info.createdAt ?? info.lastModifiedAt)}
/>
{:then thumbnail}
<DirectoryEntryLabel
type="file"
thumbnail={thumbnail ?? undefined}

View File

@@ -98,7 +98,6 @@ export const requestFileUpload = async (
export const requestEntryRename = async (entry: SelectedEntry, newName: string) => {
if (!entry.dataKey) {
// TODO: Error Handling
console.log("hi");
return false;
}