@flusys/ng-storage 0.1.0-beta.1 → 0.1.0-beta.2
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 +590 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
# Storage Package Guide
|
|
2
|
+
|
|
3
|
+
> **Package:** `@flusys/ng-storage`
|
|
4
|
+
> **Type:** File storage management with upload, folder organization, and multi-provider support
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
`@flusys/ng-storage` provides complete file storage management:
|
|
11
|
+
|
|
12
|
+
- **File Upload** - Single and multiple file uploads with image compression
|
|
13
|
+
- **File Manager** - CRUD operations for file metadata with presigned URLs
|
|
14
|
+
- **Folder Management** - Folder organization for files
|
|
15
|
+
- **Storage Configs** - Multi-provider configurations (AWS S3, Azure Blob, SFTP, Local)
|
|
16
|
+
- **Company Scoping** - Automatic company-scoped queries (when enabled)
|
|
17
|
+
- **Lazy Loading** - All page components are lazy-loaded via routes
|
|
18
|
+
|
|
19
|
+
### Package Hierarchy
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
@flusys/ng-core <- Foundation (BaseApiService, APP_CONFIG)
|
|
23
|
+
|
|
|
24
|
+
@flusys/ng-shared <- Shared utilities (ApiResourceService, IBaseEntity)
|
|
25
|
+
|
|
|
26
|
+
@flusys/ng-layout <- Layout (LAYOUT_AUTH_STATE for company context)
|
|
27
|
+
|
|
|
28
|
+
@flusys/ng-storage <- File storage (THIS PACKAGE)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Company Context
|
|
32
|
+
|
|
33
|
+
Storage components use `LAYOUT_AUTH_STATE` from `@flusys/ng-layout` for company context. This follows the Provider Interface Pattern - ng-storage depends on ng-layout's abstraction, not ng-auth directly.
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';
|
|
37
|
+
|
|
38
|
+
private readonly companyContext = inject(LAYOUT_AUTH_STATE);
|
|
39
|
+
|
|
40
|
+
readonly currentCompanyName = computed(
|
|
41
|
+
() => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME,
|
|
42
|
+
);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Package Architecture
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
ng-storage/
|
|
51
|
+
├── enums/
|
|
52
|
+
│ ├── file-location.enum.ts # FileLocationEnum, ImageFormat
|
|
53
|
+
│ └── public-api.ts
|
|
54
|
+
├── interfaces/
|
|
55
|
+
│ ├── file-manager.interface.ts # IFileManager, ICreateFileManagerDto, IUpdateFileManagerDto
|
|
56
|
+
│ ├── folder.interface.ts # IFolder, ICreateFolderDto, IUpdateFolderDto
|
|
57
|
+
│ ├── storage-config.interface.ts # IStorageConfig, provider-specific configs
|
|
58
|
+
│ ├── upload.interface.ts # IUploadOptionsDto, IUploadedFileInfo
|
|
59
|
+
│ └── public-api.ts
|
|
60
|
+
├── services/
|
|
61
|
+
│ ├── file-manager-api.service.ts # File metadata CRUD + presigned URLs
|
|
62
|
+
│ ├── folder-api.service.ts # Folder CRUD
|
|
63
|
+
│ ├── storage-config-api.service.ts # Storage config CRUD
|
|
64
|
+
│ └── upload.service.ts # File upload/delete operations
|
|
65
|
+
├── pages/
|
|
66
|
+
│ ├── storage-container/
|
|
67
|
+
│ │ └── storage-container.component.ts # Tab container (Files, Folders, Configs)
|
|
68
|
+
│ ├── file-manager/
|
|
69
|
+
│ │ ├── file-manager-list.component.ts
|
|
70
|
+
│ │ └── file-manager-form.component.ts
|
|
71
|
+
│ ├── folder/
|
|
72
|
+
│ │ ├── folder-list.component.ts
|
|
73
|
+
│ │ └── folder-form.component.ts
|
|
74
|
+
│ └── storage-config/
|
|
75
|
+
│ ├── storage-config-list.component.ts
|
|
76
|
+
│ └── storage-config-form.component.ts
|
|
77
|
+
├── routes/
|
|
78
|
+
│ └── storage.routes.ts
|
|
79
|
+
└── public-api.ts
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Route Integration
|
|
85
|
+
|
|
86
|
+
### Adding Storage Routes
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// app.routes.ts
|
|
90
|
+
export const routes: Routes = [
|
|
91
|
+
{
|
|
92
|
+
path: 'storage',
|
|
93
|
+
loadChildren: () =>
|
|
94
|
+
import('@flusys/ng-storage').then((m) => m.STORAGE_ROUTES),
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Route Structure
|
|
100
|
+
|
|
101
|
+
All routes are wrapped by `StorageContainerComponent` which provides tab navigation (Files, Folders, Configs).
|
|
102
|
+
|
|
103
|
+
| Path | Component | Description |
|
|
104
|
+
|------|-----------|-------------|
|
|
105
|
+
| `/storage` | StorageContainerComponent | Container with tab navigation |
|
|
106
|
+
| `/storage/files` | FileManagerListComponent | List all files (default) |
|
|
107
|
+
| `/storage/files/new` | FileManagerFormComponent | Upload new file |
|
|
108
|
+
| `/storage/files/:id` | FileManagerFormComponent | Edit file metadata |
|
|
109
|
+
| `/storage/folders` | FolderListComponent | List all folders |
|
|
110
|
+
| `/storage/folders/new` | FolderFormComponent | Create folder |
|
|
111
|
+
| `/storage/folders/:id` | FolderFormComponent | Edit folder |
|
|
112
|
+
| `/storage/configs` | StorageConfigListComponent | List storage configurations |
|
|
113
|
+
| `/storage/configs/new` | StorageConfigFormComponent | Create storage config |
|
|
114
|
+
| `/storage/configs/:id` | StorageConfigFormComponent | Edit storage config |
|
|
115
|
+
|
|
116
|
+
Default redirect: `/storage` -> `/storage/files`
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Enums
|
|
121
|
+
|
|
122
|
+
### FileLocationEnum
|
|
123
|
+
|
|
124
|
+
Storage provider types (matches backend).
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
enum FileLocationEnum {
|
|
128
|
+
LOCAL = 'local',
|
|
129
|
+
AWS = 'aws',
|
|
130
|
+
AZURE = 'azure',
|
|
131
|
+
SFTP = 'sftp',
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### ImageFormat
|
|
136
|
+
|
|
137
|
+
Image compression output formats.
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
enum ImageFormat {
|
|
141
|
+
ORIGINAL = 'original',
|
|
142
|
+
JPEG = 'jpeg',
|
|
143
|
+
PNG = 'png',
|
|
144
|
+
WEBP = 'webp',
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Interfaces
|
|
151
|
+
|
|
152
|
+
### Upload
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
interface IUploadOptionsDto {
|
|
156
|
+
storageConfigId?: string; // Storage config to use (uses default if not set)
|
|
157
|
+
folderPath?: string; // Target folder path
|
|
158
|
+
maxWidth?: number; // Image max width (default: 1280)
|
|
159
|
+
maxHeight?: number; // Image max height (default: 1280)
|
|
160
|
+
quality?: number; // Image quality 1-100 (default: 85)
|
|
161
|
+
format?: ImageFormat; // Output format
|
|
162
|
+
compress?: boolean; // Enable compression (default: true)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
interface IUploadedFileInfo {
|
|
166
|
+
name: string; // Original filename
|
|
167
|
+
key: string; // Storage key/path
|
|
168
|
+
size: number; // File size in bytes
|
|
169
|
+
contentType: string; // MIME type
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### File Manager
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
interface IFileManager {
|
|
177
|
+
id: string;
|
|
178
|
+
createdAt: Date;
|
|
179
|
+
updatedAt: Date;
|
|
180
|
+
name: string;
|
|
181
|
+
contentType: string;
|
|
182
|
+
size: string; // In KB (string)
|
|
183
|
+
key: string; // File key/path in storage
|
|
184
|
+
url: string | null; // Presigned URL (regenerated by backend)
|
|
185
|
+
location: FileLocationEnum;
|
|
186
|
+
storageConfigId: string | null;
|
|
187
|
+
expiresAt: Date | null; // URL expiration time
|
|
188
|
+
isPrivate: boolean;
|
|
189
|
+
companyId?: string; // Only in company mode
|
|
190
|
+
folderId?: string | null;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
interface ICreateFileManagerDto {
|
|
194
|
+
name: string;
|
|
195
|
+
key: string;
|
|
196
|
+
size: string;
|
|
197
|
+
contentType: string;
|
|
198
|
+
isPrivate: boolean;
|
|
199
|
+
folderId?: string;
|
|
200
|
+
storageConfigId?: string;
|
|
201
|
+
location?: FileLocationEnum;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
interface IUpdateFileManagerDto {
|
|
205
|
+
id: string;
|
|
206
|
+
name?: string;
|
|
207
|
+
isPrivate?: boolean;
|
|
208
|
+
folderId?: string | null;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// For fetching files with valid presigned URLs
|
|
212
|
+
interface IGetFilesRequestDto { id: string; }
|
|
213
|
+
interface IFilesResponseDto { id: string; name: string; contentType: string; url: string; }
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Folder
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
interface IFolder extends IBaseEntity {
|
|
220
|
+
name: string;
|
|
221
|
+
slug: string; // URL-friendly name
|
|
222
|
+
companyId?: string | null;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
interface ICreateFolderDto { name: string; }
|
|
226
|
+
interface IUpdateFolderDto { id: string; name?: string; }
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Storage Config
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
interface IStorageConfig extends IBaseEntity {
|
|
233
|
+
name: string;
|
|
234
|
+
storage: FileLocationEnum;
|
|
235
|
+
config: Record<string, any>; // Provider-specific configuration
|
|
236
|
+
companyId?: string | null;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
interface ICreateStorageConfigDto {
|
|
240
|
+
name: string;
|
|
241
|
+
storage: FileLocationEnum;
|
|
242
|
+
config: Record<string, any>;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
interface IUpdateStorageConfigDto {
|
|
246
|
+
id: string;
|
|
247
|
+
name?: string;
|
|
248
|
+
storage?: FileLocationEnum;
|
|
249
|
+
config?: Record<string, any>;
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Provider-Specific Configs
|
|
254
|
+
|
|
255
|
+
These define the shape of `IStorageConfig.config` for each provider:
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
interface IAwsS3Config {
|
|
259
|
+
region: string;
|
|
260
|
+
bucket: string;
|
|
261
|
+
accessKeyId: string;
|
|
262
|
+
secretAccessKey: string;
|
|
263
|
+
endpoint?: string; // Custom S3-compatible endpoint
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
interface IAzureBlobConfig {
|
|
267
|
+
accountName: string;
|
|
268
|
+
accountKey: string;
|
|
269
|
+
containerName: string;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
interface ISftpConfig {
|
|
273
|
+
host: string;
|
|
274
|
+
port: number;
|
|
275
|
+
username: string;
|
|
276
|
+
password?: string;
|
|
277
|
+
privateKey?: string;
|
|
278
|
+
basePath: string;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
interface ILocalStorageConfig {
|
|
282
|
+
basePath: string;
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Services
|
|
289
|
+
|
|
290
|
+
All services are `providedIn: 'root'`. Company scoping is automatic when the company feature is enabled.
|
|
291
|
+
|
|
292
|
+
### UploadService
|
|
293
|
+
|
|
294
|
+
Handles file upload and deletion. Extends `BaseApiService` (from ng-core).
|
|
295
|
+
|
|
296
|
+
| Method | Endpoint | Description |
|
|
297
|
+
|--------|----------|-------------|
|
|
298
|
+
| `uploadSingleFile(file, options?)` | `POST /storage/upload/single-file` | Upload single file |
|
|
299
|
+
| `uploadMultipleFiles(files, options?)` | `POST /storage/upload/multiple-file` | Upload multiple files (max 50) |
|
|
300
|
+
| `deleteSingleFile(key, storageConfigId?)` | `POST /storage/upload/delete-single-file` | Delete single file from storage |
|
|
301
|
+
| `deleteMultipleFiles(keys, storageConfigId?)` | `POST /storage/upload/delete-multiple-file` | Delete multiple files |
|
|
302
|
+
| `getFileUrl(key)` | `GET /storage/upload/file/:key` | Get direct file download URL |
|
|
303
|
+
|
|
304
|
+
Upload options are sent as **query parameters**, not form data:
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
// POST /storage/upload/single-file?storageConfigId=abc&folderPath=docs&compress=true
|
|
308
|
+
this.uploadService.uploadSingleFile(file, {
|
|
309
|
+
storageConfigId: 'abc',
|
|
310
|
+
folderPath: 'docs',
|
|
311
|
+
compress: true,
|
|
312
|
+
quality: 85,
|
|
313
|
+
format: ImageFormat.WEBP,
|
|
314
|
+
});
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### FileManagerApiService
|
|
318
|
+
|
|
319
|
+
File metadata CRUD. Extends `ApiResourceService<IUpdateFileManagerDto, IFileManager>`.
|
|
320
|
+
|
|
321
|
+
**Inherited CRUD methods** (from ApiResourceService): `insert`, `update`, `findById`, `getAll`, `delete` and their `*Async` variants.
|
|
322
|
+
|
|
323
|
+
**Additional methods:**
|
|
324
|
+
|
|
325
|
+
| Method | Endpoint | Description |
|
|
326
|
+
|--------|----------|-------------|
|
|
327
|
+
| `getFiles(fileIds)` | `POST /storage/file-manager/get-files` | Get files with valid presigned URLs |
|
|
328
|
+
| `getFilesByFolder(folderId, page?, limit?)` | `POST /storage/file-manager/get-all` | Filter files by folder |
|
|
329
|
+
| `getPrivateFiles(page?, limit?)` | `POST /storage/file-manager/get-all` | Filter by `isPrivate: true` |
|
|
330
|
+
|
|
331
|
+
**Presigned URL pattern:** Always use `getFiles()` to get valid URLs. Backend regenerates expired presigned URLs for cloud storage.
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
const response = await firstValueFrom(
|
|
335
|
+
this.fileService.getFiles(['file-id-1', 'file-id-2'])
|
|
336
|
+
);
|
|
337
|
+
// response.data → [{ id, name, contentType, url }]
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### FolderApiService
|
|
341
|
+
|
|
342
|
+
Folder CRUD. Extends `ApiResourceService<IUpdateFolderDto, IFolder>`. Standard CRUD operations only, no custom methods.
|
|
343
|
+
|
|
344
|
+
### StorageConfigApiService
|
|
345
|
+
|
|
346
|
+
Storage provider configuration CRUD. Extends `ApiResourceService<IUpdateStorageConfigDto, IStorageConfig>`. Standard CRUD operations only, no custom methods.
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## Components
|
|
351
|
+
|
|
352
|
+
All components are standalone, use Angular 21 signal forms, and lazy-load via routes.
|
|
353
|
+
|
|
354
|
+
### StorageContainerComponent
|
|
355
|
+
|
|
356
|
+
Main container with tab navigation between Files, Folders, and Configs sections. Uses inline CSS with theme variables (`--primary-color`, `--surface-ground`, etc.).
|
|
357
|
+
|
|
358
|
+
**Selector:** `lib-storage-container`
|
|
359
|
+
|
|
360
|
+
### List Components
|
|
361
|
+
|
|
362
|
+
All list components share:
|
|
363
|
+
- **Lazy pagination** via `p-datatable`
|
|
364
|
+
- **Company info display** when company feature enabled (via `APP_CONFIG`)
|
|
365
|
+
- **Delete confirmation** via `ConfirmationService`
|
|
366
|
+
- **Signal-based state:** `isLoading`, `files`/`folders`/`configs`, `totalRecords`, `pageSize`, `currentPage`
|
|
367
|
+
|
|
368
|
+
**FileManagerListComponent** additionally supports:
|
|
369
|
+
- File content type icons (image, video, audio, PDF, Word, Excel, generic)
|
|
370
|
+
- View file (opens presigned URL in new tab)
|
|
371
|
+
- **Soft delete** - marks as deleted (recoverable)
|
|
372
|
+
- **Permanent delete** - removes from storage provider (irreversible)
|
|
373
|
+
|
|
374
|
+
### Form Components
|
|
375
|
+
|
|
376
|
+
All form components share:
|
|
377
|
+
- **Signal Forms** using Angular 21 `form()` helper with `required()` validators
|
|
378
|
+
- **Create/Edit mode** auto-detection based on route param (`:id`)
|
|
379
|
+
- **Navigation** back to list on save/cancel
|
|
380
|
+
|
|
381
|
+
**FileManagerFormComponent** additionally supports:
|
|
382
|
+
- PrimeNG file upload with drag-drop
|
|
383
|
+
- Storage config selection dropdown
|
|
384
|
+
- Folder assignment
|
|
385
|
+
- Auto-filling filename from uploaded file
|
|
386
|
+
|
|
387
|
+
**StorageConfigFormComponent** has dynamic form fields based on selected provider:
|
|
388
|
+
- AWS S3: region, bucket, accessKeyId, secretAccessKey, endpoint
|
|
389
|
+
- Azure Blob: accountName, accountKey, containerName
|
|
390
|
+
- SFTP: host, port, username, password, basePath
|
|
391
|
+
- Local: basePath
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## Usage Examples
|
|
396
|
+
|
|
397
|
+
### Upload a File
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
import { UploadService, ImageFormat } from '@flusys/ng-storage';
|
|
401
|
+
|
|
402
|
+
private readonly uploadService = inject(UploadService);
|
|
403
|
+
|
|
404
|
+
async uploadImage(file: File): Promise<IUploadedFileInfo | null> {
|
|
405
|
+
const response = await firstValueFrom(
|
|
406
|
+
this.uploadService.uploadSingleFile(file, {
|
|
407
|
+
storageConfigId: 'my-config-id',
|
|
408
|
+
folderPath: 'images/avatars',
|
|
409
|
+
compress: true,
|
|
410
|
+
maxWidth: 800,
|
|
411
|
+
maxHeight: 800,
|
|
412
|
+
quality: 80,
|
|
413
|
+
format: ImageFormat.WEBP,
|
|
414
|
+
})
|
|
415
|
+
);
|
|
416
|
+
return response.success ? response.data : null;
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Get Files with Presigned URLs
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
import { FileManagerApiService } from '@flusys/ng-storage';
|
|
424
|
+
|
|
425
|
+
private readonly fileService = inject(FileManagerApiService);
|
|
426
|
+
|
|
427
|
+
async getFileUrls(ids: string[]): Promise<IFilesResponseDto[]> {
|
|
428
|
+
const response = await firstValueFrom(this.fileService.getFiles(ids));
|
|
429
|
+
return response.data ?? [];
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Delete with Confirmation
|
|
434
|
+
|
|
435
|
+
Two delete modes are available:
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
// Soft delete - marks as deleted, recoverable
|
|
439
|
+
onSoftDelete(file: IFileManager): void {
|
|
440
|
+
this.confirmationService.confirm({
|
|
441
|
+
message: `Delete "${file.name}"?`,
|
|
442
|
+
header: 'Delete File',
|
|
443
|
+
acceptButtonStyleClass: 'p-button-danger',
|
|
444
|
+
accept: async () => {
|
|
445
|
+
await this.fileService.deleteAsync({ id: file.id, type: 'delete' });
|
|
446
|
+
this.loadFiles();
|
|
447
|
+
},
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Permanent delete - removes from storage provider, irreversible
|
|
452
|
+
onPermanentDelete(file: IFileManager): void {
|
|
453
|
+
this.confirmationService.confirm({
|
|
454
|
+
message: `Permanently delete "${file.name}"? This cannot be undone.`,
|
|
455
|
+
header: 'Permanent Delete',
|
|
456
|
+
acceptButtonStyleClass: 'p-button-danger',
|
|
457
|
+
accept: async () => {
|
|
458
|
+
await firstValueFrom(
|
|
459
|
+
this.uploadService.deleteSingleFile(file.key, file.storageConfigId ?? undefined)
|
|
460
|
+
);
|
|
461
|
+
await this.fileService.deleteAsync({ id: file.id, type: 'permanent' });
|
|
462
|
+
this.loadFiles();
|
|
463
|
+
},
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
## Backend Integration
|
|
471
|
+
|
|
472
|
+
All endpoints use **POST-only RPC** style (not REST).
|
|
473
|
+
|
|
474
|
+
| Service | Endpoint | Description |
|
|
475
|
+
|---------|----------|-------------|
|
|
476
|
+
| Upload | `POST /storage/upload/single-file` | Upload single file |
|
|
477
|
+
| Upload | `POST /storage/upload/multiple-file` | Upload multiple files |
|
|
478
|
+
| Upload | `POST /storage/upload/delete-single-file` | Delete file from storage |
|
|
479
|
+
| Upload | `POST /storage/upload/delete-multiple-file` | Delete multiple files |
|
|
480
|
+
| Upload | `GET /storage/upload/file/:filePath` | Direct file download |
|
|
481
|
+
| FileManager | `POST /storage/file-manager/get-files` | Get files with presigned URLs |
|
|
482
|
+
| FileManager | `POST /storage/file-manager/insert` | Create file metadata |
|
|
483
|
+
| FileManager | `POST /storage/file-manager/get/:id` | Get file by ID |
|
|
484
|
+
| FileManager | `POST /storage/file-manager/get-all` | List files (paginated) |
|
|
485
|
+
| FileManager | `POST /storage/file-manager/update` | Update file metadata |
|
|
486
|
+
| FileManager | `POST /storage/file-manager/delete` | Delete file |
|
|
487
|
+
| Folder | `POST /storage/folder/insert` | Create folder |
|
|
488
|
+
| Folder | `POST /storage/folder/get/:id` | Get folder by ID |
|
|
489
|
+
| Folder | `POST /storage/folder/get-all` | List folders |
|
|
490
|
+
| Folder | `POST /storage/folder/update` | Update folder |
|
|
491
|
+
| Folder | `POST /storage/folder/delete` | Delete folder |
|
|
492
|
+
| StorageConfig | `POST /storage/storage-config/insert` | Create config |
|
|
493
|
+
| StorageConfig | `POST /storage/storage-config/get/:id` | Get config by ID |
|
|
494
|
+
| StorageConfig | `POST /storage/storage-config/get-all` | List configs |
|
|
495
|
+
| StorageConfig | `POST /storage/storage-config/update` | Update config |
|
|
496
|
+
| StorageConfig | `POST /storage/storage-config/delete` | Delete config |
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
## Best Practices
|
|
501
|
+
|
|
502
|
+
### 1. Always Use Presigned URLs
|
|
503
|
+
|
|
504
|
+
Never construct file URLs manually. Use `FileManagerApiService.getFiles()` or `FileUrlService` from ng-shared.
|
|
505
|
+
|
|
506
|
+
```typescript
|
|
507
|
+
// Wrong: manual URL
|
|
508
|
+
const url = `${apiBaseUrl}/storage/${fileId}`;
|
|
509
|
+
|
|
510
|
+
// Correct: backend-generated presigned URL
|
|
511
|
+
const files = await firstValueFrom(this.fileService.getFiles([fileId]));
|
|
512
|
+
const url = files.data?.[0]?.url ?? null;
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### 2. Specify Storage Config for Multi-Provider Setups
|
|
516
|
+
|
|
517
|
+
```typescript
|
|
518
|
+
// Specify which storage provider to use
|
|
519
|
+
await firstValueFrom(
|
|
520
|
+
this.uploadService.uploadSingleFile(file, {
|
|
521
|
+
storageConfigId: 'aws-media-bucket',
|
|
522
|
+
folderPath: 'images',
|
|
523
|
+
})
|
|
524
|
+
);
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### 3. Compress Images for Web
|
|
528
|
+
|
|
529
|
+
```typescript
|
|
530
|
+
const options: IUploadOptionsDto = {
|
|
531
|
+
compress: true,
|
|
532
|
+
maxWidth: 1920,
|
|
533
|
+
maxHeight: 1080,
|
|
534
|
+
quality: 85,
|
|
535
|
+
format: ImageFormat.WEBP,
|
|
536
|
+
};
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
### 4. Provide ConfirmationService at App Level
|
|
540
|
+
|
|
541
|
+
Storage list components use `ConfirmationService` for delete dialogs. Provide it in `app.config.ts`:
|
|
542
|
+
|
|
543
|
+
```typescript
|
|
544
|
+
export const appConfig: ApplicationConfig = {
|
|
545
|
+
providers: [ConfirmationService, MessageService],
|
|
546
|
+
};
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
### 5. Enable Storage in APP_CONFIG
|
|
550
|
+
|
|
551
|
+
```typescript
|
|
552
|
+
// environment.ts
|
|
553
|
+
services: {
|
|
554
|
+
storage: { baseUrl: 'http://localhost:2002/storage', enabled: true },
|
|
555
|
+
}
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
## Public API Exports
|
|
561
|
+
|
|
562
|
+
```typescript
|
|
563
|
+
// Enums
|
|
564
|
+
export { FileLocationEnum, ImageFormat } from '@flusys/ng-storage';
|
|
565
|
+
|
|
566
|
+
// Interfaces (all from interfaces/)
|
|
567
|
+
export {
|
|
568
|
+
IFileManager, ICreateFileManagerDto, IUpdateFileManagerDto,
|
|
569
|
+
IGetFilesRequestDto, IFilesResponseDto,
|
|
570
|
+
IFolder, ICreateFolderDto, IUpdateFolderDto,
|
|
571
|
+
IStorageConfig, ICreateStorageConfigDto, IUpdateStorageConfigDto,
|
|
572
|
+
IAwsS3Config, IAzureBlobConfig, ISftpConfig, ILocalStorageConfig,
|
|
573
|
+
IUploadOptionsDto, IUploadedFileInfo,
|
|
574
|
+
} from '@flusys/ng-storage';
|
|
575
|
+
|
|
576
|
+
// Services
|
|
577
|
+
export {
|
|
578
|
+
FileManagerApiService, FolderApiService,
|
|
579
|
+
StorageConfigApiService, UploadService,
|
|
580
|
+
} from '@flusys/ng-storage';
|
|
581
|
+
|
|
582
|
+
// Routes & Components
|
|
583
|
+
export { STORAGE_ROUTES } from '@flusys/ng-storage';
|
|
584
|
+
export { StorageContainerComponent } from '@flusys/ng-storage';
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
---
|
|
588
|
+
|
|
589
|
+
**Last Updated:** 2026-02-07
|
|
590
|
+
**Angular Version:** 21
|