Organizing with Folders
Relevant source files
The following files were used as context for generating this wiki page:The "Organizing with Folders" feature provides a hierarchical structure for classifying and managing archived web pages. It is a core organizational component within the Web Archive application, allowing users to group related pages together. This functionality is exposed through a dedicated backend API and is integrated into both the web client for browsing and management, and the browser plugin for saving new pages.
The system supports full CRUD (Create, Read, Update, Delete) operations for folders. When a folder is deleted, all pages within that folder are also marked as deleted. The user interface provides intuitive controls for creating new folders, editing existing ones, and navigating through the folder structure to view archived content.
Data Model
The folder system is centered around the Folder and Page data models. A Page must belong to a Folder, establishing a one-to-many relationship.
Sources: packages/shared/types/model.ts:1-24
ER Diagram
The following diagram illustrates the relationship between the Folder and Page entities.
Sources: packages/shared/types/model.ts:1-24
Folder Entity
The Folder entity contains the following attributes:
| Field | Type | Description |
|---|---|---|
id | number | The unique identifier for the folder. |
name | string | The name of the folder. |
isDeleted | number | A flag indicating if the folder is deleted (0 or 1). |
deletedAt | Date | The timestamp when the folder was deleted. |
createdAt | Date | The timestamp when the folder was created. |
updatedAt | Date | The timestamp when the folder was last updated. |
Sources: packages/shared/types/model.ts:15-21
Backend API
The folder management functionality is handled by a set of RESTful API endpoints located at /api/folders. These endpoints are built using Hono and provide the backend logic for all folder-related operations.
Sources: packages/server/src/api/folders.ts
Endpoints Summary
| Method | Path | Description |
|---|---|---|
GET | /all | Get all non-deleted folders. |
POST | /create | Create a new folder. |
DELETE | /delete | Delete a folder by ID. |
PUT | /update | Update a folder's name. |
POST | /query_deleted | Get all deleted folders. |
Sources: packages/server/src/api/folders.ts:10-129
GET /api/folders/all
This endpoint retrieves a list of all folders that have not been marked as deleted.
This diagram shows the sequence for fetching all active folders.
Response Body (Success)
{
"status": "success",
"data": [
{
"id": 1,
"name": "Tech Articles",
"isDeleted": 0,
"deletedAt": null,
"createdAt": "2023-10-27T10:00:00.000Z",
"updatedAt": "2023-10-27T10:00:00.000Z"
}
]
}
Sources: packages/server/src/api/folders.ts:10-14
POST /api/folders/create
Creates a new folder with the provided name.
This diagram shows the process of creating a new folder.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | The name for the new folder. |
Sources: packages/server/src/api/folders.ts:16-36
DELETE /api/folders/delete
Deletes a folder and all associated pages by marking them as deleted in the database.
This diagram illustrates the folder deletion process, including the cascading delete effect on pages.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Yes | The ID of the folder to delete. |
The endpoint first queries all pages within the folder to verify the number of changes, then proceeds to mark both the folder and its pages as deleted.
Sources: packages/server/src/api/folders.ts:38-69
PUT /api/folders/update
Updates the name of an existing folder.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
id | number | Yes | The ID of the folder to update. |
name | string | Yes | The new name for the folder. |
If the update results in 0 changes, it checks if a folder with the new name already exists to provide a more specific error.
Sources: packages/server/src/api/folders.ts:71-100
Frontend Integration
The folder system is deeply integrated into the web client and browser plugin, providing a seamless user experience for organizing archived pages.
Web Client UI
Sidebar Folder Menu
The SidebarFolderMenu component is the primary interface for folder management in the web UI. It displays a collapsible list of all folders.
- Data Fetching: It uses the
useRequesthook fromahooksto call thegetAllFolderdata-fetching function, which in turn calls theGET /api/folders/allendpoint. - State Management: It manages the list of folders and the currently open folder.
- Actions: It provides UI triggers for creating, editing, and deleting folders through dialogs (
NewFolderDialog,EditFolderDialog) and direct API calls.
This diagram shows the component logic and data flow for the sidebar folder menu.
When a folder is deleted, the component calculates the next folder to navigate to, ensuring a smooth user experience.
// packages/web/src/components/side-bar-folder-menu.tsx:20-28
function getNextFolderId(folders: Array<FolderType>, index: number) {
if (index === 0 && folders.length === 1) {
return null
}
if (index === 0) {
return folders[index + 1].id
}
return folders[index - 1].id
}
Sources: packages/web/src/components/side-bar-folder-menu.tsx
Folder Content Page
The FolderPage at /folder/:slug displays the archived pages within a selected folder.
- Data Fetching: It uses the
useInfiniteScrollhook to fetch paginated results from thequeryPagefunction, which calls thePOST /api/pages/queryendpoint with thefolderIdfrom the URL slug. - Infinite Scroll: As the user scrolls, it automatically loads more pages.
- Search and Filter: It receives
keywordandselectedTagfrom its parent layout to filter the pages displayed.
Sources: packages/web/src/pages/(layout)/folder.[slug].tsx
Browser Plugin UI
When saving a new page, the browser plugin's popup form allows the user to select a destination folder.
- Component:
UploadPageForm.tsxcontains aFolderSelectWithCachecomponent. - Functionality: This component fetches all available folders and presents them in a dropdown/combobox. It also allows for the creation of a new folder directly from the popup.
- State: The selected
folderIdis stored in the form's state and is required for saving a page. If no folder is selected, the save button is disabled.
// packages/plugin/popup/components/UploadPageForm.tsx:90-96
async function handleSavePage() {
// todo await folderlist to check folder extists?
if (isNil(uploadPageData.folderId)) {
toast.error(t('folder-required'))
return
}
// ... rest of the save logic
}
This snippet shows the validation check ensuring a folder is selected before a page is saved.
Sources: packages/plugin/popup/components/UploadPageForm.tsx
Conclusion
The folder system is a fundamental feature of the Web Archive project, providing the primary mechanism for content organization. It is well-structured with a clear data model, a robust backend API for management, and seamless integration into both the web client and browser plugin. The design ensures that users can easily classify new and existing archived pages, making the archive scalable and easy to navigate.