@flusys/ng-storage 3.0.0 → 4.0.0-lts
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 +13 -7
- package/fesm2022/{flusys-ng-storage-file-manager-form.component-CXVB9G-f.mjs → flusys-ng-storage-file-manager-form.component-AM7JE-s5.mjs} +67 -74
- package/fesm2022/flusys-ng-storage-file-manager-form.component-AM7JE-s5.mjs.map +1 -0
- package/fesm2022/{flusys-ng-storage-file-manager-list.component-0O_b4EjN.mjs → flusys-ng-storage-file-manager-list.component-bj6oOzOL.mjs} +66 -74
- package/fesm2022/flusys-ng-storage-file-manager-list.component-bj6oOzOL.mjs.map +1 -0
- package/fesm2022/{flusys-ng-storage-folder-form.component-BTQGEqNu.mjs → flusys-ng-storage-folder-form.component-Cc2ybTwu.mjs} +25 -34
- package/fesm2022/flusys-ng-storage-folder-form.component-Cc2ybTwu.mjs.map +1 -0
- package/fesm2022/{flusys-ng-storage-folder-list.component-B8GoIh6Z.mjs → flusys-ng-storage-folder-list.component-B2Q41I1g.mjs} +34 -39
- package/fesm2022/flusys-ng-storage-folder-list.component-B2Q41I1g.mjs.map +1 -0
- package/fesm2022/{flusys-ng-storage-storage-config-form.component-CorNWrmF.mjs → flusys-ng-storage-storage-config-form.component-a88XhuPH.mjs} +87 -85
- package/fesm2022/flusys-ng-storage-storage-config-form.component-a88XhuPH.mjs.map +1 -0
- package/fesm2022/{flusys-ng-storage-storage-config-list.component-YXzz3Tvo.mjs → flusys-ng-storage-storage-config-list.component-DBH_qf9o.mjs} +36 -35
- package/fesm2022/flusys-ng-storage-storage-config-list.component-DBH_qf9o.mjs.map +1 -0
- package/fesm2022/flusys-ng-storage.mjs +490 -151
- package/fesm2022/flusys-ng-storage.mjs.map +1 -1
- package/package.json +7 -5
- package/types/flusys-ng-storage.d.ts +56 -36
- package/fesm2022/flusys-ng-storage-file-manager-form.component-CXVB9G-f.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-file-manager-list.component-0O_b4EjN.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-folder-form.component-BTQGEqNu.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-folder-list.component-B8GoIh6Z.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-storage-config-form.component-CorNWrmF.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-storage-config-list.component-YXzz3Tvo.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Storage Package Guide
|
|
2
2
|
|
|
3
3
|
> **Package:** `@flusys/ng-storage`
|
|
4
|
-
> **Version:**
|
|
4
|
+
> **Version:** 4.0.0-rc
|
|
5
5
|
> **Type:** File storage management with upload, folder organization, and multi-provider support
|
|
6
6
|
|
|
7
7
|
---
|
|
@@ -529,11 +529,17 @@ Registers provider adapters that enable other packages (ng-auth) to access stora
|
|
|
529
529
|
...provideStorageProviders()
|
|
530
530
|
```
|
|
531
531
|
|
|
532
|
-
**Registers:** `
|
|
532
|
+
**Registers:** `FILE_PROVIDER` → `FileProviderAdapter` (implements `IFileProvider` from ng-shared)
|
|
533
533
|
|
|
534
|
-
**
|
|
534
|
+
**FileProviderAdapter features:**
|
|
535
|
+
- `loadFiles(filter)` - Load files with filtering and pagination
|
|
536
|
+
- `uploadFile(file, options)` - Upload a single file and register in file manager
|
|
537
|
+
- `uploadMultipleFiles(files, options)` - Upload multiple files at once
|
|
538
|
+
- `getFileUrls(fileIds)` - Get file URLs by IDs (for refreshing presigned URLs)
|
|
539
|
+
- `loadFolders(filter)` - Load folders for folder selector
|
|
540
|
+
- `loadStorageConfigs(filter)` - Load storage configs for config selector
|
|
535
541
|
|
|
536
|
-
**Usage:** `inject(
|
|
542
|
+
**Usage:** `inject(FILE_PROVIDER, { optional: true })?.uploadFile(file, options)`
|
|
537
543
|
|
|
538
544
|
---
|
|
539
545
|
|
|
@@ -544,13 +550,13 @@ Registers provider adapters that enable other packages (ng-auth) to access stora
|
|
|
544
550
|
| Enums | `FileLocationEnum`, `ImageFormat` |
|
|
545
551
|
| Interfaces | `IFileManager`, `ICreateFileManagerDto`, `IUpdateFileManagerDto`, `IGetFilesRequestDto`, `IFilesResponseDto`, `IFolder`, `ICreateFolderDto`, `IUpdateFolderDto`, `IStorageConfig`, `ICreateStorageConfigDto`, `IUpdateStorageConfigDto`, `IAwsS3Config`, `IAzureBlobConfig`, `ISftpConfig`, `ILocalStorageConfig`, `IUploadOptionsDto`, `IUploadedFileInfo` |
|
|
546
552
|
| Utils | `getProviderLabel`, `getProviderIcon`, `getProviderSeverity`, `getFileIcon`, `formatFileSize`, `STORAGE_PROVIDERS`, `BaseStoragePage`, `BaseStorageListPage` |
|
|
547
|
-
| Adapters | `
|
|
553
|
+
| Adapters | `FileProviderAdapter` |
|
|
548
554
|
| Services | `FileManagerApiService`, `FolderApiService`, `StorageConfigApiService`, `UploadService` |
|
|
549
555
|
| Routes | `STORAGE_ROUTES`, `StorageContainerComponent` |
|
|
550
556
|
| Providers | `provideStorageProviders` |
|
|
551
557
|
|
|
552
558
|
---
|
|
553
559
|
|
|
554
|
-
**Last Updated:** 2026-
|
|
555
|
-
**Version:** 3.0.
|
|
560
|
+
**Last Updated:** 2026-03-01
|
|
561
|
+
**Version:** 3.0.1
|
|
556
562
|
**Angular Version:** 21
|
|
@@ -1,26 +1,24 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, signal, computed, effect,
|
|
2
|
+
import { inject, signal, computed, effect, Component } from '@angular/core';
|
|
3
3
|
import { toSignal } from '@angular/core/rxjs-interop';
|
|
4
4
|
import { form, required, FormField } from '@angular/forms/signals';
|
|
5
5
|
import { ActivatedRoute } from '@angular/router';
|
|
6
|
-
import {
|
|
6
|
+
import { TranslateService } from '@flusys/ng-localization';
|
|
7
|
+
import { AngularModule, PrimeModule, TranslatePipe } from '@flusys/ng-shared';
|
|
7
8
|
import { firstValueFrom } from 'rxjs';
|
|
8
|
-
import { BaseStoragePage, FileManagerApiService, UploadService, StorageConfigApiService, FolderApiService, formatFileSize,
|
|
9
|
+
import { BaseStoragePage, FileManagerApiService, UploadService, StorageConfigApiService, FolderApiService, formatFileSize, getProviderLabelKey } from './flusys-ng-storage.mjs';
|
|
9
10
|
import * as i1 from '@angular/forms';
|
|
10
11
|
import * as i1$1 from 'primeng/button';
|
|
11
12
|
import * as i3 from 'primeng/fileupload';
|
|
12
13
|
import * as i3$1 from 'primeng/inputtext';
|
|
13
14
|
|
|
14
|
-
/**
|
|
15
|
-
* File Manager Form Component
|
|
16
|
-
* Upload and edit file metadata
|
|
17
|
-
*/
|
|
18
15
|
class FileManagerFormComponent extends BaseStoragePage {
|
|
19
16
|
route = inject(ActivatedRoute);
|
|
20
17
|
fileService = inject(FileManagerApiService);
|
|
21
18
|
uploadService = inject(UploadService);
|
|
22
19
|
configService = inject(StorageConfigApiService);
|
|
23
20
|
folderService = inject(FolderApiService);
|
|
21
|
+
translateService = inject(TranslateService);
|
|
24
22
|
routeParams = toSignal(this.route.paramMap);
|
|
25
23
|
initialized = false;
|
|
26
24
|
isLoadingConfigs = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingConfigs" }] : []));
|
|
@@ -30,10 +28,8 @@ class FileManagerFormComponent extends BaseStoragePage {
|
|
|
30
28
|
selectedFile = signal(null, ...(ngDevMode ? [{ debugName: "selectedFile" }] : []));
|
|
31
29
|
availableConfigs = signal([], ...(ngDevMode ? [{ debugName: "availableConfigs" }] : []));
|
|
32
30
|
availableFolders = signal([], ...(ngDevMode ? [{ debugName: "availableFolders" }] : []));
|
|
33
|
-
/** Utility functions exposed to template */
|
|
34
31
|
formatFileSize = formatFileSize;
|
|
35
|
-
|
|
36
|
-
/** Form model */
|
|
32
|
+
getProviderLabelKey = getProviderLabelKey;
|
|
37
33
|
formModel = signal({
|
|
38
34
|
id: '',
|
|
39
35
|
name: '',
|
|
@@ -41,11 +37,9 @@ class FileManagerFormComponent extends BaseStoragePage {
|
|
|
41
37
|
folderId: '',
|
|
42
38
|
storageConfigId: '',
|
|
43
39
|
}, ...(ngDevMode ? [{ debugName: "formModel" }] : []));
|
|
44
|
-
/** Form with validation */
|
|
45
40
|
fileForm = form(this.formModel, (f) => {
|
|
46
|
-
required(f.name, { message: '
|
|
41
|
+
required(f.name, { message: this.translateService.translate('storage.validation.file.name.required') });
|
|
47
42
|
});
|
|
48
|
-
/** Check if form is valid */
|
|
49
43
|
isFormValid = computed(() => this.formModel().name.trim().length > 0, ...(ngDevMode ? [{ debugName: "isFormValid" }] : []));
|
|
50
44
|
constructor() {
|
|
51
45
|
super();
|
|
@@ -81,7 +75,7 @@ class FileManagerFormComponent extends BaseStoragePage {
|
|
|
81
75
|
}
|
|
82
76
|
}
|
|
83
77
|
catch {
|
|
84
|
-
this.showError('
|
|
78
|
+
this.showError(this.translateService.translate('storage.config.load.failed'));
|
|
85
79
|
}
|
|
86
80
|
finally {
|
|
87
81
|
this.isLoadingConfigs.set(false);
|
|
@@ -124,7 +118,7 @@ class FileManagerFormComponent extends BaseStoragePage {
|
|
|
124
118
|
}
|
|
125
119
|
}
|
|
126
120
|
catch {
|
|
127
|
-
this.showError('
|
|
121
|
+
this.showError(this.translateService.translate('storage.error.load.file.failed'));
|
|
128
122
|
this.navigateTo(['/storage/files']);
|
|
129
123
|
}
|
|
130
124
|
finally {
|
|
@@ -151,16 +145,16 @@ class FileManagerFormComponent extends BaseStoragePage {
|
|
|
151
145
|
isPrivate: formValue.isPrivate,
|
|
152
146
|
folderId: formValue.folderId || null,
|
|
153
147
|
});
|
|
154
|
-
this.showSuccess('
|
|
148
|
+
this.showSuccess(this.translateService.translate('storage.file.update.success'));
|
|
155
149
|
}
|
|
156
150
|
else {
|
|
157
151
|
const file = this.selectedFile();
|
|
158
152
|
if (!file) {
|
|
159
|
-
this.showError('
|
|
153
|
+
this.showError(this.translateService.translate('storage.error.no.file'));
|
|
160
154
|
return;
|
|
161
155
|
}
|
|
162
156
|
if (!formValue.storageConfigId) {
|
|
163
|
-
this.showError('
|
|
157
|
+
this.showError(this.translateService.translate('storage.error.no.config'));
|
|
164
158
|
return;
|
|
165
159
|
}
|
|
166
160
|
const uploadResponse = await firstValueFrom(this.uploadService.uploadSingleFile(file, {
|
|
@@ -170,7 +164,7 @@ class FileManagerFormComponent extends BaseStoragePage {
|
|
|
170
164
|
}));
|
|
171
165
|
if (uploadResponse.success && uploadResponse.data) {
|
|
172
166
|
const uploadedFileInfo = uploadResponse.data;
|
|
173
|
-
await this.fileService.
|
|
167
|
+
await firstValueFrom(this.fileService.createFile({
|
|
174
168
|
name: formValue.name,
|
|
175
169
|
key: uploadedFileInfo.key,
|
|
176
170
|
contentType: file.type || 'application/octet-stream',
|
|
@@ -178,17 +172,17 @@ class FileManagerFormComponent extends BaseStoragePage {
|
|
|
178
172
|
isPrivate: formValue.isPrivate,
|
|
179
173
|
folderId: formValue.folderId || undefined,
|
|
180
174
|
storageConfigId: formValue.storageConfigId,
|
|
181
|
-
});
|
|
182
|
-
this.showSuccess('
|
|
175
|
+
}));
|
|
176
|
+
this.showSuccess(this.translateService.translate('storage.upload.success'));
|
|
183
177
|
}
|
|
184
178
|
else {
|
|
185
|
-
throw new Error('
|
|
179
|
+
throw new Error(this.translateService.translate('storage.upload.failed'));
|
|
186
180
|
}
|
|
187
181
|
}
|
|
188
182
|
this.navigateTo(['/storage/files']);
|
|
189
183
|
}
|
|
190
|
-
catch
|
|
191
|
-
this.showError(
|
|
184
|
+
catch {
|
|
185
|
+
this.showError(this.translateService.translate('storage.upload.failed'));
|
|
192
186
|
}
|
|
193
187
|
finally {
|
|
194
188
|
this.isLoading.set(false);
|
|
@@ -201,9 +195,9 @@ class FileManagerFormComponent extends BaseStoragePage {
|
|
|
201
195
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: FileManagerFormComponent, isStandalone: true, selector: "lib-file-manager-form", usesInheritance: true, ngImport: i0, template: `
|
|
202
196
|
<div class="card">
|
|
203
197
|
<div class="mb-4">
|
|
204
|
-
<h3 class="text-lg sm:text-xl font-semibold">{{ isEditMode() ? '
|
|
198
|
+
<h3 class="text-lg sm:text-xl font-semibold">{{ (isEditMode() ? 'storage.file.manager.edit.file' : 'storage.file.manager.upload.file') | translate }}</h3>
|
|
205
199
|
@if (showCompanyInfo()) {
|
|
206
|
-
<p class="text-sm text-muted-color mt-1">
|
|
200
|
+
<p class="text-sm text-muted-color mt-1">{{ 'storage.company' | translate }}: {{ currentCompanyName() }}</p>
|
|
207
201
|
}
|
|
208
202
|
</div>
|
|
209
203
|
|
|
@@ -211,25 +205,25 @@ class FileManagerFormComponent extends BaseStoragePage {
|
|
|
211
205
|
@if (!isEditMode()) {
|
|
212
206
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
|
213
207
|
<div class="field">
|
|
214
|
-
<label for="storageConfig" class="block font-medium mb-2 text-sm sm:text-base">
|
|
208
|
+
<label for="storageConfig" class="block font-medium mb-2 text-sm sm:text-base">{{ 'storage.config.provider.required' | translate }}</label>
|
|
215
209
|
<select id="storageConfig" class="p-select-native w-full" [formField]="fileForm.storageConfigId">
|
|
216
|
-
<option value="">
|
|
210
|
+
<option value="">{{ 'storage.config.select.config' | translate }}</option>
|
|
217
211
|
@for (config of availableConfigs(); track config.id) {
|
|
218
|
-
<option [value]="config.id">{{ config.name }} ({{
|
|
212
|
+
<option [value]="config.id">{{ config.name }} ({{ getProviderLabelKey(config.storage) | translate }})</option>
|
|
219
213
|
}
|
|
220
214
|
</select>
|
|
221
215
|
@if (availableConfigs().length === 0 && !isLoadingConfigs()) {
|
|
222
216
|
<small class="text-warn block mt-2">
|
|
223
217
|
<i class="pi pi-exclamation-triangle mr-1"></i>
|
|
224
|
-
|
|
218
|
+
{{ 'storage.config.no.configs' | translate }}
|
|
225
219
|
</small>
|
|
226
220
|
}
|
|
227
221
|
</div>
|
|
228
222
|
|
|
229
223
|
<div class="field">
|
|
230
|
-
<label for="folder" class="block font-medium mb-2 text-sm sm:text-base">
|
|
224
|
+
<label for="folder" class="block font-medium mb-2 text-sm sm:text-base">{{ 'storage.folder.optional' | translate }}</label>
|
|
231
225
|
<select id="folder" class="p-select-native w-full" [formField]="fileForm.folderId">
|
|
232
|
-
<option value="">
|
|
226
|
+
<option value="">{{ 'storage.folder.no.folder' | translate }}</option>
|
|
233
227
|
@for (folder of availableFolders(); track folder.id) {
|
|
234
228
|
<option [value]="folder.id">{{ folder.name }}</option>
|
|
235
229
|
}
|
|
@@ -237,16 +231,16 @@ class FileManagerFormComponent extends BaseStoragePage {
|
|
|
237
231
|
@if (availableFolders().length === 0 && !isLoadingFolders()) {
|
|
238
232
|
<small class="text-muted-color block mt-2">
|
|
239
233
|
<i class="pi pi-info-circle mr-1"></i>
|
|
240
|
-
|
|
234
|
+
{{ 'storage.folder.no.folders.available' | translate }}
|
|
241
235
|
</small>
|
|
242
236
|
}
|
|
243
237
|
</div>
|
|
244
238
|
</div>
|
|
245
239
|
} @else {
|
|
246
240
|
<div class="field mb-4">
|
|
247
|
-
<label for="folder" class="block font-medium mb-2 text-sm sm:text-base">
|
|
241
|
+
<label for="folder" class="block font-medium mb-2 text-sm sm:text-base">{{ 'storage.folder.optional' | translate }}</label>
|
|
248
242
|
<select id="folder" class="p-select-native w-full" [formField]="fileForm.folderId">
|
|
249
|
-
<option value="">
|
|
243
|
+
<option value="">{{ 'storage.folder.no.folder' | translate }}</option>
|
|
250
244
|
@for (folder of availableFolders(); track folder.id) {
|
|
251
245
|
<option [value]="folder.id">{{ folder.name }}</option>
|
|
252
246
|
}
|
|
@@ -254,7 +248,7 @@ class FileManagerFormComponent extends BaseStoragePage {
|
|
|
254
248
|
@if (availableFolders().length === 0 && !isLoadingFolders()) {
|
|
255
249
|
<small class="text-muted-color block mt-2">
|
|
256
250
|
<i class="pi pi-info-circle mr-1"></i>
|
|
257
|
-
|
|
251
|
+
{{ 'storage.folder.no.folders.edit' | translate }}
|
|
258
252
|
</small>
|
|
259
253
|
}
|
|
260
254
|
</div>
|
|
@@ -262,7 +256,7 @@ class FileManagerFormComponent extends BaseStoragePage {
|
|
|
262
256
|
|
|
263
257
|
@if (!isEditMode()) {
|
|
264
258
|
<div class="field mb-4">
|
|
265
|
-
<label class="block font-medium mb-2 text-sm sm:text-base">
|
|
259
|
+
<label class="block font-medium mb-2 text-sm sm:text-base">{{ 'storage.file.select.required' | translate }}</label>
|
|
266
260
|
<p-fileupload
|
|
267
261
|
#fileUpload
|
|
268
262
|
[customUpload]="true"
|
|
@@ -271,7 +265,7 @@ class FileManagerFormComponent extends BaseStoragePage {
|
|
|
271
265
|
[maxFileSize]="50000000"
|
|
272
266
|
[showUploadButton]="false"
|
|
273
267
|
[showCancelButton]="false"
|
|
274
|
-
chooseLabel="
|
|
268
|
+
[chooseLabel]="'storage.button.choose.file' | translate"
|
|
275
269
|
chooseIcon="pi pi-upload"
|
|
276
270
|
accept="*/*"
|
|
277
271
|
class="w-full"
|
|
@@ -293,60 +287,59 @@ class FileManagerFormComponent extends BaseStoragePage {
|
|
|
293
287
|
} @else {
|
|
294
288
|
<div class="flex items-center justify-center flex-col p-6 sm:p-8 border-2 border-dashed border-surface rounded-lg">
|
|
295
289
|
<i class="pi pi-cloud-upload text-3xl sm:text-4xl text-muted-color mb-3"></i>
|
|
296
|
-
<p class="text-muted-color text-center text-sm sm:text-base">
|
|
297
|
-
<p class="text-xs sm:text-sm text-muted-color mt-2">
|
|
290
|
+
<p class="text-muted-color text-center text-sm sm:text-base">{{ 'storage.upload.drag.drop' | translate }}</p>
|
|
291
|
+
<p class="text-xs sm:text-sm text-muted-color mt-2">{{ 'storage.upload.max.size' | translate: { size: '50MB' } }}</p>
|
|
298
292
|
</div>
|
|
299
293
|
}
|
|
300
294
|
</ng-template>
|
|
301
295
|
</p-fileupload>
|
|
302
296
|
@if (!selectedFile() && !isEditMode()) {
|
|
303
|
-
<small class="text-muted-color">
|
|
297
|
+
<small class="text-muted-color">{{ 'storage.upload.please.select' | translate }}</small>
|
|
304
298
|
}
|
|
305
299
|
</div>
|
|
306
300
|
}
|
|
307
301
|
|
|
308
302
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
309
303
|
<div class="field md:col-span-2">
|
|
310
|
-
<label for="name" class="block font-medium mb-2 text-sm sm:text-base">
|
|
311
|
-
<input pInputText id="name" [formField]="fileForm.name" [placeholder]="isEditMode() ? '
|
|
304
|
+
<label for="name" class="block font-medium mb-2 text-sm sm:text-base">{{ 'storage.file.name.required' | translate }}</label>
|
|
305
|
+
<input pInputText id="name" [formField]="fileForm.name" [placeholder]="(isEditMode() ? 'storage.file.placeholder.edit' : 'storage.file.placeholder') | translate" class="w-full" />
|
|
312
306
|
</div>
|
|
313
307
|
|
|
314
308
|
<div class="field">
|
|
315
309
|
<label class="p-checkbox-native flex items-center gap-2">
|
|
316
310
|
<input type="checkbox" [formField]="fileForm.isPrivate" />
|
|
317
|
-
<span>
|
|
311
|
+
<span>{{ 'storage.file.private' | translate }}</span>
|
|
318
312
|
</label>
|
|
319
313
|
<small class="text-muted-color block mt-2">
|
|
320
|
-
{{ formModel().isPrivate ? '
|
|
314
|
+
{{ (formModel().isPrivate ? 'storage.file.private.hint' : 'storage.file.public.hint') | translate }}
|
|
321
315
|
</small>
|
|
322
316
|
</div>
|
|
323
317
|
</div>
|
|
324
318
|
|
|
325
319
|
<div class="flex justify-end gap-2 mt-4">
|
|
326
|
-
<p-button label="
|
|
320
|
+
<p-button [label]="'shared.cancel' | translate" severity="secondary" [outlined]="true" (onClick)="onCancel()" />
|
|
327
321
|
<p-button
|
|
328
322
|
type="submit"
|
|
329
|
-
[label]="isEditMode() ? '
|
|
323
|
+
[label]="(isEditMode() ? 'shared.update' : 'storage.button.upload') | translate"
|
|
330
324
|
[loading]="isLoading()"
|
|
331
325
|
[disabled]="!isFormValid() || (!isEditMode() && !selectedFile()) || isLoading()"
|
|
332
326
|
/>
|
|
333
327
|
</div>
|
|
334
328
|
</form>
|
|
335
329
|
</div>
|
|
336
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "directive", type: i3$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }
|
|
330
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i1$1.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "directive", type: i3$1.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
337
331
|
}
|
|
338
332
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FileManagerFormComponent, decorators: [{
|
|
339
333
|
type: Component,
|
|
340
334
|
args: [{
|
|
341
335
|
selector: 'lib-file-manager-form',
|
|
342
|
-
|
|
343
|
-
imports: [AngularModule, PrimeModule, FormField],
|
|
336
|
+
imports: [AngularModule, PrimeModule, FormField, TranslatePipe],
|
|
344
337
|
template: `
|
|
345
338
|
<div class="card">
|
|
346
339
|
<div class="mb-4">
|
|
347
|
-
<h3 class="text-lg sm:text-xl font-semibold">{{ isEditMode() ? '
|
|
340
|
+
<h3 class="text-lg sm:text-xl font-semibold">{{ (isEditMode() ? 'storage.file.manager.edit.file' : 'storage.file.manager.upload.file') | translate }}</h3>
|
|
348
341
|
@if (showCompanyInfo()) {
|
|
349
|
-
<p class="text-sm text-muted-color mt-1">
|
|
342
|
+
<p class="text-sm text-muted-color mt-1">{{ 'storage.company' | translate }}: {{ currentCompanyName() }}</p>
|
|
350
343
|
}
|
|
351
344
|
</div>
|
|
352
345
|
|
|
@@ -354,25 +347,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
354
347
|
@if (!isEditMode()) {
|
|
355
348
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
|
356
349
|
<div class="field">
|
|
357
|
-
<label for="storageConfig" class="block font-medium mb-2 text-sm sm:text-base">
|
|
350
|
+
<label for="storageConfig" class="block font-medium mb-2 text-sm sm:text-base">{{ 'storage.config.provider.required' | translate }}</label>
|
|
358
351
|
<select id="storageConfig" class="p-select-native w-full" [formField]="fileForm.storageConfigId">
|
|
359
|
-
<option value="">
|
|
352
|
+
<option value="">{{ 'storage.config.select.config' | translate }}</option>
|
|
360
353
|
@for (config of availableConfigs(); track config.id) {
|
|
361
|
-
<option [value]="config.id">{{ config.name }} ({{
|
|
354
|
+
<option [value]="config.id">{{ config.name }} ({{ getProviderLabelKey(config.storage) | translate }})</option>
|
|
362
355
|
}
|
|
363
356
|
</select>
|
|
364
357
|
@if (availableConfigs().length === 0 && !isLoadingConfigs()) {
|
|
365
358
|
<small class="text-warn block mt-2">
|
|
366
359
|
<i class="pi pi-exclamation-triangle mr-1"></i>
|
|
367
|
-
|
|
360
|
+
{{ 'storage.config.no.configs' | translate }}
|
|
368
361
|
</small>
|
|
369
362
|
}
|
|
370
363
|
</div>
|
|
371
364
|
|
|
372
365
|
<div class="field">
|
|
373
|
-
<label for="folder" class="block font-medium mb-2 text-sm sm:text-base">
|
|
366
|
+
<label for="folder" class="block font-medium mb-2 text-sm sm:text-base">{{ 'storage.folder.optional' | translate }}</label>
|
|
374
367
|
<select id="folder" class="p-select-native w-full" [formField]="fileForm.folderId">
|
|
375
|
-
<option value="">
|
|
368
|
+
<option value="">{{ 'storage.folder.no.folder' | translate }}</option>
|
|
376
369
|
@for (folder of availableFolders(); track folder.id) {
|
|
377
370
|
<option [value]="folder.id">{{ folder.name }}</option>
|
|
378
371
|
}
|
|
@@ -380,16 +373,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
380
373
|
@if (availableFolders().length === 0 && !isLoadingFolders()) {
|
|
381
374
|
<small class="text-muted-color block mt-2">
|
|
382
375
|
<i class="pi pi-info-circle mr-1"></i>
|
|
383
|
-
|
|
376
|
+
{{ 'storage.folder.no.folders.available' | translate }}
|
|
384
377
|
</small>
|
|
385
378
|
}
|
|
386
379
|
</div>
|
|
387
380
|
</div>
|
|
388
381
|
} @else {
|
|
389
382
|
<div class="field mb-4">
|
|
390
|
-
<label for="folder" class="block font-medium mb-2 text-sm sm:text-base">
|
|
383
|
+
<label for="folder" class="block font-medium mb-2 text-sm sm:text-base">{{ 'storage.folder.optional' | translate }}</label>
|
|
391
384
|
<select id="folder" class="p-select-native w-full" [formField]="fileForm.folderId">
|
|
392
|
-
<option value="">
|
|
385
|
+
<option value="">{{ 'storage.folder.no.folder' | translate }}</option>
|
|
393
386
|
@for (folder of availableFolders(); track folder.id) {
|
|
394
387
|
<option [value]="folder.id">{{ folder.name }}</option>
|
|
395
388
|
}
|
|
@@ -397,7 +390,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
397
390
|
@if (availableFolders().length === 0 && !isLoadingFolders()) {
|
|
398
391
|
<small class="text-muted-color block mt-2">
|
|
399
392
|
<i class="pi pi-info-circle mr-1"></i>
|
|
400
|
-
|
|
393
|
+
{{ 'storage.folder.no.folders.edit' | translate }}
|
|
401
394
|
</small>
|
|
402
395
|
}
|
|
403
396
|
</div>
|
|
@@ -405,7 +398,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
405
398
|
|
|
406
399
|
@if (!isEditMode()) {
|
|
407
400
|
<div class="field mb-4">
|
|
408
|
-
<label class="block font-medium mb-2 text-sm sm:text-base">
|
|
401
|
+
<label class="block font-medium mb-2 text-sm sm:text-base">{{ 'storage.file.select.required' | translate }}</label>
|
|
409
402
|
<p-fileupload
|
|
410
403
|
#fileUpload
|
|
411
404
|
[customUpload]="true"
|
|
@@ -414,7 +407,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
414
407
|
[maxFileSize]="50000000"
|
|
415
408
|
[showUploadButton]="false"
|
|
416
409
|
[showCancelButton]="false"
|
|
417
|
-
chooseLabel="
|
|
410
|
+
[chooseLabel]="'storage.button.choose.file' | translate"
|
|
418
411
|
chooseIcon="pi pi-upload"
|
|
419
412
|
accept="*/*"
|
|
420
413
|
class="w-full"
|
|
@@ -436,40 +429,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
436
429
|
} @else {
|
|
437
430
|
<div class="flex items-center justify-center flex-col p-6 sm:p-8 border-2 border-dashed border-surface rounded-lg">
|
|
438
431
|
<i class="pi pi-cloud-upload text-3xl sm:text-4xl text-muted-color mb-3"></i>
|
|
439
|
-
<p class="text-muted-color text-center text-sm sm:text-base">
|
|
440
|
-
<p class="text-xs sm:text-sm text-muted-color mt-2">
|
|
432
|
+
<p class="text-muted-color text-center text-sm sm:text-base">{{ 'storage.upload.drag.drop' | translate }}</p>
|
|
433
|
+
<p class="text-xs sm:text-sm text-muted-color mt-2">{{ 'storage.upload.max.size' | translate: { size: '50MB' } }}</p>
|
|
441
434
|
</div>
|
|
442
435
|
}
|
|
443
436
|
</ng-template>
|
|
444
437
|
</p-fileupload>
|
|
445
438
|
@if (!selectedFile() && !isEditMode()) {
|
|
446
|
-
<small class="text-muted-color">
|
|
439
|
+
<small class="text-muted-color">{{ 'storage.upload.please.select' | translate }}</small>
|
|
447
440
|
}
|
|
448
441
|
</div>
|
|
449
442
|
}
|
|
450
443
|
|
|
451
444
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
452
445
|
<div class="field md:col-span-2">
|
|
453
|
-
<label for="name" class="block font-medium mb-2 text-sm sm:text-base">
|
|
454
|
-
<input pInputText id="name" [formField]="fileForm.name" [placeholder]="isEditMode() ? '
|
|
446
|
+
<label for="name" class="block font-medium mb-2 text-sm sm:text-base">{{ 'storage.file.name.required' | translate }}</label>
|
|
447
|
+
<input pInputText id="name" [formField]="fileForm.name" [placeholder]="(isEditMode() ? 'storage.file.placeholder.edit' : 'storage.file.placeholder') | translate" class="w-full" />
|
|
455
448
|
</div>
|
|
456
449
|
|
|
457
450
|
<div class="field">
|
|
458
451
|
<label class="p-checkbox-native flex items-center gap-2">
|
|
459
452
|
<input type="checkbox" [formField]="fileForm.isPrivate" />
|
|
460
|
-
<span>
|
|
453
|
+
<span>{{ 'storage.file.private' | translate }}</span>
|
|
461
454
|
</label>
|
|
462
455
|
<small class="text-muted-color block mt-2">
|
|
463
|
-
{{ formModel().isPrivate ? '
|
|
456
|
+
{{ (formModel().isPrivate ? 'storage.file.private.hint' : 'storage.file.public.hint') | translate }}
|
|
464
457
|
</small>
|
|
465
458
|
</div>
|
|
466
459
|
</div>
|
|
467
460
|
|
|
468
461
|
<div class="flex justify-end gap-2 mt-4">
|
|
469
|
-
<p-button label="
|
|
462
|
+
<p-button [label]="'shared.cancel' | translate" severity="secondary" [outlined]="true" (onClick)="onCancel()" />
|
|
470
463
|
<p-button
|
|
471
464
|
type="submit"
|
|
472
|
-
[label]="isEditMode() ? '
|
|
465
|
+
[label]="(isEditMode() ? 'shared.update' : 'storage.button.upload') | translate"
|
|
473
466
|
[loading]="isLoading()"
|
|
474
467
|
[disabled]="!isFormValid() || (!isEditMode() && !selectedFile()) || isLoading()"
|
|
475
468
|
/>
|
|
@@ -481,4 +474,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
481
474
|
}], ctorParameters: () => [] });
|
|
482
475
|
|
|
483
476
|
export { FileManagerFormComponent };
|
|
484
|
-
//# sourceMappingURL=flusys-ng-storage-file-manager-form.component-
|
|
477
|
+
//# sourceMappingURL=flusys-ng-storage-file-manager-form.component-AM7JE-s5.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flusys-ng-storage-file-manager-form.component-AM7JE-s5.mjs","sources":["../../../projects/ng-storage/pages/file-manager/file-manager-form.component.ts"],"sourcesContent":["import { Component, computed, effect, inject, signal } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { form, FormField, required } from '@angular/forms/signals';\nimport { ActivatedRoute } from '@angular/router';\nimport { TranslateService } from '@flusys/ng-localization';\nimport { AngularModule, PrimeModule, TranslatePipe } from '@flusys/ng-shared';\nimport { firstValueFrom } from 'rxjs';\nimport { IFileManager } from '../../interfaces/file-manager.interface';\nimport { IFolder } from '../../interfaces/folder.interface';\nimport { IStorageConfig } from '../../interfaces/storage-config.interface';\nimport { FileManagerApiService } from '../../services/file-manager-api.service';\nimport { FolderApiService } from '../../services/folder-api.service';\nimport { StorageConfigApiService } from '../../services/storage-config-api.service';\nimport { UploadService } from '../../services/upload.service';\nimport { BaseStoragePage } from '../../utils/base-storage-page';\nimport { formatFileSize, getProviderLabelKey } from '../../utils/storage-utils';\n\ninterface IFileManagerFormModel {\n id: string;\n name: string;\n isPrivate: boolean;\n folderId: string;\n storageConfigId: string;\n}\n\n@Component({\n selector: 'lib-file-manager-form',\n imports: [AngularModule, PrimeModule, FormField, TranslatePipe],\n template: `\n <div class=\"card\">\n <div class=\"mb-4\">\n <h3 class=\"text-lg sm:text-xl font-semibold\">{{ (isEditMode() ? 'storage.file.manager.edit.file' : 'storage.file.manager.upload.file') | translate }}</h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">{{ 'storage.company' | translate }}: {{ currentCompanyName() }}</p>\n }\n </div>\n\n <form (ngSubmit)=\"onSubmit()\">\n @if (!isEditMode()) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mb-4\">\n <div class=\"field\">\n <label for=\"storageConfig\" class=\"block font-medium mb-2 text-sm sm:text-base\">{{ 'storage.config.provider.required' | translate }}</label>\n <select id=\"storageConfig\" class=\"p-select-native w-full\" [formField]=\"fileForm.storageConfigId\">\n <option value=\"\">{{ 'storage.config.select.config' | translate }}</option>\n @for (config of availableConfigs(); track config.id) {\n <option [value]=\"config.id\">{{ config.name }} ({{ getProviderLabelKey(config.storage) | translate }})</option>\n }\n </select>\n @if (availableConfigs().length === 0 && !isLoadingConfigs()) {\n <small class=\"text-warn block mt-2\">\n <i class=\"pi pi-exclamation-triangle mr-1\"></i>\n {{ 'storage.config.no.configs' | translate }}\n </small>\n }\n </div>\n\n <div class=\"field\">\n <label for=\"folder\" class=\"block font-medium mb-2 text-sm sm:text-base\">{{ 'storage.folder.optional' | translate }}</label>\n <select id=\"folder\" class=\"p-select-native w-full\" [formField]=\"fileForm.folderId\">\n <option value=\"\">{{ 'storage.folder.no.folder' | translate }}</option>\n @for (folder of availableFolders(); track folder.id) {\n <option [value]=\"folder.id\">{{ folder.name }}</option>\n }\n </select>\n @if (availableFolders().length === 0 && !isLoadingFolders()) {\n <small class=\"text-muted-color block mt-2\">\n <i class=\"pi pi-info-circle mr-1\"></i>\n {{ 'storage.folder.no.folders.available' | translate }}\n </small>\n }\n </div>\n </div>\n } @else {\n <div class=\"field mb-4\">\n <label for=\"folder\" class=\"block font-medium mb-2 text-sm sm:text-base\">{{ 'storage.folder.optional' | translate }}</label>\n <select id=\"folder\" class=\"p-select-native w-full\" [formField]=\"fileForm.folderId\">\n <option value=\"\">{{ 'storage.folder.no.folder' | translate }}</option>\n @for (folder of availableFolders(); track folder.id) {\n <option [value]=\"folder.id\">{{ folder.name }}</option>\n }\n </select>\n @if (availableFolders().length === 0 && !isLoadingFolders()) {\n <small class=\"text-muted-color block mt-2\">\n <i class=\"pi pi-info-circle mr-1\"></i>\n {{ 'storage.folder.no.folders.edit' | translate }}\n </small>\n }\n </div>\n }\n\n @if (!isEditMode()) {\n <div class=\"field mb-4\">\n <label class=\"block font-medium mb-2 text-sm sm:text-base\">{{ 'storage.file.select.required' | translate }}</label>\n <p-fileupload\n #fileUpload\n [customUpload]=\"true\"\n (onSelect)=\"onFileSelect($event)\"\n [multiple]=\"false\"\n [maxFileSize]=\"50000000\"\n [showUploadButton]=\"false\"\n [showCancelButton]=\"false\"\n [chooseLabel]=\"'storage.button.choose.file' | translate\"\n chooseIcon=\"pi pi-upload\"\n accept=\"*/*\"\n class=\"w-full\"\n >\n <ng-template #content let-files>\n @if (files && files.length > 0) {\n <div class=\"flex flex-col gap-2\">\n @for (file of files; track file.name) {\n <div class=\"flex items-center gap-3 p-3 border border-surface rounded-lg bg-surface-ground\">\n <i class=\"pi pi-file text-xl sm:text-2xl text-primary\"></i>\n <div class=\"flex-1 min-w-0\">\n <div class=\"font-medium truncate\">{{ file.name }}</div>\n <div class=\"text-sm text-muted-color\">{{ formatFileSize(file.size) }}</div>\n </div>\n <p-button icon=\"pi pi-times\" [text]=\"true\" severity=\"danger\" size=\"small\" (onClick)=\"fileUpload.clear()\" />\n </div>\n }\n </div>\n } @else {\n <div class=\"flex items-center justify-center flex-col p-6 sm:p-8 border-2 border-dashed border-surface rounded-lg\">\n <i class=\"pi pi-cloud-upload text-3xl sm:text-4xl text-muted-color mb-3\"></i>\n <p class=\"text-muted-color text-center text-sm sm:text-base\">{{ 'storage.upload.drag.drop' | translate }}</p>\n <p class=\"text-xs sm:text-sm text-muted-color mt-2\">{{ 'storage.upload.max.size' | translate: { size: '50MB' } }}</p>\n </div>\n }\n </ng-template>\n </p-fileupload>\n @if (!selectedFile() && !isEditMode()) {\n <small class=\"text-muted-color\">{{ 'storage.upload.please.select' | translate }}</small>\n }\n </div>\n }\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div class=\"field md:col-span-2\">\n <label for=\"name\" class=\"block font-medium mb-2 text-sm sm:text-base\">{{ 'storage.file.name.required' | translate }}</label>\n <input pInputText id=\"name\" [formField]=\"fileForm.name\" [placeholder]=\"(isEditMode() ? 'storage.file.placeholder.edit' : 'storage.file.placeholder') | translate\" class=\"w-full\" />\n </div>\n\n <div class=\"field\">\n <label class=\"p-checkbox-native flex items-center gap-2\">\n <input type=\"checkbox\" [formField]=\"fileForm.isPrivate\" />\n <span>{{ 'storage.file.private' | translate }}</span>\n </label>\n <small class=\"text-muted-color block mt-2\">\n {{ (formModel().isPrivate ? 'storage.file.private.hint' : 'storage.file.public.hint') | translate }}\n </small>\n </div>\n </div>\n\n <div class=\"flex justify-end gap-2 mt-4\">\n <p-button [label]=\"'shared.cancel' | translate\" severity=\"secondary\" [outlined]=\"true\" (onClick)=\"onCancel()\" />\n <p-button\n type=\"submit\"\n [label]=\"(isEditMode() ? 'shared.update' : 'storage.button.upload') | translate\"\n [loading]=\"isLoading()\"\n [disabled]=\"!isFormValid() || (!isEditMode() && !selectedFile()) || isLoading()\"\n />\n </div>\n </form>\n </div>\n `,\n})\nexport class FileManagerFormComponent extends BaseStoragePage {\n private readonly route = inject(ActivatedRoute);\n private readonly fileService = inject(FileManagerApiService);\n private readonly uploadService = inject(UploadService);\n private readonly configService = inject(StorageConfigApiService);\n private readonly folderService = inject(FolderApiService);\n private readonly translateService = inject(TranslateService);\n\n private readonly routeParams = toSignal(this.route.paramMap);\n private initialized = false;\n\n readonly isLoadingConfigs = signal(false);\n readonly isLoadingFolders = signal(false);\n readonly existingFile = signal<IFileManager | null>(null);\n readonly isEditMode = computed(() => !!this.existingFile());\n readonly selectedFile = signal<File | null>(null);\n readonly availableConfigs = signal<IStorageConfig[]>([]);\n readonly availableFolders = signal<IFolder[]>([]);\n\n readonly formatFileSize = formatFileSize;\n readonly getProviderLabelKey = getProviderLabelKey;\n\n readonly formModel = signal<IFileManagerFormModel>({\n id: '',\n name: '',\n isPrivate: false,\n folderId: '',\n storageConfigId: '',\n });\n\n readonly fileForm = form(this.formModel, (f) => {\n required(f.name, { message: this.translateService.translate('storage.validation.file.name.required') });\n });\n\n readonly isFormValid = computed(() => this.formModel().name.trim().length > 0);\n\n constructor() {\n super();\n effect(() => {\n const params = this.routeParams();\n if (!params || this.initialized) return;\n\n this.initialized = true;\n const fileId = params.get('id');\n if (fileId) {\n this.loadFile(fileId);\n } else {\n this.loadStorageConfigs();\n }\n this.loadFolders();\n });\n }\n\n async loadStorageConfigs(): Promise<void> {\n this.isLoadingConfigs.set(true);\n try {\n const response = await firstValueFrom(\n this.configService.getAll('', {\n pagination: { currentPage: 0, pageSize: 100 },\n filter: {},\n select: [],\n sort: {},\n }),\n );\n if (response.success && response.data) {\n this.availableConfigs.set(response.data);\n if (response.data.length === 1) {\n this.formModel.update((m) => ({ ...m, storageConfigId: response.data![0].id }));\n }\n }\n } catch {\n this.showError(this.translateService.translate('storage.config.load.failed'));\n } finally {\n this.isLoadingConfigs.set(false);\n }\n }\n\n async loadFolders(): Promise<void> {\n this.isLoadingFolders.set(true);\n try {\n const response = await firstValueFrom(\n this.folderService.getAll('', {\n pagination: { currentPage: 0, pageSize: 100 },\n filter: {},\n select: [],\n sort: {},\n }),\n );\n if (response.success && response.data) {\n this.availableFolders.set(response.data);\n }\n } catch {\n // Silently fail - folders are optional\n } finally {\n this.isLoadingFolders.set(false);\n }\n }\n\n async loadFile(id: string): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await this.fileService.findByIdAsync(id);\n if (response.success && response.data) {\n const file = response.data;\n this.existingFile.set(file);\n this.formModel.set({\n id: file.id,\n name: file.name,\n isPrivate: file.isPrivate ?? false,\n folderId: file.folderId ?? '',\n storageConfigId: '',\n });\n }\n } catch {\n this.showError(this.translateService.translate('storage.error.load.file.failed'));\n this.navigateTo(['/storage/files']);\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onFileSelect(event: { files?: File[]; currentFiles?: File[] }): void {\n const file = event.files?.[0] || event.currentFiles?.[0];\n if (file) {\n this.selectedFile.set(file);\n this.formModel.update((m) => ({ ...m, name: file.name }));\n }\n }\n\n async onSubmit(): Promise<void> {\n if (!this.isFormValid()) return;\n\n this.isLoading.set(true);\n try {\n const formValue = this.formModel();\n\n if (this.isEditMode()) {\n await this.fileService.updateAsync({\n id: formValue.id,\n name: formValue.name,\n isPrivate: formValue.isPrivate,\n folderId: formValue.folderId || null,\n });\n this.showSuccess(this.translateService.translate('storage.file.update.success'));\n } else {\n const file = this.selectedFile();\n if (!file) {\n this.showError(this.translateService.translate('storage.error.no.file'));\n return;\n }\n\n if (!formValue.storageConfigId) {\n this.showError(this.translateService.translate('storage.error.no.config'));\n return;\n }\n\n const uploadResponse = await firstValueFrom(\n this.uploadService.uploadSingleFile(file, {\n compress: true,\n quality: 85,\n storageConfigId: formValue.storageConfigId,\n }),\n );\n\n if (uploadResponse.success && uploadResponse.data) {\n const uploadedFileInfo = uploadResponse.data;\n await firstValueFrom(\n this.fileService.createFile({\n name: formValue.name,\n key: uploadedFileInfo.key,\n contentType: file.type || 'application/octet-stream',\n size: Math.round(file.size / 1024).toString(),\n isPrivate: formValue.isPrivate,\n folderId: formValue.folderId || undefined,\n storageConfigId: formValue.storageConfigId,\n }),\n );\n this.showSuccess(this.translateService.translate('storage.upload.success'));\n } else {\n throw new Error(this.translateService.translate('storage.upload.failed'));\n }\n }\n\n this.navigateTo(['/storage/files']);\n } catch {\n this.showError(this.translateService.translate('storage.upload.failed'));\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onCancel(): void {\n this.navigateTo(['/storage/files']);\n }\n}\n"],"names":["i2","i4"],"mappings":"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"}
|