@flusys/ng-storage
v4.1.1
Published
File storage module for FLUSYS Angular applications
Readme
@flusys/ng-storage
File storage UI library for the FLUSYS Angular platform — file upload, folder management, file browser, presigned URL fetching, and provider adapter registration.
Table of Contents
- Overview
- Features
- Compatibility
- Installation
- Quick Start
- Module Registration
- File URL Rule
- Services
- Components
- Storage Routes
- File Location Enum
- API Endpoints
- Configuration Reference
- Troubleshooting
- License
Overview
@flusys/ng-storage provides the complete file management UI for FLUSYS applications. It supports all four storage backends (Local, S3, Azure Blob, SFTP) transparently — the backend generates the correct presigned URLs for each provider.
Critical rule: Never construct file URLs manually. Always use FileUrlService (from ng-shared) or the FILE_PROVIDER token. The backend generates presigned URLs that are provider-agnostic and access-controlled.
Features
- ✅ File browser with folder navigation
- ✅ Drag-and-drop upload with progress
- ✅ Multi-file selection dialog (
FileSelectorDialogComponent) - ✅ Image preview thumbnails
- ✅ Download and delete actions
- ✅
UploadService— typed multi-part file upload - ✅
provideStorageProviders()— registersFILE_PROVIDERfor shared components - ✅ Presigned URL fetching via
FileUrlService - ✅ Support for
LOCAL,S3,AZURE,SFTPbackends
Compatibility
| Package | Version | |---------|---------| | Angular | 21+ | | @flusys/ng-core | 4.x | | @flusys/ng-shared | 4.x |
Installation
npm install @flusys/ng-storage @flusys/ng-core @flusys/ng-sharedQuick Start
1. Enable Storage in Config
// environments/environment.ts
export const environment = {
services: {
storage: { enabled: true },
},
};2. Register Storage Providers
// app.config.ts
import { provideStorageProviders } from '@flusys/ng-storage';
export const appConfig: ApplicationConfig = {
providers: [
...provideStorageProviders(),
// Provides: FILE_PROVIDER (IFileProvider) — used by FileSelectorDialogComponent, FileUrlService
],
};3. Add Storage Routes (Optional)
// app.routes.ts
import { STORAGE_ROUTES } from '@flusys/ng-storage';
export const routes: Routes = [
{
path: 'storage',
loadChildren: () => STORAGE_ROUTES,
},
];Module Registration
provideStorageProviders()
Registers the storage adapter against the FILE_PROVIDER token from ng-shared:
import { provideStorageProviders } from '@flusys/ng-storage';
providers: [
...provideStorageProviders(),
]This enables:
FileSelectorDialogComponent(fromng-shared) to list/browse filesFileUrlService.fetchSingleFileUrl()to work correctlyHasPermissionDirectiveto show storage-gated content
File URL Rule
CRITICAL: Never construct file URLs manually. The backend handles URL generation for all storage providers (Local, S3, Azure, SFTP) including presigned URL rotation.
// ❌ WRONG — breaks with S3, Azure, SFTP
const url = `${apiBaseUrl}/uploads/${fileId}`;
const url = `https://my-bucket.s3.amazonaws.com/${path}`;
// ✅ CORRECT — always use FileUrlService
import { FileUrlService } from '@flusys/ng-shared';
const file = await this.fileUrlService.fetchSingleFileUrl(fileId);
const url = file?.url ?? null; // Presigned, access-controlled, provider-agnosticWhy backend URLs:
- S3/Azure require presigned URLs that expire
- URLs are access-controlled (user must have permission)
- Works transparently across all 4 storage providers
- Automatic URL refresh on expiry
Services
FileManagerApiService
Typed API client for file management operations:
import { FileManagerApiService } from '@flusys/ng-storage';
@Injectable({ ... })
export class MyService {
private fileApi = inject(FileManagerApiService);
getFiles(folderId?: string): Observable<IListResponse<IFile>> {
return this.fileApi.getAll({ filters: { folderId } });
}
getFileUrls(fileIds: string[]): Observable<ISingleResponse<IFileWithUrl[]>> {
return this.fileApi.getFiles(fileIds);
}
deleteFile(id: string): Observable<IMessageResponse> {
return this.fileApi.delete(id);
}
}FileManagerApiService Methods:
| Method | Endpoint | Description |
|--------|----------|-------------|
| getAll(params) | POST /file-manager/get-all | List files with pagination |
| getById(id) | POST /file-manager/get/:id | Get file metadata |
| getFiles(ids[]) | POST /file-manager/get-files | Batch fetch with presigned URLs |
| delete(id) | POST /file-manager/delete | Delete file |
| bulkDelete(ids[]) | POST /file-manager/bulk-delete | Delete multiple files |
| move(id, folderId) | POST /file-manager/move | Move file to folder |
FolderApiService
Typed API client for folder management:
import { FolderApiService } from '@flusys/ng-storage';
@Injectable({ ... })
export class MyService {
private folderApi = inject(FolderApiService);
getFolders(parentId?: string): Observable<IListResponse<IFolder>> {
return this.folderApi.getAll({ filters: { parentId } });
}
createFolder(name: string, parentId?: string): Observable<ISingleResponse<IFolder>> {
return this.folderApi.insert({ name, parentId });
}
}FolderApiService Methods:
| Method | Endpoint | Description |
|--------|----------|-------------|
| getAll(params) | POST /folder/get-all | List folders |
| getById(id) | POST /folder/get/:id | Get folder |
| insert(dto) | POST /folder/insert | Create folder |
| update(dto) | POST /folder/update | Rename folder |
| delete(id) | POST /folder/delete | Delete folder |
UploadService
Handles multi-part file uploads with progress tracking:
import { UploadService } from '@flusys/ng-storage';
@Component({ ... })
export class UploadComponent {
private uploadService = inject(UploadService);
uploadFile(file: File, folderId?: string): void {
this.uploadService.upload(file, { folderId }).subscribe({
next: (event) => {
if (event.type === 'progress') {
console.log(`Progress: ${event.percent}%`);
}
if (event.type === 'complete') {
console.log('Uploaded:', event.file);
}
},
error: (err) => console.error('Upload failed:', err),
});
}
uploadMultiple(files: File[]): void {
this.uploadService.uploadBatch(files).subscribe(results => {
console.log(`Uploaded ${results.length} files`);
});
}
}UploadService API:
| Method | Description |
|--------|-------------|
| upload(file, options?) | Single file upload with progress events |
| uploadBatch(files, options?) | Multiple file upload (sequential) |
| cancel(uploadId) | Cancel in-progress upload |
Components
FileManagerComponent
Full-page file browser with folder tree, grid/list view, upload, and actions.
<!-- Full file manager -->
<flusys-file-manager />
<!-- With pre-selected folder -->
<flusys-file-manager [initialFolderId]="rootFolderId" />Features:
- Folder tree (left panel)
- File grid with thumbnails (right panel)
- Drag-and-drop upload zone
- Right-click context menu (rename, move, delete)
- Breadcrumb navigation
- Search files
FileSelectorDialogComponent
Dialog for selecting one or multiple files. Used by other packages (ng-form-builder, ng-email) to pick files.
<flusys-file-selector-dialog
[visible]="showPicker"
[multiple]="true"
[accept]="'image/*'"
(fileSelected)="onFilesSelected($event)"
(cancel)="showPicker = false"
/>| Input | Type | Description |
|-------|------|-------------|
| visible | boolean | Show/hide dialog |
| multiple | boolean | Allow multi-select (default: false) |
| accept | string | MIME type filter |
| folderId | string | Pre-open specific folder |
| Output | Type | Description |
|--------|------|-------------|
| fileSelected | IFile \| IFile[] | Selected file(s) |
| cancel | void | Dialog dismissed |
FileUploaderComponent
Lightweight standalone upload component (without the full browser):
<flusys-file-uploader
[multiple]="false"
[accept]="'image/jpeg,image/png'"
[maxSizeMb]="5"
[folderId]="profilePicturesFolderId"
(uploaded)="onAvatarUploaded($event)"
/>Storage Routes
Lazy-loaded pages for the full file manager:
import { STORAGE_ROUTES } from '@flusys/ng-storage';
{ path: 'storage', loadChildren: () => STORAGE_ROUTES }| Route | Component | Description |
|-------|-----------|-------------|
| /storage | FileManagerPageComponent | Full file manager page |
| /storage/folder/:id | FileManagerPageComponent | Open specific folder |
File Location Enum
import { FileLocationEnum } from '@flusys/ng-storage';
enum FileLocationEnum {
LOCAL = 'LOCAL',
S3 = 'S3',
AZURE = 'AZURE',
SFTP = 'SFTP',
}Use FileLocationEnum when filtering or categorizing files by their storage backend.
API Endpoints
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | /file-manager/get-all | List files with pagination |
| POST | /file-manager/get/:id | Get file metadata |
| POST | /file-manager/get-files | Batch fetch with presigned URLs |
| POST | /file-manager/upload | Upload file (multipart) |
| POST | /file-manager/delete | Delete file |
| POST | /file-manager/bulk-delete | Delete multiple files |
| POST | /file-manager/move | Move file to folder |
| POST | /folder/get-all | List folders |
| POST | /folder/get/:id | Get folder metadata |
| POST | /folder/insert | Create folder |
| POST | /folder/update | Rename folder |
| POST | /folder/delete | Delete folder |
Configuration Reference
| Config Key | Type | Default | Description |
|------------|------|---------|-------------|
| services.storage.enabled | boolean | false | Enable storage module |
The storage backend (LOCAL/S3/AZURE/SFTP) is configured server-side in nestjs-storage. The Angular client doesn't need to know which provider is active.
Troubleshooting
File thumbnails don't load
Images are loaded via presigned URLs. Ensure FileUrlService.fetchSingleFileUrl() is used (not manual URL construction). Check the browser network tab — are the URLs returning 403?
Upload fails with 413 Payload Too Large
The backend has a file size limit. Configure maxBodySize in nestjs-storage on the server. On the Angular side, validate client-side before upload:
<flusys-file-uploader [maxSizeMb]="10" />No provider for FILE_PROVIDER
Add provideStorageProviders() to app.config.ts providers.
FileSelectorDialog is empty (no files)
Ensure the user has permission to list files (file:read) and the backend storage is configured. Check the network tab for errors on POST /file-manager/get-all.
Files visible but download fails
The presigned URL may have expired. Call FileUrlService.clearCache(fileId) to force a fresh URL fetch.
License
MIT © FLUSYS
