@flusys/ng-storage 1.0.0-rc → 1.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 +1 -1
- package/fesm2022/{flusys-ng-storage-file-manager-form.component-CMS_ddbs.mjs → flusys-ng-storage-file-manager-form.component-CXVB9G-f.mjs} +4 -5
- package/fesm2022/flusys-ng-storage-file-manager-form.component-CXVB9G-f.mjs.map +1 -0
- package/fesm2022/{flusys-ng-storage-file-manager-list.component-DDOFAPRD.mjs → flusys-ng-storage-file-manager-list.component-0O_b4EjN.mjs} +4 -5
- package/fesm2022/flusys-ng-storage-file-manager-list.component-0O_b4EjN.mjs.map +1 -0
- package/fesm2022/{flusys-ng-storage-folder-form.component-ClYATZkh.mjs → flusys-ng-storage-folder-form.component-BTQGEqNu.mjs} +5 -7
- package/fesm2022/flusys-ng-storage-folder-form.component-BTQGEqNu.mjs.map +1 -0
- package/fesm2022/{flusys-ng-storage-folder-list.component-CzONANHt.mjs → flusys-ng-storage-folder-list.component-B8GoIh6Z.mjs} +5 -11
- package/fesm2022/flusys-ng-storage-folder-list.component-B8GoIh6Z.mjs.map +1 -0
- package/fesm2022/{flusys-ng-storage-storage-config-form.component-CODLLCtg.mjs → flusys-ng-storage-storage-config-form.component-CorNWrmF.mjs} +70 -93
- package/fesm2022/flusys-ng-storage-storage-config-form.component-CorNWrmF.mjs.map +1 -0
- package/fesm2022/{flusys-ng-storage-storage-config-list.component-BbBx0iSL.mjs → flusys-ng-storage-storage-config-list.component-YXzz3Tvo.mjs} +14 -40
- package/fesm2022/flusys-ng-storage-storage-config-list.component-YXzz3Tvo.mjs.map +1 -0
- package/fesm2022/flusys-ng-storage.mjs +122 -248
- package/fesm2022/flusys-ng-storage.mjs.map +1 -1
- package/package.json +10 -10
- package/types/flusys-ng-storage.d.ts +32 -188
- package/fesm2022/flusys-ng-storage-file-manager-form.component-CMS_ddbs.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-file-manager-list.component-DDOFAPRD.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-folder-form.component-ClYATZkh.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-folder-list.component-CzONANHt.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-storage-config-form.component-CODLLCtg.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-storage-config-list.component-BbBx0iSL.mjs.map +0 -1
|
@@ -3,7 +3,7 @@ import { inject, signal, computed, Directive, Injectable, ChangeDetectionStrateg
|
|
|
3
3
|
import { Router, RouterOutlet, RouterLink, RouterLinkActive } from '@angular/router';
|
|
4
4
|
import { APP_CONFIG, DEFAULT_APP_NAME, BaseApiService, getDefaultStorageConfigId } from '@flusys/ng-core';
|
|
5
5
|
import { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';
|
|
6
|
-
import { BaseListPage, ApiResourceService, PROFILE_UPLOAD_PROVIDER } from '@flusys/ng-shared';
|
|
6
|
+
import { BaseListPage, ApiResourceService, PROFILE_UPLOAD_PROVIDER, permissionGuard, FILE_PERMISSIONS, FOLDER_PERMISSIONS, STORAGE_CONFIG_PERMISSIONS, PermissionValidatorService } from '@flusys/ng-shared';
|
|
7
7
|
import { MessageService } from 'primeng/api';
|
|
8
8
|
import { map } from 'rxjs/operators';
|
|
9
9
|
import { firstValueFrom, switchMap } from 'rxjs';
|
|
@@ -118,219 +118,135 @@ const STORAGE_PROVIDERS = [
|
|
|
118
118
|
{ label: 'Local Storage', value: FileLocationEnum.LOCAL },
|
|
119
119
|
];
|
|
120
120
|
|
|
121
|
-
/**
|
|
122
|
-
* Base Storage Page
|
|
123
|
-
*
|
|
124
|
-
* Provides common signals, computed values, and utilities for storage pages.
|
|
125
|
-
* Used by form components that need company context and message utilities.
|
|
126
|
-
*/
|
|
127
121
|
class BaseStoragePage {
|
|
128
122
|
router = inject(Router);
|
|
129
123
|
messageService = inject(MessageService);
|
|
130
124
|
appConfig = inject(APP_CONFIG);
|
|
131
125
|
companyContext = inject(LAYOUT_AUTH_STATE);
|
|
132
|
-
/** Loading state */
|
|
133
126
|
isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
134
|
-
/** Show company info if company feature enabled */
|
|
135
127
|
showCompanyInfo = computed(() => this.appConfig.enableCompanyFeature, ...(ngDevMode ? [{ debugName: "showCompanyInfo" }] : []));
|
|
136
|
-
/** Current company name */
|
|
137
128
|
currentCompanyName = computed(() => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME, ...(ngDevMode ? [{ debugName: "currentCompanyName" }] : []));
|
|
138
|
-
/** Show success message */
|
|
139
129
|
showSuccess(detail, summary = 'Success') {
|
|
140
130
|
this.messageService.add({ severity: 'success', summary, detail });
|
|
141
131
|
}
|
|
142
|
-
/** Show error message */
|
|
143
132
|
showError(detail, summary = 'Error') {
|
|
144
133
|
this.messageService.add({ severity: 'error', summary, detail });
|
|
145
134
|
}
|
|
146
|
-
/** Navigate to a route */
|
|
147
135
|
navigateTo(path) {
|
|
148
136
|
this.router.navigate(path);
|
|
149
137
|
}
|
|
150
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.
|
|
151
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.
|
|
138
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: BaseStoragePage, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
139
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.5", type: BaseStoragePage, isStandalone: true, ngImport: i0 });
|
|
152
140
|
}
|
|
153
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.
|
|
141
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: BaseStoragePage, decorators: [{
|
|
154
142
|
type: Directive
|
|
155
143
|
}] });
|
|
156
|
-
/**
|
|
157
|
-
* Base Storage List Page
|
|
158
|
-
*
|
|
159
|
-
* Extends the shared BaseListPage with storage-specific functionality:
|
|
160
|
-
* - Company context integration via LAYOUT_AUTH_STATE
|
|
161
|
-
* - Current company name computed signal
|
|
162
|
-
* - Storage-specific defaults (pageSize: 50)
|
|
163
|
-
*
|
|
164
|
-
* Usage:
|
|
165
|
-
* ```typescript
|
|
166
|
-
* @Component({ ... })
|
|
167
|
-
* export class FolderListComponent extends BaseStorageListPage<IFolder> {
|
|
168
|
-
* getResourceRoute(): string { return '/storage/folders'; }
|
|
169
|
-
* getDeleteConfirmMessage(folder: IFolder): string { return `Delete "${folder.name}"?`; }
|
|
170
|
-
* async loadData(): Promise<void> { ... }
|
|
171
|
-
* }
|
|
172
|
-
* ```
|
|
173
|
-
*/
|
|
174
144
|
class BaseStorageListPage extends BaseListPage {
|
|
175
145
|
companyContext = inject(LAYOUT_AUTH_STATE);
|
|
176
|
-
/** Override default page size for storage pages */
|
|
177
146
|
pageSize = signal(50, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
|
|
178
|
-
/** Total records alias for backward compatibility */
|
|
179
147
|
totalRecords = this.total;
|
|
180
|
-
/** Current company name */
|
|
181
148
|
currentCompanyName = computed(() => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME, ...(ngDevMode ? [{ debugName: "currentCompanyName" }] : []));
|
|
182
|
-
/**
|
|
183
|
-
* Default implementation - subclasses should override if needed
|
|
184
|
-
*/
|
|
185
149
|
getDeleteConfirmMessage(item) {
|
|
186
150
|
const name = item.name ?? 'this item';
|
|
187
151
|
return `Are you sure you want to delete "${name}"?`;
|
|
188
152
|
}
|
|
189
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.
|
|
190
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.
|
|
153
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: BaseStorageListPage, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
154
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.5", type: BaseStorageListPage, isStandalone: true, usesInheritance: true, ngImport: i0 });
|
|
191
155
|
}
|
|
192
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.
|
|
156
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: BaseStorageListPage, decorators: [{
|
|
193
157
|
type: Directive
|
|
194
158
|
}] });
|
|
195
159
|
|
|
196
|
-
/**
|
|
197
|
-
* File Manager API Service
|
|
198
|
-
* Handles file metadata CRUD operations
|
|
199
|
-
* Endpoint: POST /storage/file-manager/*
|
|
200
|
-
*
|
|
201
|
-
* Note: Company feature enabled - all queries automatically scoped to user's company
|
|
202
|
-
*/
|
|
203
160
|
class FileManagerApiService extends ApiResourceService {
|
|
204
161
|
constructor() {
|
|
205
|
-
|
|
206
|
-
super('storage/file-manager', http);
|
|
162
|
+
super('file-manager', inject(HttpClient), 'storage');
|
|
207
163
|
}
|
|
208
|
-
/**
|
|
209
|
-
* Get multiple files with valid URLs
|
|
210
|
-
* POST /storage/file-manager/get-files
|
|
211
|
-
* Regenerates presigned URLs if expired
|
|
212
|
-
*/
|
|
213
164
|
getFiles(fileIds) {
|
|
214
165
|
const requests = fileIds.map((id) => ({ id }));
|
|
215
166
|
return this.http.post(`${this.baseUrl}/get-files`, requests);
|
|
216
167
|
}
|
|
217
|
-
/**
|
|
218
|
-
* Get files by folder
|
|
219
|
-
* POST /storage/file-manager/get-all
|
|
220
|
-
* Filtered by folder ID (UUID) and company (if enabled)
|
|
221
|
-
*/
|
|
222
|
-
getFilesByFolder(folderId, page = 1, limit = 50) {
|
|
223
|
-
return this.getAll('', {
|
|
224
|
-
filter: folderId ? { folderId } : {},
|
|
225
|
-
pagination: { currentPage: page - 1, pageSize: limit },
|
|
226
|
-
select: [],
|
|
227
|
-
sort: {},
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Get private files (requires permission)
|
|
232
|
-
* POST /storage/file-manager/get-all
|
|
233
|
-
* Filtered by isPrivate and user permission 'storage.file.viewPrivate'
|
|
234
|
-
*/
|
|
235
|
-
getPrivateFiles(page = 1, limit = 50) {
|
|
236
|
-
return this.getAll('', {
|
|
237
|
-
filter: { isPrivate: true },
|
|
238
|
-
pagination: { currentPage: page - 1, pageSize: limit },
|
|
239
|
-
select: [],
|
|
240
|
-
sort: {},
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Create a new file record
|
|
245
|
-
* POST /storage/file-manager/insert
|
|
246
|
-
* Uses ICreateFileManagerDto which has different required fields than update
|
|
247
|
-
*/
|
|
248
168
|
createFile(dto) {
|
|
249
169
|
return this.http.post(`${this.baseUrl}/insert`, dto);
|
|
250
170
|
}
|
|
251
|
-
/**
|
|
252
|
-
* Create a new file record (async/await version)
|
|
253
|
-
* POST /storage/file-manager/insert
|
|
254
|
-
*/
|
|
255
171
|
async createFileAsync(dto) {
|
|
256
172
|
return firstValueFrom(this.createFile(dto));
|
|
257
173
|
}
|
|
258
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.
|
|
259
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.
|
|
174
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FileManagerApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
175
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FileManagerApiService, providedIn: 'root' });
|
|
260
176
|
}
|
|
261
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.
|
|
177
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FileManagerApiService, decorators: [{
|
|
262
178
|
type: Injectable,
|
|
263
|
-
args: [{
|
|
264
|
-
providedIn: 'root',
|
|
265
|
-
}]
|
|
179
|
+
args: [{ providedIn: 'root' }]
|
|
266
180
|
}], ctorParameters: () => [] });
|
|
267
181
|
|
|
268
182
|
/**
|
|
269
|
-
* Upload Service
|
|
270
|
-
* Handles file upload/delete operations
|
|
183
|
+
* Upload Service - File upload/delete operations
|
|
271
184
|
* Endpoint: POST /storage/upload/*
|
|
272
|
-
*
|
|
273
|
-
* Features:
|
|
274
|
-
* - Company-scoped uploads (if company feature enabled)
|
|
275
|
-
* - Image compression
|
|
276
|
-
* - Multiple storage providers
|
|
277
|
-
* - File validation (size, type)
|
|
278
|
-
* - Default storage config from environment (services.storage.defaultStorageConfigId)
|
|
279
185
|
*/
|
|
280
186
|
class UploadService extends BaseApiService {
|
|
281
187
|
fileManagerApi = inject(FileManagerApiService);
|
|
282
188
|
constructor() {
|
|
283
189
|
super('storage');
|
|
284
190
|
}
|
|
285
|
-
/**
|
|
286
|
-
* Get default storage config ID from app config
|
|
287
|
-
* Used when no storageConfigId is provided in upload options
|
|
288
|
-
*/
|
|
191
|
+
/** Get default storage config ID from app config */
|
|
289
192
|
getDefaultConfigId() {
|
|
290
193
|
return getDefaultStorageConfigId(this.appConfig);
|
|
291
194
|
}
|
|
292
|
-
/**
|
|
293
|
-
* Upload single file
|
|
294
|
-
* POST /storage/upload/single-file?storageConfigId=x&folderPath=y
|
|
295
|
-
*
|
|
296
|
-
* @param file - File to upload
|
|
297
|
-
* @param options - Upload options (storage config, compression, etc.)
|
|
298
|
-
*/
|
|
195
|
+
/** Upload single file - POST /storage/upload/single-file */
|
|
299
196
|
uploadSingleFile(file, options) {
|
|
300
197
|
const formData = new FormData();
|
|
301
198
|
formData.append('file', file);
|
|
302
|
-
|
|
303
|
-
const url = queryParams
|
|
304
|
-
? `${this.getUrl('upload/single-file')}?${queryParams}`
|
|
305
|
-
: this.getUrl('upload/single-file');
|
|
306
|
-
return this.http.post(url, formData);
|
|
199
|
+
return this.http.post(this.buildUploadUrl('single-file', options), formData);
|
|
307
200
|
}
|
|
308
|
-
/**
|
|
309
|
-
* Upload multiple files (max 50)
|
|
310
|
-
* POST /storage/upload/multiple-file?storageConfigId=x&folderPath=y
|
|
311
|
-
*
|
|
312
|
-
* @param files - Array of files to upload
|
|
313
|
-
* @param options - Upload options
|
|
314
|
-
*/
|
|
201
|
+
/** Upload multiple files (max 50) - POST /storage/upload/multiple-file */
|
|
315
202
|
uploadMultipleFiles(files, options) {
|
|
316
203
|
const formData = new FormData();
|
|
317
204
|
files.forEach((file) => formData.append('files', file));
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
return this.http.post(
|
|
205
|
+
return this.http.post(this.buildUploadUrl('multiple-file', options), formData);
|
|
206
|
+
}
|
|
207
|
+
/** Delete single file - POST /storage/upload/delete-single-file */
|
|
208
|
+
deleteSingleFile(key, storageConfigId) {
|
|
209
|
+
return this.http.post(this.getUrl('upload/delete-single-file'), this.buildDeleteBody({ key }, storageConfigId));
|
|
210
|
+
}
|
|
211
|
+
/** Delete multiple files - POST /storage/upload/delete-multiple-file */
|
|
212
|
+
deleteMultipleFiles(keys, storageConfigId) {
|
|
213
|
+
return this.http.post(this.getUrl('upload/delete-multiple-file'), this.buildDeleteBody({ keys }, storageConfigId));
|
|
214
|
+
}
|
|
215
|
+
/** Get file download URL - GET /storage/upload/file/:filePath */
|
|
216
|
+
getFileUrl(key) {
|
|
217
|
+
return this.getUrl(`upload/file/${key}`);
|
|
218
|
+
}
|
|
219
|
+
/** Upload file and register in file manager - returns file manager ID (UUID) */
|
|
220
|
+
uploadAndRegister(file, options) {
|
|
221
|
+
return this.uploadSingleFile(file, options).pipe(switchMap((response) => {
|
|
222
|
+
if (!response.success || !response.data) {
|
|
223
|
+
throw new Error(response.message || 'Upload failed');
|
|
224
|
+
}
|
|
225
|
+
return this.fileManagerApi.createFile({
|
|
226
|
+
name: response.data.name,
|
|
227
|
+
key: response.data.key,
|
|
228
|
+
size: String(response.data.size),
|
|
229
|
+
contentType: response.data.contentType,
|
|
230
|
+
isPrivate: options?.isPrivate ?? false,
|
|
231
|
+
folderId: options?.folderId,
|
|
232
|
+
storageConfigId: this.resolveConfigId(options?.storageConfigId),
|
|
233
|
+
});
|
|
234
|
+
}));
|
|
235
|
+
}
|
|
236
|
+
// ─── Private Helpers ───────────────────────────────────────────────────────
|
|
237
|
+
resolveConfigId(storageConfigId) {
|
|
238
|
+
return storageConfigId ?? this.getDefaultConfigId();
|
|
239
|
+
}
|
|
240
|
+
buildUploadUrl(endpoint, options) {
|
|
241
|
+
const params = this.buildQueryParams(options);
|
|
242
|
+
const baseUrl = this.getUrl(`upload/${endpoint}`);
|
|
243
|
+
return params ? `${baseUrl}?${params}` : baseUrl;
|
|
323
244
|
}
|
|
324
|
-
/**
|
|
325
|
-
* Build query string from upload options
|
|
326
|
-
* Uses default storageConfigId from app config if not provided in options
|
|
327
|
-
*/
|
|
328
245
|
buildQueryParams(options) {
|
|
329
246
|
const params = new URLSearchParams();
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
params.append('storageConfigId', storageConfigId);
|
|
247
|
+
const configId = this.resolveConfigId(options?.storageConfigId);
|
|
248
|
+
if (configId)
|
|
249
|
+
params.append('storageConfigId', configId);
|
|
334
250
|
if (options?.folderPath)
|
|
335
251
|
params.append('folderPath', options.folderPath);
|
|
336
252
|
if (options?.maxWidth)
|
|
@@ -345,73 +261,16 @@ class UploadService extends BaseApiService {
|
|
|
345
261
|
params.append('compress', options.compress.toString());
|
|
346
262
|
return params.toString();
|
|
347
263
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
*
|
|
352
|
-
* @param key - File key/path to delete
|
|
353
|
-
* @param storageConfigId - Optional storage config ID (uses default from config if not provided)
|
|
354
|
-
*/
|
|
355
|
-
deleteSingleFile(key, storageConfigId) {
|
|
356
|
-
const configId = storageConfigId ?? this.getDefaultConfigId();
|
|
357
|
-
return this.http.post(this.getUrl('upload/delete-single-file'), { key, ...(configId && { storageConfigId: configId }) });
|
|
358
|
-
}
|
|
359
|
-
/**
|
|
360
|
-
* Delete multiple files
|
|
361
|
-
* POST /storage/upload/delete-multiple-file
|
|
362
|
-
*
|
|
363
|
-
* @param keys - Array of file keys/paths to delete
|
|
364
|
-
* @param storageConfigId - Optional storage config ID (uses default from config if not provided)
|
|
365
|
-
*/
|
|
366
|
-
deleteMultipleFiles(keys, storageConfigId) {
|
|
367
|
-
const configId = storageConfigId ?? this.getDefaultConfigId();
|
|
368
|
-
return this.http.post(this.getUrl('upload/delete-multiple-file'), { keys, ...(configId && { storageConfigId: configId }) });
|
|
264
|
+
buildDeleteBody(data, storageConfigId) {
|
|
265
|
+
const configId = this.resolveConfigId(storageConfigId);
|
|
266
|
+
return { ...data, ...(configId && { storageConfigId: configId }) };
|
|
369
267
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
* GET /storage/upload/file/:filePath
|
|
373
|
-
*
|
|
374
|
-
* @param key - File key/path
|
|
375
|
-
* @returns URL for direct file access
|
|
376
|
-
*/
|
|
377
|
-
getFileUrl(key) {
|
|
378
|
-
return this.getUrl(`upload/file/${key}`);
|
|
379
|
-
}
|
|
380
|
-
/**
|
|
381
|
-
* Upload file and register in file manager
|
|
382
|
-
* Returns file manager ID (UUID) for storing in references like profilePictureId
|
|
383
|
-
*
|
|
384
|
-
* @param file - File to upload
|
|
385
|
-
* @param options - Upload options (storage config, compression, etc.)
|
|
386
|
-
* @returns Observable with file manager record (id is the UUID to store)
|
|
387
|
-
*/
|
|
388
|
-
uploadAndRegister(file, options) {
|
|
389
|
-
return this.uploadSingleFile(file, options).pipe(switchMap((uploadResponse) => {
|
|
390
|
-
if (!uploadResponse.success || !uploadResponse.data) {
|
|
391
|
-
throw new Error(uploadResponse.message || 'Upload failed');
|
|
392
|
-
}
|
|
393
|
-
const uploadedFile = uploadResponse.data;
|
|
394
|
-
const storageConfigId = options?.storageConfigId ?? this.getDefaultConfigId();
|
|
395
|
-
// Create file manager record using proper DTO
|
|
396
|
-
return this.fileManagerApi.createFile({
|
|
397
|
-
name: uploadedFile.name,
|
|
398
|
-
key: uploadedFile.key,
|
|
399
|
-
size: String(uploadedFile.size),
|
|
400
|
-
contentType: uploadedFile.contentType,
|
|
401
|
-
isPrivate: options?.isPrivate ?? false,
|
|
402
|
-
folderId: options?.folderId,
|
|
403
|
-
storageConfigId,
|
|
404
|
-
});
|
|
405
|
-
}));
|
|
406
|
-
}
|
|
407
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UploadService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
408
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UploadService, providedIn: 'root' });
|
|
268
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UploadService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
269
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UploadService, providedIn: 'root' });
|
|
409
270
|
}
|
|
410
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.
|
|
271
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UploadService, decorators: [{
|
|
411
272
|
type: Injectable,
|
|
412
|
-
args: [{
|
|
413
|
-
providedIn: 'root',
|
|
414
|
-
}]
|
|
273
|
+
args: [{ providedIn: 'root' }]
|
|
415
274
|
}], ctorParameters: () => [] });
|
|
416
275
|
|
|
417
276
|
/**
|
|
@@ -454,10 +313,10 @@ class ProfileUploadProviderAdapter {
|
|
|
454
313
|
: undefined,
|
|
455
314
|
})));
|
|
456
315
|
}
|
|
457
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.
|
|
458
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.
|
|
316
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: ProfileUploadProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
317
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: ProfileUploadProviderAdapter });
|
|
459
318
|
}
|
|
460
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.
|
|
319
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: ProfileUploadProviderAdapter, decorators: [{
|
|
461
320
|
type: Injectable
|
|
462
321
|
}] });
|
|
463
322
|
|
|
@@ -495,13 +354,12 @@ function provideStorageProviders() {
|
|
|
495
354
|
*/
|
|
496
355
|
class FolderApiService extends ApiResourceService {
|
|
497
356
|
constructor() {
|
|
498
|
-
|
|
499
|
-
super('storage/folder', http);
|
|
357
|
+
super('folder', inject(HttpClient), 'storage');
|
|
500
358
|
}
|
|
501
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.
|
|
502
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.
|
|
359
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FolderApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
360
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FolderApiService, providedIn: 'root' });
|
|
503
361
|
}
|
|
504
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.
|
|
362
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FolderApiService, decorators: [{
|
|
505
363
|
type: Injectable,
|
|
506
364
|
args: [{
|
|
507
365
|
providedIn: 'root',
|
|
@@ -517,13 +375,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
517
375
|
*/
|
|
518
376
|
class StorageConfigApiService extends ApiResourceService {
|
|
519
377
|
constructor() {
|
|
520
|
-
|
|
521
|
-
super('storage/storage-config', http);
|
|
378
|
+
super('storage-config', inject(HttpClient), 'storage');
|
|
522
379
|
}
|
|
523
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.
|
|
524
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.
|
|
380
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: StorageConfigApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
381
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: StorageConfigApiService, providedIn: 'root' });
|
|
525
382
|
}
|
|
526
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.
|
|
383
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: StorageConfigApiService, decorators: [{
|
|
527
384
|
type: Injectable,
|
|
528
385
|
args: [{
|
|
529
386
|
providedIn: 'root',
|
|
@@ -532,9 +389,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
532
389
|
|
|
533
390
|
/**
|
|
534
391
|
* Storage Module Routes
|
|
535
|
-
* All
|
|
536
|
-
*
|
|
537
|
-
* All routes are protected by permission guards to prevent direct URL access.
|
|
392
|
+
* All routes protected by permission guards
|
|
538
393
|
*/
|
|
539
394
|
const STORAGE_ROUTES = [
|
|
540
395
|
{
|
|
@@ -544,63 +399,68 @@ const STORAGE_ROUTES = [
|
|
|
544
399
|
// File Manager Routes
|
|
545
400
|
{
|
|
546
401
|
path: 'files',
|
|
402
|
+
canActivate: [permissionGuard(FILE_PERMISSIONS.READ)],
|
|
547
403
|
children: [
|
|
548
404
|
{
|
|
549
405
|
path: '',
|
|
550
|
-
loadComponent: () => import('./flusys-ng-storage-file-manager-list.component-
|
|
406
|
+
loadComponent: () => import('./flusys-ng-storage-file-manager-list.component-0O_b4EjN.mjs').then((m) => m.FileManagerListComponent),
|
|
551
407
|
},
|
|
552
408
|
{
|
|
553
409
|
path: 'new',
|
|
554
|
-
|
|
410
|
+
canActivate: [permissionGuard(FILE_PERMISSIONS.CREATE)],
|
|
411
|
+
loadComponent: () => import('./flusys-ng-storage-file-manager-form.component-CXVB9G-f.mjs').then((m) => m.FileManagerFormComponent),
|
|
555
412
|
},
|
|
556
413
|
{
|
|
557
414
|
path: ':id',
|
|
558
|
-
|
|
415
|
+
canActivate: [permissionGuard(FILE_PERMISSIONS.UPDATE)],
|
|
416
|
+
loadComponent: () => import('./flusys-ng-storage-file-manager-form.component-CXVB9G-f.mjs').then((m) => m.FileManagerFormComponent),
|
|
559
417
|
},
|
|
560
418
|
],
|
|
561
419
|
},
|
|
562
420
|
// Folder Routes
|
|
563
421
|
{
|
|
564
422
|
path: 'folders',
|
|
423
|
+
canActivate: [permissionGuard(FOLDER_PERMISSIONS.READ)],
|
|
565
424
|
children: [
|
|
566
425
|
{
|
|
567
426
|
path: '',
|
|
568
|
-
loadComponent: () => import('./flusys-ng-storage-folder-list.component-
|
|
427
|
+
loadComponent: () => import('./flusys-ng-storage-folder-list.component-B8GoIh6Z.mjs').then((m) => m.FolderListComponent),
|
|
569
428
|
},
|
|
570
429
|
{
|
|
571
430
|
path: 'new',
|
|
572
|
-
|
|
431
|
+
canActivate: [permissionGuard(FOLDER_PERMISSIONS.CREATE)],
|
|
432
|
+
loadComponent: () => import('./flusys-ng-storage-folder-form.component-BTQGEqNu.mjs').then((m) => m.FolderFormComponent),
|
|
573
433
|
},
|
|
574
434
|
{
|
|
575
435
|
path: ':id',
|
|
576
|
-
|
|
436
|
+
canActivate: [permissionGuard(FOLDER_PERMISSIONS.UPDATE)],
|
|
437
|
+
loadComponent: () => import('./flusys-ng-storage-folder-form.component-BTQGEqNu.mjs').then((m) => m.FolderFormComponent),
|
|
577
438
|
},
|
|
578
439
|
],
|
|
579
440
|
},
|
|
580
441
|
// Storage Config Routes
|
|
581
442
|
{
|
|
582
443
|
path: 'configs',
|
|
444
|
+
canActivate: [permissionGuard(STORAGE_CONFIG_PERMISSIONS.READ)],
|
|
583
445
|
children: [
|
|
584
446
|
{
|
|
585
447
|
path: '',
|
|
586
|
-
loadComponent: () => import('./flusys-ng-storage-storage-config-list.component-
|
|
448
|
+
loadComponent: () => import('./flusys-ng-storage-storage-config-list.component-YXzz3Tvo.mjs').then((m) => m.StorageConfigListComponent),
|
|
587
449
|
},
|
|
588
450
|
{
|
|
589
451
|
path: 'new',
|
|
590
|
-
|
|
452
|
+
canActivate: [permissionGuard(STORAGE_CONFIG_PERMISSIONS.CREATE)],
|
|
453
|
+
loadComponent: () => import('./flusys-ng-storage-storage-config-form.component-CorNWrmF.mjs').then((m) => m.StorageConfigFormComponent),
|
|
591
454
|
},
|
|
592
455
|
{
|
|
593
456
|
path: ':id',
|
|
594
|
-
|
|
457
|
+
canActivate: [permissionGuard(STORAGE_CONFIG_PERMISSIONS.UPDATE)],
|
|
458
|
+
loadComponent: () => import('./flusys-ng-storage-storage-config-form.component-CorNWrmF.mjs').then((m) => m.StorageConfigFormComponent),
|
|
595
459
|
},
|
|
596
460
|
],
|
|
597
461
|
},
|
|
598
|
-
// Default redirect
|
|
599
|
-
{
|
|
600
|
-
path: '',
|
|
601
|
-
redirectTo: 'files',
|
|
602
|
-
pathMatch: 'full',
|
|
603
|
-
},
|
|
462
|
+
// Default redirect
|
|
463
|
+
{ path: '', redirectTo: 'files', pathMatch: 'full' },
|
|
604
464
|
],
|
|
605
465
|
},
|
|
606
466
|
];
|
|
@@ -610,39 +470,53 @@ const STORAGE_ROUTES = [
|
|
|
610
470
|
*
|
|
611
471
|
* Main container for Storage module with tab navigation
|
|
612
472
|
* Routes: Files | Folders | Configurations
|
|
473
|
+
* Tabs are filtered based on user permissions
|
|
613
474
|
*/
|
|
614
475
|
class StorageContainerComponent {
|
|
615
|
-
|
|
616
|
-
tabs
|
|
476
|
+
permissionValidator = inject(PermissionValidatorService);
|
|
477
|
+
/** All available tabs with required permissions */
|
|
478
|
+
allTabs = [
|
|
617
479
|
{
|
|
618
480
|
id: 'files',
|
|
619
481
|
label: 'Files',
|
|
620
482
|
icon: 'pi pi-file',
|
|
621
483
|
route: 'files',
|
|
484
|
+
permission: FILE_PERMISSIONS.READ,
|
|
622
485
|
},
|
|
623
486
|
{
|
|
624
487
|
id: 'folders',
|
|
625
488
|
label: 'Folders',
|
|
626
489
|
icon: 'pi pi-folder',
|
|
627
490
|
route: 'folders',
|
|
491
|
+
permission: FOLDER_PERMISSIONS.READ,
|
|
628
492
|
},
|
|
629
493
|
{
|
|
630
494
|
id: 'configs',
|
|
631
495
|
label: 'Configurations',
|
|
632
496
|
icon: 'pi pi-cog',
|
|
633
497
|
route: 'configs',
|
|
498
|
+
permission: STORAGE_CONFIG_PERMISSIONS.READ,
|
|
634
499
|
},
|
|
635
500
|
];
|
|
636
|
-
|
|
637
|
-
|
|
501
|
+
/** Visible tabs based on user permissions */
|
|
502
|
+
visibleTabs = computed(() => this.allTabs.filter((tab) => this.permissionValidator.hasPermission(tab.permission)), ...(ngDevMode ? [{ debugName: "visibleTabs" }] : []));
|
|
503
|
+
/** Dynamic subtitle based on visible tabs */
|
|
504
|
+
subtitle = computed(() => {
|
|
505
|
+
const tabs = this.visibleTabs();
|
|
506
|
+
if (tabs.length === 0)
|
|
507
|
+
return 'No permissions available';
|
|
508
|
+
return `Manage ${tabs.map((t) => t.label.toLowerCase()).join(', ')}`;
|
|
509
|
+
}, ...(ngDevMode ? [{ debugName: "subtitle" }] : []));
|
|
510
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: StorageContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
511
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: StorageContainerComponent, isStandalone: true, selector: "lib-storage-container", ngImport: i0, template: `
|
|
638
512
|
<div class="p-2 sm:p-4">
|
|
639
513
|
<div class="mb-4">
|
|
640
514
|
<h1 class="text-xl sm:text-2xl font-bold m-0">Storage</h1>
|
|
641
|
-
<p class="text-muted-color mt-1 text-sm sm:text-base">
|
|
515
|
+
<p class="text-muted-color mt-1 text-sm sm:text-base">{{ subtitle() }}</p>
|
|
642
516
|
</div>
|
|
643
517
|
|
|
644
518
|
<div class="scrollbar-hide flex gap-1 mb-4 border-b border-surface overflow-x-auto flex-nowrap">
|
|
645
|
-
@for (tab of
|
|
519
|
+
@for (tab of visibleTabs(); track tab.id) {
|
|
646
520
|
<a
|
|
647
521
|
[routerLink]="tab.route"
|
|
648
522
|
routerLinkActive="tab-active"
|
|
@@ -658,17 +532,17 @@ class StorageContainerComponent {
|
|
|
658
532
|
</div>
|
|
659
533
|
`, isInline: true, styles: [".scrollbar-hide{-ms-overflow-style:none;scrollbar-width:none}.scrollbar-hide::-webkit-scrollbar{display:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
660
534
|
}
|
|
661
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.
|
|
535
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: StorageContainerComponent, decorators: [{
|
|
662
536
|
type: Component,
|
|
663
|
-
args: [{ selector: 'lib-storage-container',
|
|
537
|
+
args: [{ selector: 'lib-storage-container', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, RouterOutlet, RouterLink, RouterLinkActive], template: `
|
|
664
538
|
<div class="p-2 sm:p-4">
|
|
665
539
|
<div class="mb-4">
|
|
666
540
|
<h1 class="text-xl sm:text-2xl font-bold m-0">Storage</h1>
|
|
667
|
-
<p class="text-muted-color mt-1 text-sm sm:text-base">
|
|
541
|
+
<p class="text-muted-color mt-1 text-sm sm:text-base">{{ subtitle() }}</p>
|
|
668
542
|
</div>
|
|
669
543
|
|
|
670
544
|
<div class="scrollbar-hide flex gap-1 mb-4 border-b border-surface overflow-x-auto flex-nowrap">
|
|
671
|
-
@for (tab of
|
|
545
|
+
@for (tab of visibleTabs(); track tab.id) {
|
|
672
546
|
<a
|
|
673
547
|
[routerLink]="tab.route"
|
|
674
548
|
routerLinkActive="tab-active"
|