@unciatech/file-manager 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +251 -0
- package/dist/index.d.mts +292 -0
- package/dist/index.d.ts +292 -0
- package/dist/index.js +116 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +116 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# 🗂️ File Manager
|
|
2
|
+
|
|
3
|
+
A robust, production-ready React / Next.js file management system designed to mirror the capabilities of professional asset managers (like Google Drive, macOS Finder, or Strapi Media Library).
|
|
4
|
+
|
|
5
|
+
It supports deep folder nesting, drag-and-drop file uploads, metadata management for various file types (Images, Videos, Audio, Documents), unified grid layouts, and fully optimized loading states.
|
|
6
|
+
|
|
7
|
+
## 🌟 Key Features
|
|
8
|
+
- **Dual Operating Modes**: Use it as a standalone full-page media library or instantiate it as a picker modal for form inputs.
|
|
9
|
+
- **Unified Grid View**: Beautiful, responsive layout that intelligently renders thumbnails, icons, and metadata based on the file's MIME type.
|
|
10
|
+
- **Nested Folder Structure**: Infinite folder depth with smooth virtualized/paginated fetching.
|
|
11
|
+
- **Provider Agnostic**: Built on an `IFileManagerProvider` interface. You can easily hot-swap the mock data provider for a real backend (Node.js, Supabase, Strapi, etc.).
|
|
12
|
+
- **Bulk Actions**: Select multiple files/folders at once to bulk move or bulk delete.
|
|
13
|
+
- **Optimistic UI Updates**: Instant visual feedback when renaming folders or updating file descriptions, with silent background synchronization.
|
|
14
|
+
- **Graceful Error Handling**: Resilient `<FileManagerErrorBoundary>` that captures catastrophic failures and allows users to hard-reload safely without app crashes.
|
|
15
|
+
|
|
16
|
+
## 🛠️ Tech Stack
|
|
17
|
+
- **Framework**: Next.js / React
|
|
18
|
+
- **Styling**: Tailwind CSS
|
|
19
|
+
- **Icons**: Lucide React
|
|
20
|
+
- **Notifications**: Sonner
|
|
21
|
+
|
|
22
|
+
## 🚀 How to Install and Use in Your Project
|
|
23
|
+
|
|
24
|
+
If you want to integrate this File Manager into your own Next.js or React application, follow this step-by-step guide.
|
|
25
|
+
|
|
26
|
+
### Step 1: Copy the Core Files
|
|
27
|
+
Copy the `components`, `types`, `hooks`, `context`, and `providers` folders related to the file manager into your project's source directory (e.g., `src/`).
|
|
28
|
+
|
|
29
|
+
### Step 2: Create your Custom API Provider
|
|
30
|
+
|
|
31
|
+
The file manager is completely agnostic to your backend database. You simply need to create a class that implements the `IFileManagerProvider` interface.
|
|
32
|
+
|
|
33
|
+
Here is an example of what your custom provider might look like, making real API calls to your backend using `fetch`:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// lib/my-api-provider.ts
|
|
37
|
+
import {
|
|
38
|
+
IFileManagerProvider,
|
|
39
|
+
FolderId,
|
|
40
|
+
FileUploadInput
|
|
41
|
+
} from "@/types/file-manager";
|
|
42
|
+
|
|
43
|
+
export class MyCustomApiProvider implements IFileManagerProvider {
|
|
44
|
+
private baseUrl = "https://api.mybackend.com/v1";
|
|
45
|
+
|
|
46
|
+
// Example 1: Fetching folders from your Real API
|
|
47
|
+
async getFolders(folderId: FolderId, page = 1, limit = 24) {
|
|
48
|
+
const parentQuery = folderId ? `&parentId=${folderId}` : "&isRoot=true";
|
|
49
|
+
|
|
50
|
+
// Simulate real API Call
|
|
51
|
+
const res = await fetch(`${this.baseUrl}/folders?page=${page}&limit=${limit}${parentQuery}`);
|
|
52
|
+
|
|
53
|
+
if (!res.ok) throw new Error("Failed to fetch folders");
|
|
54
|
+
|
|
55
|
+
const data = await res.json();
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
folders: data.folders, // Array of Folder objects matching our interface
|
|
59
|
+
pagination: data.pagination // { currentPage, totalPages, totalFiles, filesPerPage }
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Example 2: Uploading files via multipart/form-data
|
|
64
|
+
async uploadFiles(filesInput: FileUploadInput[], folderId?: FolderId) {
|
|
65
|
+
const formData = new FormData();
|
|
66
|
+
if (folderId) formData.append("folderId", String(folderId));
|
|
67
|
+
|
|
68
|
+
filesInput.forEach(({ file }) => {
|
|
69
|
+
formData.append("files", file);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const res = await fetch(`${this.baseUrl}/upload`, {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
body: formData
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
return res.json(); // Returns array of FileMetaData
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ... Implement the remaining interface methods (getFiles, renameFolder, bulkMove, etc.)
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
> **💡 Pro Tip - The Mock Provider:**
|
|
85
|
+
> If you are just prototyping and don't have a backend ready yet, you can skip Step 2 entirely! We included a fully functional `MockFileManagerProvider` that fakes network latency and stores data in memory. Just import it and use it right away to see the UI in action.
|
|
86
|
+
|
|
87
|
+
### Step 3: Wrap Your Page with the Provider
|
|
88
|
+
|
|
89
|
+
Finally, import your provider and wrap the `<FileManager />` component in the Context Provider. Define which file types you want to allow.
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
// app/media/page.tsx
|
|
93
|
+
import { FileManagerProvider } from "@/context/file-manager-context";
|
|
94
|
+
import { FileManager } from "@/components/file-manager";
|
|
95
|
+
|
|
96
|
+
// Import your real provider OR the mock one
|
|
97
|
+
import { MyCustomApiProvider } from "@/lib/my-api-provider";
|
|
98
|
+
// import { MockFileManagerProvider } from "@/providers/mock-provider";
|
|
99
|
+
|
|
100
|
+
export default function MediaLibraryPage() {
|
|
101
|
+
// Instantiate the provider
|
|
102
|
+
const apiProvider = new MyCustomApiProvider();
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<div className="h-screen w-full">
|
|
106
|
+
<FileManagerProvider
|
|
107
|
+
mode="page"
|
|
108
|
+
selectionMode="multiple"
|
|
109
|
+
allowedFileTypes={["images", "videos", "audios", "files"]}
|
|
110
|
+
provider={apiProvider}
|
|
111
|
+
>
|
|
112
|
+
<FileManager />
|
|
113
|
+
</FileManagerProvider>
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 💾 Database Schema Design
|
|
122
|
+
|
|
123
|
+
Because this application relies heavily on tree structures (Folders inside Folders) and varied JSON metadata (Video durations vs Document page counts), using a relational database with JSONB support (like PostgreSQL) is highly recommended.
|
|
124
|
+
|
|
125
|
+
Below are production-ready schema examples using **Prisma** and **Drizzle ORM**.
|
|
126
|
+
|
|
127
|
+
### Option A: Prisma Schema (PostgreSQL/MySQL)
|
|
128
|
+
|
|
129
|
+
```prisma
|
|
130
|
+
generator client {
|
|
131
|
+
provider = "prisma-client-js"
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
datasource db {
|
|
135
|
+
provider = "postgresql" // or "mysql"
|
|
136
|
+
url = env("DATABASE_URL")
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
model Folder {
|
|
140
|
+
id Int @id @default(autoincrement())
|
|
141
|
+
name String
|
|
142
|
+
|
|
143
|
+
// Self-referencing relationship for infinite folder depth
|
|
144
|
+
parentId Int?
|
|
145
|
+
parent Folder? @relation("FolderHierarchy", fields: [parentId], references: [id])
|
|
146
|
+
children Folder[] @relation("FolderHierarchy")
|
|
147
|
+
|
|
148
|
+
// Cached counts for fast UI rendering
|
|
149
|
+
folderCount Int @default(0)
|
|
150
|
+
fileCount Int @default(0)
|
|
151
|
+
|
|
152
|
+
// Path optimization
|
|
153
|
+
pathId Int @default(0)
|
|
154
|
+
path String? // e.g. "/1/5/12"
|
|
155
|
+
|
|
156
|
+
createdAt DateTime @default(now())
|
|
157
|
+
updatedAt DateTime @updatedAt
|
|
158
|
+
|
|
159
|
+
files File[]
|
|
160
|
+
|
|
161
|
+
@@index([parentId])
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
model File {
|
|
165
|
+
id Int @id @default(autoincrement())
|
|
166
|
+
name String
|
|
167
|
+
|
|
168
|
+
// Foreign Key to Folder
|
|
169
|
+
folderId Int?
|
|
170
|
+
folder Folder? @relation(fields: [folderId], references: [id], onDelete: Cascade)
|
|
171
|
+
folderPath String?
|
|
172
|
+
|
|
173
|
+
// Core Asset Data
|
|
174
|
+
size Int
|
|
175
|
+
url String
|
|
176
|
+
previewUrl String? // Lightweight thumbnail URL
|
|
177
|
+
mime String // e.g. "image/jpeg", "video/mp4"
|
|
178
|
+
ext String?
|
|
179
|
+
hash String?
|
|
180
|
+
|
|
181
|
+
// Common Media Details
|
|
182
|
+
alternativeText String?
|
|
183
|
+
caption String?
|
|
184
|
+
width Int?
|
|
185
|
+
height Int?
|
|
186
|
+
|
|
187
|
+
// JSONB storage for flexible metadata
|
|
188
|
+
// (e.g., formats: { thumbnail: {...}, small: {...} })
|
|
189
|
+
formats Json?
|
|
190
|
+
// (e.g., metaData: { duration: 120, bitrate: 320, pageCount: 15 })
|
|
191
|
+
metaData Json?
|
|
192
|
+
|
|
193
|
+
createdAt DateTime @default(now())
|
|
194
|
+
updatedAt DateTime @updatedAt
|
|
195
|
+
|
|
196
|
+
@@index([folderId])
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
### Option B: Drizzle ORM Schema (PostgreSQL)
|
|
202
|
+
|
|
203
|
+
If you prefer a lighter, TypeScript-first approach using Drizzle:
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
import { pgTable, serial, varchar, integer, timestamp, jsonb, text } from "drizzle-orm/pg-core";
|
|
207
|
+
|
|
208
|
+
export const folders = pgTable("folders", {
|
|
209
|
+
id: serial("id").primaryKey(),
|
|
210
|
+
name: varchar("name", { length: 255 }).notNull(),
|
|
211
|
+
|
|
212
|
+
// Nullable parentId allows root-level folders
|
|
213
|
+
parentId: integer("parent_id"), // Needs recursive FK setup in relations
|
|
214
|
+
|
|
215
|
+
folderCount: integer("folder_count").default(0),
|
|
216
|
+
fileCount: integer("file_count").default(0),
|
|
217
|
+
|
|
218
|
+
pathId: integer("path_id").default(0),
|
|
219
|
+
path: varchar("path", { length: 255 }),
|
|
220
|
+
|
|
221
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
222
|
+
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
export const files = pgTable("files", {
|
|
226
|
+
id: serial("id").primaryKey(),
|
|
227
|
+
name: varchar("name", { length: 255 }).notNull(),
|
|
228
|
+
|
|
229
|
+
folderId: integer("folder_id").references(() => folders.id, { onDelete: "cascade" }),
|
|
230
|
+
folderPath: varchar("folder_path", { length: 255 }),
|
|
231
|
+
|
|
232
|
+
size: integer("size").notNull(),
|
|
233
|
+
url: text("url").notNull(),
|
|
234
|
+
previewUrl: text("preview_url"),
|
|
235
|
+
mime: varchar("mime", { length: 100 }).notNull(),
|
|
236
|
+
ext: varchar("ext", { length: 20 }),
|
|
237
|
+
hash: varchar("hash", { length: 255 }),
|
|
238
|
+
|
|
239
|
+
alternativeText: text("alternative_text"),
|
|
240
|
+
caption: text("caption"),
|
|
241
|
+
width: integer("width"),
|
|
242
|
+
height: integer("height"),
|
|
243
|
+
|
|
244
|
+
// JSONB is perfect for storing our dynamic metadata & responsive formats
|
|
245
|
+
formats: jsonb("formats"),
|
|
246
|
+
metaData: jsonb("meta_data"),
|
|
247
|
+
|
|
248
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
249
|
+
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
|
250
|
+
});
|
|
251
|
+
```
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
type FileUploadInput = {
|
|
4
|
+
file: File;
|
|
5
|
+
metadata: Partial<FileMetaData>;
|
|
6
|
+
videoSource?: VideoSource;
|
|
7
|
+
};
|
|
8
|
+
interface IFileManagerProvider {
|
|
9
|
+
getFolder(folderId: FolderId): Promise<Folder | null>;
|
|
10
|
+
getFolders(folderId: FolderId, page?: number, limit?: number, query?: string): Promise<{
|
|
11
|
+
folders: Folder[];
|
|
12
|
+
pagination: PaginationInfo;
|
|
13
|
+
}>;
|
|
14
|
+
getTags(): Promise<string[]>;
|
|
15
|
+
getFiles(folderId: FolderId, fileTypes?: FileType[] | null, page?: number, limit?: number, query?: string): Promise<{
|
|
16
|
+
files: FileMetaData[];
|
|
17
|
+
pagination: PaginationInfo;
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* Get files and folders separately (folders always come first)
|
|
21
|
+
* Folders are returned for the current page, followed by files
|
|
22
|
+
*/
|
|
23
|
+
getItems(folderId: FolderId, fileTypes?: FileType[], page?: number, limit?: number, query?: string): Promise<{
|
|
24
|
+
folders: Folder[];
|
|
25
|
+
files: FileMetaData[];
|
|
26
|
+
pagination: PaginationInfo;
|
|
27
|
+
}>;
|
|
28
|
+
createFolder(name: string, parentId?: FolderId): Promise<Folder>;
|
|
29
|
+
uploadFiles(files: FileUploadInput[], folderId?: FolderId): Promise<FileMetaData[]>;
|
|
30
|
+
renameFolder(folderId: FolderId, newName: string): Promise<Folder>;
|
|
31
|
+
moveFiles(fileIds: EntityId[], newFolderId: FolderId): Promise<FileMetaData[]>;
|
|
32
|
+
moveFolders(folderIds: FolderId[], newParentId: FolderId): Promise<Folder[]>;
|
|
33
|
+
updateFileMetaData(fileId: EntityId, metaData: Partial<FileMetaData>): Promise<FileMetaData>;
|
|
34
|
+
deleteFiles(fileIds: EntityId[]): Promise<void>;
|
|
35
|
+
deleteFolders(folderIds: FolderId[]): Promise<void>;
|
|
36
|
+
findFiles(searchQuery: string): Promise<FileMetaData[]>;
|
|
37
|
+
findFolders(searchQuery: string): Promise<Folder[]>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
declare const MODE: {
|
|
41
|
+
readonly PAGE: "page";
|
|
42
|
+
readonly MODAL: "modal";
|
|
43
|
+
};
|
|
44
|
+
type Mode = (typeof MODE)[keyof typeof MODE];
|
|
45
|
+
declare const FILE_TYPE: {
|
|
46
|
+
readonly IMAGE: "images";
|
|
47
|
+
readonly VIDEO: "videos";
|
|
48
|
+
readonly AUDIO: "audios";
|
|
49
|
+
readonly FILE: "files";
|
|
50
|
+
};
|
|
51
|
+
type FileType = (typeof FILE_TYPE)[keyof typeof FILE_TYPE];
|
|
52
|
+
declare const SELECTION_MODE: {
|
|
53
|
+
readonly SINGLE: "single";
|
|
54
|
+
readonly MULTIPLE: "multiple";
|
|
55
|
+
};
|
|
56
|
+
type SelectionMode = (typeof SELECTION_MODE)[keyof typeof SELECTION_MODE];
|
|
57
|
+
declare const VIEW_MODE: {
|
|
58
|
+
readonly GRID: "grid";
|
|
59
|
+
readonly LIST: "list";
|
|
60
|
+
};
|
|
61
|
+
type ViewMode = (typeof VIEW_MODE)[keyof typeof VIEW_MODE];
|
|
62
|
+
declare const VIDEO_SOURCE: {
|
|
63
|
+
readonly LOCAL: "local";
|
|
64
|
+
readonly REMOTE: "remote";
|
|
65
|
+
readonly YOUTUBE: "youtube";
|
|
66
|
+
readonly VIMEO: "vimeo";
|
|
67
|
+
};
|
|
68
|
+
type VideoSource = (typeof VIDEO_SOURCE)[keyof typeof VIDEO_SOURCE];
|
|
69
|
+
interface MetaDataType {
|
|
70
|
+
/** Video or Audio duration in seconds. */
|
|
71
|
+
duration?: number;
|
|
72
|
+
/** Provider source for video content (e.g., 'local', 'youtube'). */
|
|
73
|
+
videoSource?: VideoSource;
|
|
74
|
+
/** Audio bitrate in kbps. */
|
|
75
|
+
bitrate?: number;
|
|
76
|
+
/** Total number of pages for document file types. */
|
|
77
|
+
pageCount?: number;
|
|
78
|
+
/** Original creator or author of the document. */
|
|
79
|
+
author?: string;
|
|
80
|
+
/** General description text used across multiple asset types. */
|
|
81
|
+
description?: string;
|
|
82
|
+
}
|
|
83
|
+
type EntityId = string | number;
|
|
84
|
+
type FolderId = string | number | null;
|
|
85
|
+
interface Folder {
|
|
86
|
+
id: FolderId;
|
|
87
|
+
name: string;
|
|
88
|
+
pathId: number;
|
|
89
|
+
path: string;
|
|
90
|
+
parent?: Folder | null;
|
|
91
|
+
folderCount?: number;
|
|
92
|
+
parentId: FolderId;
|
|
93
|
+
folderPath?: string;
|
|
94
|
+
color?: string;
|
|
95
|
+
fileCount?: number;
|
|
96
|
+
createdAt: Date;
|
|
97
|
+
updatedAt: Date;
|
|
98
|
+
tags?: string[];
|
|
99
|
+
}
|
|
100
|
+
interface FormatDetails {
|
|
101
|
+
ext: string;
|
|
102
|
+
url: string;
|
|
103
|
+
hash: string;
|
|
104
|
+
mime: string;
|
|
105
|
+
name: string;
|
|
106
|
+
path: string | null;
|
|
107
|
+
size: number;
|
|
108
|
+
width: number;
|
|
109
|
+
height: number;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Core interface representing a File entity in the file manager.
|
|
113
|
+
* Supports various formats (images, videos, audio, documents) via common fields
|
|
114
|
+
* and nested metadata structures.
|
|
115
|
+
*/
|
|
116
|
+
interface FileMetaData {
|
|
117
|
+
/** Unique identifier for the file. */
|
|
118
|
+
id: EntityId;
|
|
119
|
+
/** Human-readable name of the file (including extension). */
|
|
120
|
+
name: string;
|
|
121
|
+
/** ID of the folder containing this file. Null represents the root directory. */
|
|
122
|
+
folderId: FolderId;
|
|
123
|
+
/** Path representation of the file's location (e.g., "/1/156"). */
|
|
124
|
+
folderPath?: string;
|
|
125
|
+
/** Size of the file in bytes. */
|
|
126
|
+
size: number;
|
|
127
|
+
/** Direct URL path to access or download the full asset. */
|
|
128
|
+
url: string;
|
|
129
|
+
/** URL to an optimized, lightweight thumbnail or preview of the asset. */
|
|
130
|
+
previewUrl?: string;
|
|
131
|
+
/** Content-Type HTTP header representation (e.g., "image/jpeg"). */
|
|
132
|
+
mime: string;
|
|
133
|
+
/** File extension including the dot (e.g., ".jpg"). */
|
|
134
|
+
ext?: string;
|
|
135
|
+
/** Content hash for deduplication and cache busting. */
|
|
136
|
+
hash?: string;
|
|
137
|
+
/** Accessible alt text for images to display when images are disabled. */
|
|
138
|
+
alternativeText?: string;
|
|
139
|
+
/** Caption text commonly used in images and videos. */
|
|
140
|
+
caption?: string;
|
|
141
|
+
/** Intrinsic width in pixels for image/video assets. */
|
|
142
|
+
width?: number;
|
|
143
|
+
/** Intrinsic height in pixels for image/video assets. */
|
|
144
|
+
height?: number;
|
|
145
|
+
/** Collection of generated optimized formats for images. */
|
|
146
|
+
formats?: Record<string, FormatDetails>;
|
|
147
|
+
/** Dynamic metadata payload containing properties specific to the asset type. */
|
|
148
|
+
metaData: MetaDataType;
|
|
149
|
+
/** Timestamp of file creation. */
|
|
150
|
+
createdAt: Date;
|
|
151
|
+
/** Timestamp of last file modification. */
|
|
152
|
+
updatedAt: Date;
|
|
153
|
+
/** Categorization tags for sorting and discovery. */
|
|
154
|
+
tags?: string[];
|
|
155
|
+
}
|
|
156
|
+
interface PaginationInfo {
|
|
157
|
+
currentPage: number;
|
|
158
|
+
totalPages: number;
|
|
159
|
+
totalFiles: number;
|
|
160
|
+
filesPerPage: number;
|
|
161
|
+
}
|
|
162
|
+
interface FileManagerPageProps {
|
|
163
|
+
allowedFileTypes: FileType[];
|
|
164
|
+
viewMode: ViewMode;
|
|
165
|
+
initialFolderId?: FolderId;
|
|
166
|
+
provider: IFileManagerProvider;
|
|
167
|
+
basePath?: string;
|
|
168
|
+
}
|
|
169
|
+
interface FileManagerModalProps {
|
|
170
|
+
open: boolean;
|
|
171
|
+
onClose: () => void;
|
|
172
|
+
onFilesSelected: (files: FileMetaData[]) => void;
|
|
173
|
+
fileSelectionMode?: SelectionMode;
|
|
174
|
+
allowedFileTypes: FileType[];
|
|
175
|
+
acceptedFileTypes?: FileType[];
|
|
176
|
+
viewMode?: ViewMode;
|
|
177
|
+
initialFolderId?: FolderId;
|
|
178
|
+
provider: IFileManagerProvider;
|
|
179
|
+
basePath?: string;
|
|
180
|
+
}
|
|
181
|
+
interface FileManagerRootProps {
|
|
182
|
+
mode: Mode;
|
|
183
|
+
selectionMode: SelectionMode;
|
|
184
|
+
allowedFileTypes: FileType[];
|
|
185
|
+
viewMode: ViewMode;
|
|
186
|
+
initialFolderId?: FolderId;
|
|
187
|
+
acceptedFileTypesForModal?: FileType[];
|
|
188
|
+
provider: IFileManagerProvider;
|
|
189
|
+
basePath?: string;
|
|
190
|
+
onFilesSelected?: (files: FileMetaData[]) => void;
|
|
191
|
+
onClose?: () => void;
|
|
192
|
+
maxUploadFiles?: number;
|
|
193
|
+
maxUploadSize?: number;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
declare function FileManager(props: FileManagerPageProps): react_jsx_runtime.JSX.Element;
|
|
197
|
+
|
|
198
|
+
declare function FileManagerModal({ open, onClose, ...props }: FileManagerModalProps): react_jsx_runtime.JSX.Element;
|
|
199
|
+
|
|
200
|
+
interface FileManagerContextType {
|
|
201
|
+
files: FileMetaData[];
|
|
202
|
+
folders: Folder[];
|
|
203
|
+
selectedFiles: FileMetaData[];
|
|
204
|
+
selectedFolders: Folder[];
|
|
205
|
+
currentFolder: Folder | null;
|
|
206
|
+
isLoading: boolean;
|
|
207
|
+
pagination: PaginationInfo;
|
|
208
|
+
isUploadModalOpen: boolean;
|
|
209
|
+
isCreateFolderModalOpen: boolean;
|
|
210
|
+
isSearchModalOpen: boolean;
|
|
211
|
+
isMoveFileModalOpen: boolean;
|
|
212
|
+
isRenameFolderModalOpen: boolean;
|
|
213
|
+
fileDetailsModalFile: FileMetaData | null;
|
|
214
|
+
folderToRename: Folder | null;
|
|
215
|
+
mode: Mode;
|
|
216
|
+
selectionMode: SelectionMode;
|
|
217
|
+
allowedFileTypes: FileType[];
|
|
218
|
+
acceptedFileTypesForModal?: FileType[];
|
|
219
|
+
maxUploadFiles: number;
|
|
220
|
+
maxUploadSize: number;
|
|
221
|
+
provider: IFileManagerProvider;
|
|
222
|
+
basePath?: string;
|
|
223
|
+
setSelectedFiles: (files: FileMetaData[]) => void;
|
|
224
|
+
setSelectedFolders: (folders: Folder[]) => void;
|
|
225
|
+
setIsUploadModalOpen: (isOpen: boolean) => void;
|
|
226
|
+
setIsCreateFolderModalOpen: (isOpen: boolean) => void;
|
|
227
|
+
setIsSearchModalOpen: (isOpen: boolean) => void;
|
|
228
|
+
setIsMoveFileModalOpen: (isOpen: boolean) => void;
|
|
229
|
+
setIsRenameFolderModalOpen: (isOpen: boolean) => void;
|
|
230
|
+
setFileDetailsModalFile: (file: FileMetaData | null) => void;
|
|
231
|
+
setFolderToRename: (folder: Folder | null) => void;
|
|
232
|
+
handleFileClick: (file: FileMetaData, event?: React.MouseEvent, isCheckboxClick?: boolean) => void;
|
|
233
|
+
handleFolderClick: (folder: Folder | null, event?: React.MouseEvent, isCheckboxClick?: boolean) => void;
|
|
234
|
+
handleClearSelection: () => void;
|
|
235
|
+
handleSelectAllGlobal: (checked: boolean) => void;
|
|
236
|
+
handlePageChange: (page: number) => void;
|
|
237
|
+
searchQuery: string;
|
|
238
|
+
updateSearchQuery: (query: string) => void;
|
|
239
|
+
uploadFiles: (fileUploadInput: FileUploadInput[]) => Promise<void>;
|
|
240
|
+
createFolder: (name: string) => Promise<void>;
|
|
241
|
+
bulkMove: (targetFolderId: FolderId) => Promise<void>;
|
|
242
|
+
renameFolder: (folderId: EntityId, newName: string) => Promise<void>;
|
|
243
|
+
updateFileMetadata: (fileId: EntityId, metadata: Partial<FileMetaData>) => Promise<void>;
|
|
244
|
+
bulkDelete: () => Promise<void>;
|
|
245
|
+
refreshData: () => Promise<void>;
|
|
246
|
+
isInSelectionMode: () => boolean;
|
|
247
|
+
getCurrentFolder: () => Folder | null;
|
|
248
|
+
getSelectionState: () => boolean | "indeterminate";
|
|
249
|
+
onClose?: () => void;
|
|
250
|
+
onFilesSelected?: (files: FileMetaData[]) => void;
|
|
251
|
+
}
|
|
252
|
+
declare function FileManagerProvider({ children, mode, selectionMode, allowedFileTypes, onFilesSelected, onClose, acceptedFileTypesForModal, initialFolderId, provider, basePath, maxUploadFiles, maxUploadSize, }: FileManagerRootProps & {
|
|
253
|
+
children: React.ReactNode;
|
|
254
|
+
}): react_jsx_runtime.JSX.Element;
|
|
255
|
+
declare function useFileManager(): FileManagerContextType;
|
|
256
|
+
|
|
257
|
+
declare class MockProvider implements IFileManagerProvider {
|
|
258
|
+
getFolder(folderId: FolderId): Promise<Folder | null>;
|
|
259
|
+
getFolders(folderId: FolderId, page?: number, limit?: number, query?: string): Promise<{
|
|
260
|
+
folders: Folder[];
|
|
261
|
+
pagination: PaginationInfo;
|
|
262
|
+
}>;
|
|
263
|
+
getTags(): Promise<string[]>;
|
|
264
|
+
getFiles(folderId: FolderId, fileTypes?: FileType[], page?: number, limit?: number, query?: string): Promise<{
|
|
265
|
+
files: FileMetaData[];
|
|
266
|
+
pagination: PaginationInfo;
|
|
267
|
+
}>;
|
|
268
|
+
/**
|
|
269
|
+
* Get files and folders separately (folders always come first)
|
|
270
|
+
* Folders are not paginated (all folders in current directory are returned)
|
|
271
|
+
* Files are paginated after folders
|
|
272
|
+
*/
|
|
273
|
+
getItems(folderId: FolderId, fileTypes?: FileType[], page?: number, limit?: number, query?: string): Promise<{
|
|
274
|
+
folders: Folder[];
|
|
275
|
+
files: FileMetaData[];
|
|
276
|
+
pagination: PaginationInfo;
|
|
277
|
+
}>;
|
|
278
|
+
createFolder(name: string, parentId?: FolderId): Promise<Folder>;
|
|
279
|
+
private getMetaDataType;
|
|
280
|
+
private getFileType;
|
|
281
|
+
uploadFiles(files: FileUploadInput[], folderId?: FolderId): Promise<FileMetaData[]>;
|
|
282
|
+
renameFolder(folderId: EntityId, newName: string): Promise<Folder>;
|
|
283
|
+
updateFileMetaData(fileId: EntityId, updates: Partial<FileMetaData>): Promise<FileMetaData>;
|
|
284
|
+
deleteFiles(fileIds: EntityId[]): Promise<void>;
|
|
285
|
+
deleteFolders(folderIds: EntityId[]): Promise<void>;
|
|
286
|
+
findFiles(searchQuery: string): Promise<FileMetaData[]>;
|
|
287
|
+
findFolders(searchQuery: string): Promise<Folder[]>;
|
|
288
|
+
moveFiles(fileIds: EntityId[], newFolderId: FolderId): Promise<FileMetaData[]>;
|
|
289
|
+
moveFolders(folderIds: FolderId[], newParentId: FolderId): Promise<Folder[]>;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export { FileManager, FileManagerModal, type FileManagerModalProps, type FileManagerPageProps, FileManagerProvider, type FileMetaData, type FileType, type Folder, type IFileManagerProvider, MockProvider, type SelectionMode, type ViewMode, useFileManager };
|