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