@flusys/ng-storage 1.1.1-beta → 1.2.0-rc.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.
Files changed (29) hide show
  1. package/README.md +36 -623
  2. package/fesm2022/flusys-ng-storage-file-manager-form.component-DhqZmpuX.mjs +671 -0
  3. package/fesm2022/flusys-ng-storage-file-manager-form.component-DhqZmpuX.mjs.map +1 -0
  4. package/fesm2022/flusys-ng-storage-file-manager-list.component-nZDj1UfS.mjs +464 -0
  5. package/fesm2022/flusys-ng-storage-file-manager-list.component-nZDj1UfS.mjs.map +1 -0
  6. package/fesm2022/flusys-ng-storage-folder-form.component-Bru9NQyr.mjs +218 -0
  7. package/fesm2022/flusys-ng-storage-folder-form.component-Bru9NQyr.mjs.map +1 -0
  8. package/fesm2022/flusys-ng-storage-folder-list.component-fuJMWYWZ.mjs +263 -0
  9. package/fesm2022/flusys-ng-storage-folder-list.component-fuJMWYWZ.mjs.map +1 -0
  10. package/fesm2022/flusys-ng-storage-storage-config-form.component-Da-pWR7d.mjs +891 -0
  11. package/fesm2022/flusys-ng-storage-storage-config-form.component-Da-pWR7d.mjs.map +1 -0
  12. package/fesm2022/flusys-ng-storage-storage-config-list.component-D59X4sae.mjs +288 -0
  13. package/fesm2022/flusys-ng-storage-storage-config-list.component-D59X4sae.mjs.map +1 -0
  14. package/fesm2022/flusys-ng-storage.mjs +679 -321
  15. package/fesm2022/flusys-ng-storage.mjs.map +1 -1
  16. package/package.json +11 -10
  17. package/types/flusys-ng-storage.d.ts +179 -178
  18. package/fesm2022/flusys-ng-storage-file-manager-form.component-H3OZS0SW.mjs +0 -715
  19. package/fesm2022/flusys-ng-storage-file-manager-form.component-H3OZS0SW.mjs.map +0 -1
  20. package/fesm2022/flusys-ng-storage-file-manager-list.component-4pb6TafD.mjs +0 -475
  21. package/fesm2022/flusys-ng-storage-file-manager-list.component-4pb6TafD.mjs.map +0 -1
  22. package/fesm2022/flusys-ng-storage-folder-form.component-DQ0QY7P0.mjs +0 -253
  23. package/fesm2022/flusys-ng-storage-folder-form.component-DQ0QY7P0.mjs.map +0 -1
  24. package/fesm2022/flusys-ng-storage-folder-list.component-D-oMaEgl.mjs +0 -267
  25. package/fesm2022/flusys-ng-storage-folder-list.component-D-oMaEgl.mjs.map +0 -1
  26. package/fesm2022/flusys-ng-storage-storage-config-form.component-CjIAxfHC.mjs +0 -546
  27. package/fesm2022/flusys-ng-storage-storage-config-form.component-CjIAxfHC.mjs.map +0 -1
  28. package/fesm2022/flusys-ng-storage-storage-config-list.component-jHk8O9Mx.mjs +0 -328
  29. package/fesm2022/flusys-ng-storage-storage-config-list.component-jHk8O9Mx.mjs.map +0 -1
@@ -1,715 +0,0 @@
1
- import * as i0 from '@angular/core';
2
- import { inject, signal, computed, Component } from '@angular/core';
3
- import { form, required, FormField } from '@angular/forms/signals';
4
- import { Router, ActivatedRoute } from '@angular/router';
5
- import { APP_CONFIG, DEFAULT_APP_NAME } from '@flusys/ng-core';
6
- import { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';
7
- import { AngularModule, PrimeModule } from '@flusys/ng-shared';
8
- import { MessageService } from 'primeng/api';
9
- import { firstValueFrom } from 'rxjs';
10
- import { FileManagerApiService, UploadService, StorageConfigApiService, FolderApiService } from './flusys-ng-storage.mjs';
11
- import * as i1 from '@angular/forms';
12
- import * as i1$1 from 'primeng/button';
13
- import * as i3 from 'primeng/fileupload';
14
- import * as i3$1 from 'primeng/inputtext';
15
-
16
- /**
17
- * File Manager Form Component
18
- * Upload and edit file metadata
19
- */
20
- class FileManagerFormComponent {
21
- router = inject(Router);
22
- route = inject(ActivatedRoute);
23
- messageService = inject(MessageService);
24
- fileService = inject(FileManagerApiService);
25
- uploadService = inject(UploadService);
26
- configService = inject(StorageConfigApiService);
27
- folderService = inject(FolderApiService);
28
- appConfig = inject(APP_CONFIG);
29
- companyContext = inject(LAYOUT_AUTH_STATE);
30
- isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
31
- isLoadingConfigs = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingConfigs" }] : []));
32
- isLoadingFolders = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingFolders" }] : []));
33
- existingFile = signal(null, ...(ngDevMode ? [{ debugName: "existingFile" }] : []));
34
- isEditMode = computed(() => !!this.existingFile(), ...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
35
- selectedFile = signal(null, ...(ngDevMode ? [{ debugName: "selectedFile" }] : []));
36
- availableConfigs = signal([], ...(ngDevMode ? [{ debugName: "availableConfigs" }] : []));
37
- availableFolders = signal([], ...(ngDevMode ? [{ debugName: "availableFolders" }] : []));
38
- showCompanyInfo = computed(() => this.appConfig.enableCompanyFeature, ...(ngDevMode ? [{ debugName: "showCompanyInfo" }] : []));
39
- currentCompanyName = computed(() => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME, ...(ngDevMode ? [{ debugName: "currentCompanyName" }] : []));
40
- // ============================================
41
- // Form (Signal Forms)
42
- // ============================================
43
- /** Form model */
44
- formModel = signal({
45
- id: '',
46
- name: '',
47
- isPrivate: false,
48
- folderId: '',
49
- storageConfigId: '',
50
- }, ...(ngDevMode ? [{ debugName: "formModel" }] : []));
51
- /** Form with validation schema */
52
- fileForm = form(this.formModel, (f) => {
53
- required(f.name, { message: 'File name is required' });
54
- // storageConfigId validation will be done manually in onSubmit
55
- // as it's only required for new uploads, not edits
56
- });
57
- /** Check if form is valid */
58
- isFormValid = computed(() => {
59
- const model = this.formModel();
60
- return model.name.trim().length > 0;
61
- }, ...(ngDevMode ? [{ debugName: "isFormValid" }] : []));
62
- ngOnInit() {
63
- const fileId = this.route.snapshot.paramMap.get('id');
64
- if (fileId) {
65
- this.loadFile(fileId);
66
- }
67
- else {
68
- // Load storage configurations for new upload
69
- this.loadStorageConfigs();
70
- }
71
- // Load folders for both create and edit modes
72
- this.loadFolders();
73
- }
74
- async loadStorageConfigs() {
75
- this.isLoadingConfigs.set(true);
76
- try {
77
- const response = await firstValueFrom(this.configService.getAll('', {
78
- pagination: { currentPage: 0, pageSize: 100 },
79
- filter: {},
80
- select: [],
81
- sort: {},
82
- }));
83
- if (response.success && response.data) {
84
- this.availableConfigs.set(response.data);
85
- // Auto-select first config if only one available
86
- if (response.data.length === 1) {
87
- this.formModel.update((m) => ({
88
- ...m,
89
- storageConfigId: response.data[0].id,
90
- }));
91
- }
92
- }
93
- }
94
- catch (error) {
95
- this.messageService.add({
96
- severity: 'error',
97
- summary: 'Error',
98
- detail: 'Failed to load storage configurations.',
99
- });
100
- }
101
- finally {
102
- this.isLoadingConfigs.set(false);
103
- }
104
- }
105
- async loadFolders() {
106
- this.isLoadingFolders.set(true);
107
- try {
108
- const response = await firstValueFrom(this.folderService.getAll('', {
109
- pagination: { currentPage: 0, pageSize: 100 },
110
- filter: {},
111
- select: [],
112
- sort: {},
113
- }));
114
- if (response.success && response.data) {
115
- this.availableFolders.set(response.data);
116
- }
117
- }
118
- catch {
119
- // Silently fail - folders are optional
120
- }
121
- finally {
122
- this.isLoadingFolders.set(false);
123
- }
124
- }
125
- async loadFile(id) {
126
- this.isLoading.set(true);
127
- try {
128
- const response = await this.fileService.findByIdAsync(id);
129
- if (response.success && response.data) {
130
- const file = response.data;
131
- this.existingFile.set(file);
132
- this.formModel.set({
133
- id: file.id,
134
- name: file.name,
135
- isPrivate: file.isPrivate ?? false,
136
- folderId: file.folderId ?? '',
137
- storageConfigId: '',
138
- });
139
- }
140
- }
141
- catch (error) {
142
- this.messageService.add({
143
- severity: 'error',
144
- summary: 'Error',
145
- detail: 'Failed to load file.',
146
- });
147
- this.router.navigate(['/storage/files']);
148
- }
149
- finally {
150
- this.isLoading.set(false);
151
- }
152
- }
153
- onFileSelect(event) {
154
- const file = event.files?.[0] || event.currentFiles?.[0];
155
- if (file) {
156
- this.selectedFile.set(file);
157
- // Auto-fill file name
158
- this.formModel.update((m) => ({ ...m, name: file.name }));
159
- }
160
- }
161
- async onSubmit() {
162
- if (!this.isFormValid())
163
- return;
164
- this.isLoading.set(true);
165
- try {
166
- const formValue = this.formModel();
167
- if (this.isEditMode()) {
168
- // Update existing file metadata only
169
- await this.fileService.updateAsync({
170
- id: formValue.id,
171
- name: formValue.name,
172
- isPrivate: formValue.isPrivate,
173
- folderId: formValue.folderId || null,
174
- });
175
- this.messageService.add({
176
- severity: 'success',
177
- summary: 'Success',
178
- detail: 'File updated successfully.',
179
- });
180
- }
181
- else {
182
- // Upload new file
183
- const file = this.selectedFile();
184
- if (!file) {
185
- this.messageService.add({
186
- severity: 'error',
187
- summary: 'Error',
188
- detail: 'Please select a file to upload.',
189
- });
190
- return;
191
- }
192
- // Validate storage config selection
193
- if (!formValue.storageConfigId) {
194
- this.messageService.add({
195
- severity: 'error',
196
- summary: 'Error',
197
- detail: 'Please select a storage configuration.',
198
- });
199
- return;
200
- }
201
- // Upload file first
202
- const uploadResponse = await firstValueFrom(this.uploadService.uploadSingleFile(file, {
203
- compress: true,
204
- quality: 85,
205
- storageConfigId: formValue.storageConfigId,
206
- }));
207
- if (uploadResponse.success && uploadResponse.data) {
208
- const uploadedFileInfo = uploadResponse.data;
209
- // Save file metadata
210
- await this.fileService.insertAsync({
211
- name: formValue.name,
212
- key: uploadedFileInfo.key,
213
- contentType: file.type || 'application/octet-stream',
214
- size: Math.round(file.size / 1024).toString(),
215
- isPrivate: formValue.isPrivate,
216
- folderId: formValue.folderId || undefined,
217
- storageConfigId: formValue.storageConfigId, // ✅ Include storage config ID
218
- });
219
- this.messageService.add({
220
- severity: 'success',
221
- summary: 'Success',
222
- detail: 'File uploaded successfully.',
223
- });
224
- }
225
- else {
226
- throw new Error('Upload failed');
227
- }
228
- }
229
- this.router.navigate(['/storage/files']);
230
- }
231
- catch (error) {
232
- this.messageService.add({
233
- severity: 'error',
234
- summary: 'Error',
235
- detail: error?.message ||
236
- `Failed to ${this.isEditMode() ? 'update' : 'upload'} file.`,
237
- });
238
- }
239
- finally {
240
- this.isLoading.set(false);
241
- }
242
- }
243
- onCancel() {
244
- this.router.navigate(['/storage/files']);
245
- }
246
- formatFileSize(bytes) {
247
- if (bytes === 0)
248
- return '0 Bytes';
249
- const k = 1024;
250
- const sizes = ['Bytes', 'KB', 'MB', 'GB'];
251
- const i = Math.floor(Math.log(bytes) / Math.log(k));
252
- return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
253
- }
254
- getProviderLabel(storage) {
255
- const labels = {
256
- AWS: 'AWS S3',
257
- AZURE: 'Azure Blob',
258
- SFTP: 'SFTP',
259
- LOCAL: 'Local',
260
- };
261
- return labels[storage] || storage;
262
- }
263
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: FileManagerFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
264
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: FileManagerFormComponent, isStandalone: true, selector: "lib-file-manager-form", ngImport: i0, template: `
265
- <div class="card">
266
- <div class="flex justify-between items-center mb-4">
267
- <div>
268
- <h3 class="text-xl font-semibold">
269
- {{ isEditMode() ? 'Edit File' : 'Upload File' }}
270
- </h3>
271
- @if (showCompanyInfo()) {
272
- <p class="text-sm text-muted-color mt-1">
273
- Company: {{ currentCompanyName() }}
274
- </p>
275
- }
276
- </div>
277
- <p-button
278
- label="Back"
279
- icon="pi pi-arrow-left"
280
- severity="secondary"
281
- [text]="true"
282
- (onClick)="onCancel()"
283
- />
284
- </div>
285
-
286
- <form (ngSubmit)="onSubmit()">
287
- <!-- Storage Configuration & Folder Selection (only for new files) -->
288
- @if (!isEditMode()) {
289
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
290
- <!-- Storage Configuration -->
291
- <div class="field">
292
- <label for="storageConfig" class="block font-medium mb-2"
293
- >Storage Configuration *</label
294
- >
295
- <select
296
- id="storageConfig"
297
- class="p-select-native"
298
- [formField]="fileForm.storageConfigId"
299
- >
300
- <option value="">Select storage configuration...</option>
301
- @for (config of availableConfigs(); track config.id) {
302
- <option [value]="config.id">
303
- {{ config.name }} ({{ getProviderLabel(config.storage) }})
304
- </option>
305
- }
306
- </select>
307
- @if (availableConfigs().length === 0 && !isLoadingConfigs()) {
308
- <small class="text-warn block mt-2">
309
- <i class="pi pi-exclamation-triangle mr-1"></i>
310
- No storage configurations found. Please create one first.
311
- </small>
312
- }
313
- </div>
314
-
315
- <!-- Folder Selection -->
316
- <div class="field">
317
- <label for="folder" class="block font-medium mb-2"
318
- >Folder (Optional)</label
319
- >
320
- <select
321
- id="folder"
322
- class="p-select-native"
323
- [formField]="fileForm.folderId"
324
- >
325
- <option value="">No folder (root level)</option>
326
- @for (folder of availableFolders(); track folder.id) {
327
- <option [value]="folder.id">{{ folder.name }}</option>
328
- }
329
- </select>
330
- @if (availableFolders().length === 0 && !isLoadingFolders()) {
331
- <small class="text-muted-color block mt-2">
332
- <i class="pi pi-info-circle mr-1"></i>
333
- No folders available. File will be uploaded to root level.
334
- </small>
335
- }
336
- </div>
337
- </div>
338
- } @else {
339
- <!-- Folder Selection for Edit Mode -->
340
- <div class="field mb-4">
341
- <label for="folder" class="block font-medium mb-2"
342
- >Folder (Optional)</label
343
- >
344
- <select
345
- id="folder"
346
- class="p-select-native"
347
- [formField]="fileForm.folderId"
348
- >
349
- <option value="">No folder (root level)</option>
350
- @for (folder of availableFolders(); track folder.id) {
351
- <option [value]="folder.id">{{ folder.name }}</option>
352
- }
353
- </select>
354
- @if (availableFolders().length === 0 && !isLoadingFolders()) {
355
- <small class="text-muted-color block mt-2">
356
- <i class="pi pi-info-circle mr-1"></i>
357
- No folders available.
358
- </small>
359
- }
360
- </div>
361
- }
362
-
363
- <!-- File Upload (only for new files) -->
364
- @if (!isEditMode()) {
365
- <div class="field mb-4">
366
- <label class="block font-medium mb-2">Select File *</label>
367
- <p-fileupload
368
- #fileUpload
369
- [customUpload]="true"
370
- (onSelect)="onFileSelect($event)"
371
- [multiple]="false"
372
- [maxFileSize]="50000000"
373
- [showUploadButton]="false"
374
- [showCancelButton]="false"
375
- chooseLabel="Choose File"
376
- chooseIcon="pi pi-upload"
377
- accept="*/*"
378
- class="w-full"
379
- >
380
- <ng-template #content let-files>
381
- @if (files && files.length > 0) {
382
- <div class="flex flex-col gap-2">
383
- @for (file of files; track file.name) {
384
- <div class="flex items-center gap-3 p-3 border rounded">
385
- <i class="pi pi-file text-2xl"></i>
386
- <div class="flex-1">
387
- <div class="font-medium">{{ file.name }}</div>
388
- <div class="text-sm text-muted-color">
389
- {{ formatFileSize(file.size) }}
390
- </div>
391
- </div>
392
- <p-button
393
- icon="pi pi-times"
394
- [text]="true"
395
- severity="danger"
396
- size="small"
397
- (onClick)="fileUpload.clear()"
398
- />
399
- </div>
400
- }
401
- </div>
402
- } @else {
403
- <div
404
- class="flex items-center justify-center flex-col p-8 border-2 border-dashed border-surface-300 rounded"
405
- >
406
- <i
407
- class="pi pi-cloud-upload text-4xl text-muted-color mb-3"
408
- ></i>
409
- <p class="text-muted-color">
410
- Drag and drop file here or click to browse
411
- </p>
412
- <p class="text-sm text-muted-color mt-2">
413
- Maximum file size: 50MB
414
- </p>
415
- </div>
416
- }
417
- </ng-template>
418
- </p-fileupload>
419
- @if (!selectedFile() && !isEditMode()) {
420
- <small class="text-muted-color"
421
- >Please select a file to upload</small
422
- >
423
- }
424
- </div>
425
- }
426
-
427
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
428
- <!-- File Name (read-only for uploads, editable for existing) -->
429
- <div class="field md:col-span-2">
430
- <label for="name" class="block font-medium mb-2">File Name *</label>
431
- <input
432
- pInputText
433
- id="name"
434
- [formField]="fileForm.name"
435
- [placeholder]="
436
- isEditMode()
437
- ? 'Enter file name'
438
- : 'Will be auto-filled from selected file'
439
- "
440
- class="w-full"
441
- />
442
- </div>
443
-
444
- <!-- Privacy Toggle -->
445
- <div class="field">
446
- <label class="p-checkbox-native">
447
- <input type="checkbox" [formField]="fileForm.isPrivate" />
448
- <span>Private File</span>
449
- </label>
450
- <small class="text-muted-color block mt-2">
451
- {{
452
- formModel().isPrivate
453
- ? 'Only users with permission can access'
454
- : 'File is publicly accessible'
455
- }}
456
- </small>
457
- </div>
458
- </div>
459
-
460
- <div class="flex gap-2 mt-4">
461
- <p-button
462
- type="submit"
463
- [label]="isEditMode() ? 'Update' : 'Upload'"
464
- [icon]="isEditMode() ? 'pi pi-check' : 'pi pi-cloud-upload'"
465
- [loading]="isLoading()"
466
- [disabled]="
467
- !isFormValid() ||
468
- (!isEditMode() && !selectedFile()) ||
469
- isLoading()
470
- "
471
- />
472
- <p-button
473
- type="button"
474
- label="Cancel"
475
- severity="secondary"
476
- icon="pi pi-times"
477
- [text]="true"
478
- (onClick)="onCancel()"
479
- />
480
- </div>
481
- </form>
482
- </div>
483
- `, 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"] }] });
484
- }
485
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: FileManagerFormComponent, decorators: [{
486
- type: Component,
487
- args: [{
488
- selector: 'lib-file-manager-form',
489
- standalone: true,
490
- imports: [AngularModule, PrimeModule, FormField],
491
- template: `
492
- <div class="card">
493
- <div class="flex justify-between items-center mb-4">
494
- <div>
495
- <h3 class="text-xl font-semibold">
496
- {{ isEditMode() ? 'Edit File' : 'Upload File' }}
497
- </h3>
498
- @if (showCompanyInfo()) {
499
- <p class="text-sm text-muted-color mt-1">
500
- Company: {{ currentCompanyName() }}
501
- </p>
502
- }
503
- </div>
504
- <p-button
505
- label="Back"
506
- icon="pi pi-arrow-left"
507
- severity="secondary"
508
- [text]="true"
509
- (onClick)="onCancel()"
510
- />
511
- </div>
512
-
513
- <form (ngSubmit)="onSubmit()">
514
- <!-- Storage Configuration & Folder Selection (only for new files) -->
515
- @if (!isEditMode()) {
516
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
517
- <!-- Storage Configuration -->
518
- <div class="field">
519
- <label for="storageConfig" class="block font-medium mb-2"
520
- >Storage Configuration *</label
521
- >
522
- <select
523
- id="storageConfig"
524
- class="p-select-native"
525
- [formField]="fileForm.storageConfigId"
526
- >
527
- <option value="">Select storage configuration...</option>
528
- @for (config of availableConfigs(); track config.id) {
529
- <option [value]="config.id">
530
- {{ config.name }} ({{ getProviderLabel(config.storage) }})
531
- </option>
532
- }
533
- </select>
534
- @if (availableConfigs().length === 0 && !isLoadingConfigs()) {
535
- <small class="text-warn block mt-2">
536
- <i class="pi pi-exclamation-triangle mr-1"></i>
537
- No storage configurations found. Please create one first.
538
- </small>
539
- }
540
- </div>
541
-
542
- <!-- Folder Selection -->
543
- <div class="field">
544
- <label for="folder" class="block font-medium mb-2"
545
- >Folder (Optional)</label
546
- >
547
- <select
548
- id="folder"
549
- class="p-select-native"
550
- [formField]="fileForm.folderId"
551
- >
552
- <option value="">No folder (root level)</option>
553
- @for (folder of availableFolders(); track folder.id) {
554
- <option [value]="folder.id">{{ folder.name }}</option>
555
- }
556
- </select>
557
- @if (availableFolders().length === 0 && !isLoadingFolders()) {
558
- <small class="text-muted-color block mt-2">
559
- <i class="pi pi-info-circle mr-1"></i>
560
- No folders available. File will be uploaded to root level.
561
- </small>
562
- }
563
- </div>
564
- </div>
565
- } @else {
566
- <!-- Folder Selection for Edit Mode -->
567
- <div class="field mb-4">
568
- <label for="folder" class="block font-medium mb-2"
569
- >Folder (Optional)</label
570
- >
571
- <select
572
- id="folder"
573
- class="p-select-native"
574
- [formField]="fileForm.folderId"
575
- >
576
- <option value="">No folder (root level)</option>
577
- @for (folder of availableFolders(); track folder.id) {
578
- <option [value]="folder.id">{{ folder.name }}</option>
579
- }
580
- </select>
581
- @if (availableFolders().length === 0 && !isLoadingFolders()) {
582
- <small class="text-muted-color block mt-2">
583
- <i class="pi pi-info-circle mr-1"></i>
584
- No folders available.
585
- </small>
586
- }
587
- </div>
588
- }
589
-
590
- <!-- File Upload (only for new files) -->
591
- @if (!isEditMode()) {
592
- <div class="field mb-4">
593
- <label class="block font-medium mb-2">Select File *</label>
594
- <p-fileupload
595
- #fileUpload
596
- [customUpload]="true"
597
- (onSelect)="onFileSelect($event)"
598
- [multiple]="false"
599
- [maxFileSize]="50000000"
600
- [showUploadButton]="false"
601
- [showCancelButton]="false"
602
- chooseLabel="Choose File"
603
- chooseIcon="pi pi-upload"
604
- accept="*/*"
605
- class="w-full"
606
- >
607
- <ng-template #content let-files>
608
- @if (files && files.length > 0) {
609
- <div class="flex flex-col gap-2">
610
- @for (file of files; track file.name) {
611
- <div class="flex items-center gap-3 p-3 border rounded">
612
- <i class="pi pi-file text-2xl"></i>
613
- <div class="flex-1">
614
- <div class="font-medium">{{ file.name }}</div>
615
- <div class="text-sm text-muted-color">
616
- {{ formatFileSize(file.size) }}
617
- </div>
618
- </div>
619
- <p-button
620
- icon="pi pi-times"
621
- [text]="true"
622
- severity="danger"
623
- size="small"
624
- (onClick)="fileUpload.clear()"
625
- />
626
- </div>
627
- }
628
- </div>
629
- } @else {
630
- <div
631
- class="flex items-center justify-center flex-col p-8 border-2 border-dashed border-surface-300 rounded"
632
- >
633
- <i
634
- class="pi pi-cloud-upload text-4xl text-muted-color mb-3"
635
- ></i>
636
- <p class="text-muted-color">
637
- Drag and drop file here or click to browse
638
- </p>
639
- <p class="text-sm text-muted-color mt-2">
640
- Maximum file size: 50MB
641
- </p>
642
- </div>
643
- }
644
- </ng-template>
645
- </p-fileupload>
646
- @if (!selectedFile() && !isEditMode()) {
647
- <small class="text-muted-color"
648
- >Please select a file to upload</small
649
- >
650
- }
651
- </div>
652
- }
653
-
654
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
655
- <!-- File Name (read-only for uploads, editable for existing) -->
656
- <div class="field md:col-span-2">
657
- <label for="name" class="block font-medium mb-2">File Name *</label>
658
- <input
659
- pInputText
660
- id="name"
661
- [formField]="fileForm.name"
662
- [placeholder]="
663
- isEditMode()
664
- ? 'Enter file name'
665
- : 'Will be auto-filled from selected file'
666
- "
667
- class="w-full"
668
- />
669
- </div>
670
-
671
- <!-- Privacy Toggle -->
672
- <div class="field">
673
- <label class="p-checkbox-native">
674
- <input type="checkbox" [formField]="fileForm.isPrivate" />
675
- <span>Private File</span>
676
- </label>
677
- <small class="text-muted-color block mt-2">
678
- {{
679
- formModel().isPrivate
680
- ? 'Only users with permission can access'
681
- : 'File is publicly accessible'
682
- }}
683
- </small>
684
- </div>
685
- </div>
686
-
687
- <div class="flex gap-2 mt-4">
688
- <p-button
689
- type="submit"
690
- [label]="isEditMode() ? 'Update' : 'Upload'"
691
- [icon]="isEditMode() ? 'pi pi-check' : 'pi pi-cloud-upload'"
692
- [loading]="isLoading()"
693
- [disabled]="
694
- !isFormValid() ||
695
- (!isEditMode() && !selectedFile()) ||
696
- isLoading()
697
- "
698
- />
699
- <p-button
700
- type="button"
701
- label="Cancel"
702
- severity="secondary"
703
- icon="pi pi-times"
704
- [text]="true"
705
- (onClick)="onCancel()"
706
- />
707
- </div>
708
- </form>
709
- </div>
710
- `,
711
- }]
712
- }] });
713
-
714
- export { FileManagerFormComponent };
715
- //# sourceMappingURL=flusys-ng-storage-file-manager-form.component-H3OZS0SW.mjs.map