@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,546 +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 { AngularModule, PrimeModule } from '@flusys/ng-shared';
6
- import { APP_CONFIG } from '@flusys/ng-core';
7
- import { MessageService } from 'primeng/api';
8
- import { StorageConfigApiService, FileLocationEnum } from './flusys-ng-storage.mjs';
9
- import * as i1 from '@angular/forms';
10
- import * as i1$1 from 'primeng/button';
11
- import * as i3 from 'primeng/inputtext';
12
- import * as i4 from 'primeng/toggleswitch';
13
-
14
- /**
15
- * Storage Config Form Component
16
- * Create and edit storage configurations
17
- */
18
- class StorageConfigFormComponent {
19
- router = inject(Router);
20
- route = inject(ActivatedRoute);
21
- messageService = inject(MessageService);
22
- configService = inject(StorageConfigApiService);
23
- appConfig = inject(APP_CONFIG);
24
- fileLocationEnum = FileLocationEnum;
25
- isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
26
- existingConfig = signal(null, ...(ngDevMode ? [{ debugName: "existingConfig" }] : []));
27
- isEditMode = computed(() => !!this.existingConfig(), ...(ngDevMode ? [{ debugName: "isEditMode" }] : []));
28
- showCompanyInfo = computed(() => this.appConfig.enableCompanyFeature, ...(ngDevMode ? [{ debugName: "showCompanyInfo" }] : []));
29
- currentCompanyName = computed(() => 'Current Company', ...(ngDevMode ? [{ debugName: "currentCompanyName" }] : []));
30
- storageProviders = [
31
- { label: 'AWS S3', value: FileLocationEnum.AWS },
32
- { label: 'Azure Blob Storage', value: FileLocationEnum.AZURE },
33
- { label: 'SFTP', value: FileLocationEnum.SFTP },
34
- { label: 'Local Storage', value: FileLocationEnum.LOCAL },
35
- ];
36
- // ============================================
37
- // Form (Signal Forms)
38
- // ============================================
39
- /** Form model */
40
- formModel = signal({
41
- id: '',
42
- name: '',
43
- storage: FileLocationEnum.AWS,
44
- isActive: true,
45
- isDefault: false,
46
- // AWS S3
47
- awsRegion: '',
48
- awsBucket: '',
49
- awsAccessKeyId: '',
50
- awsSecretAccessKey: '',
51
- awsEndpoint: '',
52
- // Azure
53
- azureAccountName: '',
54
- azureAccountKey: '',
55
- azureContainerName: '',
56
- // SFTP
57
- sftpHost: '',
58
- sftpPort: '22',
59
- sftpUsername: '',
60
- sftpPassword: '',
61
- sftpBasePath: '',
62
- // Local
63
- localBasePath: '',
64
- }, ...(ngDevMode ? [{ debugName: "formModel" }] : []));
65
- /** Form with validation schema */
66
- configForm = form(this.formModel, (f) => {
67
- required(f.name, { message: 'Configuration name is required' });
68
- });
69
- /** Selected provider */
70
- selectedProvider = computed(() => this.formModel().storage, ...(ngDevMode ? [{ debugName: "selectedProvider" }] : []));
71
- /** Check if form is valid */
72
- isFormValid = computed(() => {
73
- const model = this.formModel();
74
- return model.name.trim().length > 0;
75
- }, ...(ngDevMode ? [{ debugName: "isFormValid" }] : []));
76
- ngOnInit() {
77
- const configId = this.route.snapshot.paramMap.get('id');
78
- if (configId) {
79
- this.loadConfig(configId);
80
- }
81
- }
82
- async loadConfig(id) {
83
- this.isLoading.set(true);
84
- try {
85
- const response = await this.configService.findByIdAsync(id);
86
- if (response.success && response.data) {
87
- const config = response.data;
88
- this.existingConfig.set(config);
89
- // Base form values
90
- const formData = {
91
- id: config.id,
92
- name: config.name,
93
- storage: config.storage,
94
- isActive: config.isActive ?? true,
95
- isDefault: config.isDefault ?? false,
96
- };
97
- // Load provider-specific config
98
- if (config.storage === FileLocationEnum.AWS && config.config) {
99
- formData.awsRegion = config.config['region'] || '';
100
- formData.awsBucket = config.config['bucket'] || '';
101
- formData.awsAccessKeyId = config.config['accessKeyId'] || '';
102
- formData.awsSecretAccessKey = config.config['secretAccessKey'] || '';
103
- formData.awsEndpoint = config.config['endpoint'] || '';
104
- }
105
- else if (config.storage === FileLocationEnum.AZURE && config.config) {
106
- formData.azureAccountName = config.config['accountName'] || '';
107
- formData.azureAccountKey = config.config['accountKey'] || '';
108
- formData.azureContainerName = config.config['containerName'] || '';
109
- }
110
- else if (config.storage === FileLocationEnum.SFTP && config.config) {
111
- formData.sftpHost = config.config['host'] || '';
112
- formData.sftpPort = (config.config['port'] || 22).toString();
113
- formData.sftpUsername = config.config['username'] || '';
114
- formData.sftpPassword = config.config['password'] || '';
115
- formData.sftpBasePath = config.config['basePath'] || '';
116
- }
117
- else if (config.storage === FileLocationEnum.LOCAL && config.config) {
118
- formData.localBasePath = config.config['basePath'] || '';
119
- }
120
- this.formModel.update((m) => ({ ...m, ...formData }));
121
- }
122
- }
123
- catch (error) {
124
- this.messageService.add({
125
- severity: 'error',
126
- summary: 'Error',
127
- detail: 'Failed to load storage configuration.',
128
- });
129
- this.router.navigate(['/storage/configs']);
130
- }
131
- finally {
132
- this.isLoading.set(false);
133
- }
134
- }
135
- async onSubmit() {
136
- if (!this.isFormValid())
137
- return;
138
- this.isLoading.set(true);
139
- try {
140
- const formValue = this.formModel();
141
- let config = {};
142
- // Build provider-specific config
143
- if (formValue.storage === FileLocationEnum.AWS) {
144
- config = {
145
- region: formValue.awsRegion,
146
- bucket: formValue.awsBucket,
147
- accessKeyId: formValue.awsAccessKeyId,
148
- secretAccessKey: formValue.awsSecretAccessKey,
149
- ...(formValue.awsEndpoint && { endpoint: formValue.awsEndpoint }),
150
- };
151
- }
152
- else if (formValue.storage === FileLocationEnum.AZURE) {
153
- config = {
154
- accountName: formValue.azureAccountName,
155
- accountKey: formValue.azureAccountKey,
156
- containerName: formValue.azureContainerName,
157
- };
158
- }
159
- else if (formValue.storage === FileLocationEnum.SFTP) {
160
- config = {
161
- host: formValue.sftpHost,
162
- port: formValue.sftpPort ? parseInt(formValue.sftpPort, 10) : 22,
163
- username: formValue.sftpUsername,
164
- password: formValue.sftpPassword,
165
- basePath: formValue.sftpBasePath,
166
- };
167
- }
168
- else if (formValue.storage === FileLocationEnum.LOCAL) {
169
- config = {
170
- basePath: formValue.localBasePath,
171
- };
172
- }
173
- if (this.isEditMode()) {
174
- await this.configService.updateAsync({
175
- id: formValue.id,
176
- name: formValue.name,
177
- storage: formValue.storage,
178
- config,
179
- isActive: formValue.isActive,
180
- isDefault: formValue.isDefault,
181
- });
182
- this.messageService.add({
183
- severity: 'success',
184
- summary: 'Success',
185
- detail: 'Storage configuration updated successfully.',
186
- });
187
- }
188
- else {
189
- await this.configService.insertAsync({
190
- name: formValue.name,
191
- storage: formValue.storage,
192
- config,
193
- isActive: formValue.isActive,
194
- isDefault: formValue.isDefault,
195
- });
196
- this.messageService.add({
197
- severity: 'success',
198
- summary: 'Success',
199
- detail: 'Storage configuration created successfully.',
200
- });
201
- }
202
- this.router.navigate(['/storage/configs']);
203
- }
204
- catch (error) {
205
- this.messageService.add({
206
- severity: 'error',
207
- summary: 'Error',
208
- detail: `Failed to ${this.isEditMode() ? 'update' : 'create'} storage configuration.`,
209
- });
210
- }
211
- finally {
212
- this.isLoading.set(false);
213
- }
214
- }
215
- onCancel() {
216
- this.router.navigate(['/storage/configs']);
217
- }
218
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: StorageConfigFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
219
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: StorageConfigFormComponent, isStandalone: true, selector: "lib-storage-config-form", ngImport: i0, template: `
220
- <div class="card">
221
- <div class="flex justify-between items-center mb-4">
222
- <div>
223
- <h3 class="text-xl font-semibold">
224
- {{ isEditMode() ? 'Edit Storage Configuration' : 'New Storage Configuration' }}
225
- </h3>
226
- @if (showCompanyInfo()) {
227
- <p class="text-sm text-muted-color mt-1">
228
- Company: {{ currentCompanyName() }}
229
- </p>
230
- }
231
- </div>
232
- <p-button
233
- label="Back"
234
- icon="pi pi-arrow-left"
235
- severity="secondary"
236
- [text]="true"
237
- (onClick)="onCancel()" />
238
- </div>
239
-
240
- <form (ngSubmit)="onSubmit()">
241
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
242
- <!-- Name -->
243
- <div class="field md:col-span-2">
244
- <label for="name" class="block font-medium mb-2">Configuration Name *</label>
245
- <input
246
- pInputText
247
- id="name"
248
- [formField]="configForm.name"
249
- placeholder="e.g., Production AWS S3"
250
- class="w-full" />
251
- </div>
252
-
253
- <!-- Storage Provider -->
254
- <div class="field md:col-span-2">
255
- <label for="storage" class="block font-medium mb-2">Storage Provider *</label>
256
- <select
257
- id="storage"
258
- class="p-select-native"
259
- [formField]="configForm.storage">
260
- @for (provider of storageProviders; track provider.value) {
261
- <option [value]="provider.value">{{ provider.label }}</option>
262
- }
263
- </select>
264
- </div>
265
-
266
- <!-- Active Toggle -->
267
- <div class="field flex items-center gap-2">
268
- <p-toggleswitch [formField]="configForm.isActive" />
269
- <label>Active</label>
270
- </div>
271
-
272
- <!-- Default Toggle -->
273
- <div class="field flex items-center gap-2">
274
- <p-toggleswitch [formField]="configForm.isDefault" />
275
- <label>Set as Default</label>
276
- </div>
277
- </div>
278
-
279
- <!-- AWS S3 Fields -->
280
- @if (selectedProvider() === fileLocationEnum.AWS) {
281
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
282
- <div class="field">
283
- <label for="awsRegion" class="block font-medium mb-2">AWS Region *</label>
284
- <input pInputText id="awsRegion" [formField]="configForm.awsRegion" placeholder="us-east-1" class="w-full" />
285
- </div>
286
- <div class="field">
287
- <label for="awsBucket" class="block font-medium mb-2">Bucket Name *</label>
288
- <input pInputText id="awsBucket" [formField]="configForm.awsBucket" placeholder="my-bucket" class="w-full" />
289
- </div>
290
- <div class="field">
291
- <label for="awsAccessKeyId" class="block font-medium mb-2">Access Key ID *</label>
292
- <input pInputText id="awsAccessKeyId" [formField]="configForm.awsAccessKeyId" class="w-full" />
293
- </div>
294
- <div class="field">
295
- <label for="awsSecretAccessKey" class="block font-medium mb-2">Secret Access Key *</label>
296
- <input type="password" pInputText id="awsSecretAccessKey" [formField]="configForm.awsSecretAccessKey" class="w-full" />
297
- </div>
298
- <div class="field md:col-span-2">
299
- <label for="awsEndpoint" class="block font-medium mb-2">Custom Endpoint (Optional)</label>
300
- <input pInputText id="awsEndpoint" [formField]="configForm.awsEndpoint" placeholder="https://s3.custom-endpoint.com" class="w-full" />
301
- </div>
302
- </div>
303
- }
304
-
305
- <!-- Azure Blob Fields -->
306
- @if (selectedProvider() === fileLocationEnum.AZURE) {
307
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
308
- <div class="field">
309
- <label for="azureAccountName" class="block font-medium mb-2">Account Name *</label>
310
- <input pInputText id="azureAccountName" [formField]="configForm.azureAccountName" class="w-full" />
311
- </div>
312
- <div class="field">
313
- <label for="azureContainerName" class="block font-medium mb-2">Container Name *</label>
314
- <input pInputText id="azureContainerName" [formField]="configForm.azureContainerName" class="w-full" />
315
- </div>
316
- <div class="field md:col-span-2">
317
- <label for="azureAccountKey" class="block font-medium mb-2">Account Key *</label>
318
- <input type="password" pInputText id="azureAccountKey" [formField]="configForm.azureAccountKey" class="w-full" />
319
- </div>
320
- </div>
321
- }
322
-
323
- <!-- SFTP Fields -->
324
- @if (selectedProvider() === fileLocationEnum.SFTP) {
325
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
326
- <div class="field">
327
- <label for="sftpHost" class="block font-medium mb-2">Host *</label>
328
- <input pInputText id="sftpHost" [formField]="configForm.sftpHost" placeholder="sftp.example.com" class="w-full" />
329
- </div>
330
- <div class="field">
331
- <label for="sftpPort" class="block font-medium mb-2">Port *</label>
332
- <input type="number" pInputText id="sftpPort" [formField]="configForm.sftpPort" placeholder="22" class="w-full" />
333
- </div>
334
- <div class="field">
335
- <label for="sftpUsername" class="block font-medium mb-2">Username *</label>
336
- <input pInputText id="sftpUsername" [formField]="configForm.sftpUsername" class="w-full" />
337
- </div>
338
- <div class="field">
339
- <label for="sftpPassword" class="block font-medium mb-2">Password *</label>
340
- <input type="password" pInputText id="sftpPassword" [formField]="configForm.sftpPassword" class="w-full" />
341
- </div>
342
- <div class="field md:col-span-2">
343
- <label for="sftpBasePath" class="block font-medium mb-2">Base Path *</label>
344
- <input pInputText id="sftpBasePath" [formField]="configForm.sftpBasePath" placeholder="/uploads" class="w-full" />
345
- </div>
346
- </div>
347
- }
348
-
349
- <!-- Local Fields -->
350
- @if (selectedProvider() === fileLocationEnum.LOCAL) {
351
- <div class="grid grid-cols-1 gap-4 mt-4">
352
- <div class="field">
353
- <label for="localBasePath" class="block font-medium mb-2">Base Path *</label>
354
- <input pInputText id="localBasePath" [formField]="configForm.localBasePath" placeholder="/var/www/uploads" class="w-full" />
355
- </div>
356
- </div>
357
- }
358
-
359
- <div class="flex gap-2 mt-4">
360
- <p-button
361
- type="submit"
362
- [label]="isEditMode() ? 'Update' : 'Create'"
363
- icon="pi pi-check"
364
- [loading]="isLoading()"
365
- [disabled]="!isFormValid() || isLoading()" />
366
- <p-button
367
- type="button"
368
- label="Cancel"
369
- severity="secondary"
370
- icon="pi pi-times"
371
- [text]="true"
372
- (onClick)="onCancel()" />
373
- </div>
374
- </form>
375
- </div>
376
- `, 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: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: i4.ToggleSwitch, selector: "p-toggleswitch, p-toggleSwitch, p-toggle-switch", inputs: ["styleClass", "tabindex", "inputId", "readonly", "trueValue", "falseValue", "ariaLabel", "size", "ariaLabelledBy", "autofocus"], outputs: ["onChange"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }] });
377
- }
378
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: StorageConfigFormComponent, decorators: [{
379
- type: Component,
380
- args: [{
381
- selector: 'lib-storage-config-form',
382
- standalone: true,
383
- imports: [AngularModule, PrimeModule, FormField],
384
- template: `
385
- <div class="card">
386
- <div class="flex justify-between items-center mb-4">
387
- <div>
388
- <h3 class="text-xl font-semibold">
389
- {{ isEditMode() ? 'Edit Storage Configuration' : 'New Storage Configuration' }}
390
- </h3>
391
- @if (showCompanyInfo()) {
392
- <p class="text-sm text-muted-color mt-1">
393
- Company: {{ currentCompanyName() }}
394
- </p>
395
- }
396
- </div>
397
- <p-button
398
- label="Back"
399
- icon="pi pi-arrow-left"
400
- severity="secondary"
401
- [text]="true"
402
- (onClick)="onCancel()" />
403
- </div>
404
-
405
- <form (ngSubmit)="onSubmit()">
406
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
407
- <!-- Name -->
408
- <div class="field md:col-span-2">
409
- <label for="name" class="block font-medium mb-2">Configuration Name *</label>
410
- <input
411
- pInputText
412
- id="name"
413
- [formField]="configForm.name"
414
- placeholder="e.g., Production AWS S3"
415
- class="w-full" />
416
- </div>
417
-
418
- <!-- Storage Provider -->
419
- <div class="field md:col-span-2">
420
- <label for="storage" class="block font-medium mb-2">Storage Provider *</label>
421
- <select
422
- id="storage"
423
- class="p-select-native"
424
- [formField]="configForm.storage">
425
- @for (provider of storageProviders; track provider.value) {
426
- <option [value]="provider.value">{{ provider.label }}</option>
427
- }
428
- </select>
429
- </div>
430
-
431
- <!-- Active Toggle -->
432
- <div class="field flex items-center gap-2">
433
- <p-toggleswitch [formField]="configForm.isActive" />
434
- <label>Active</label>
435
- </div>
436
-
437
- <!-- Default Toggle -->
438
- <div class="field flex items-center gap-2">
439
- <p-toggleswitch [formField]="configForm.isDefault" />
440
- <label>Set as Default</label>
441
- </div>
442
- </div>
443
-
444
- <!-- AWS S3 Fields -->
445
- @if (selectedProvider() === fileLocationEnum.AWS) {
446
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
447
- <div class="field">
448
- <label for="awsRegion" class="block font-medium mb-2">AWS Region *</label>
449
- <input pInputText id="awsRegion" [formField]="configForm.awsRegion" placeholder="us-east-1" class="w-full" />
450
- </div>
451
- <div class="field">
452
- <label for="awsBucket" class="block font-medium mb-2">Bucket Name *</label>
453
- <input pInputText id="awsBucket" [formField]="configForm.awsBucket" placeholder="my-bucket" class="w-full" />
454
- </div>
455
- <div class="field">
456
- <label for="awsAccessKeyId" class="block font-medium mb-2">Access Key ID *</label>
457
- <input pInputText id="awsAccessKeyId" [formField]="configForm.awsAccessKeyId" class="w-full" />
458
- </div>
459
- <div class="field">
460
- <label for="awsSecretAccessKey" class="block font-medium mb-2">Secret Access Key *</label>
461
- <input type="password" pInputText id="awsSecretAccessKey" [formField]="configForm.awsSecretAccessKey" class="w-full" />
462
- </div>
463
- <div class="field md:col-span-2">
464
- <label for="awsEndpoint" class="block font-medium mb-2">Custom Endpoint (Optional)</label>
465
- <input pInputText id="awsEndpoint" [formField]="configForm.awsEndpoint" placeholder="https://s3.custom-endpoint.com" class="w-full" />
466
- </div>
467
- </div>
468
- }
469
-
470
- <!-- Azure Blob Fields -->
471
- @if (selectedProvider() === fileLocationEnum.AZURE) {
472
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
473
- <div class="field">
474
- <label for="azureAccountName" class="block font-medium mb-2">Account Name *</label>
475
- <input pInputText id="azureAccountName" [formField]="configForm.azureAccountName" class="w-full" />
476
- </div>
477
- <div class="field">
478
- <label for="azureContainerName" class="block font-medium mb-2">Container Name *</label>
479
- <input pInputText id="azureContainerName" [formField]="configForm.azureContainerName" class="w-full" />
480
- </div>
481
- <div class="field md:col-span-2">
482
- <label for="azureAccountKey" class="block font-medium mb-2">Account Key *</label>
483
- <input type="password" pInputText id="azureAccountKey" [formField]="configForm.azureAccountKey" class="w-full" />
484
- </div>
485
- </div>
486
- }
487
-
488
- <!-- SFTP Fields -->
489
- @if (selectedProvider() === fileLocationEnum.SFTP) {
490
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
491
- <div class="field">
492
- <label for="sftpHost" class="block font-medium mb-2">Host *</label>
493
- <input pInputText id="sftpHost" [formField]="configForm.sftpHost" placeholder="sftp.example.com" class="w-full" />
494
- </div>
495
- <div class="field">
496
- <label for="sftpPort" class="block font-medium mb-2">Port *</label>
497
- <input type="number" pInputText id="sftpPort" [formField]="configForm.sftpPort" placeholder="22" class="w-full" />
498
- </div>
499
- <div class="field">
500
- <label for="sftpUsername" class="block font-medium mb-2">Username *</label>
501
- <input pInputText id="sftpUsername" [formField]="configForm.sftpUsername" class="w-full" />
502
- </div>
503
- <div class="field">
504
- <label for="sftpPassword" class="block font-medium mb-2">Password *</label>
505
- <input type="password" pInputText id="sftpPassword" [formField]="configForm.sftpPassword" class="w-full" />
506
- </div>
507
- <div class="field md:col-span-2">
508
- <label for="sftpBasePath" class="block font-medium mb-2">Base Path *</label>
509
- <input pInputText id="sftpBasePath" [formField]="configForm.sftpBasePath" placeholder="/uploads" class="w-full" />
510
- </div>
511
- </div>
512
- }
513
-
514
- <!-- Local Fields -->
515
- @if (selectedProvider() === fileLocationEnum.LOCAL) {
516
- <div class="grid grid-cols-1 gap-4 mt-4">
517
- <div class="field">
518
- <label for="localBasePath" class="block font-medium mb-2">Base Path *</label>
519
- <input pInputText id="localBasePath" [formField]="configForm.localBasePath" placeholder="/var/www/uploads" class="w-full" />
520
- </div>
521
- </div>
522
- }
523
-
524
- <div class="flex gap-2 mt-4">
525
- <p-button
526
- type="submit"
527
- [label]="isEditMode() ? 'Update' : 'Create'"
528
- icon="pi pi-check"
529
- [loading]="isLoading()"
530
- [disabled]="!isFormValid() || isLoading()" />
531
- <p-button
532
- type="button"
533
- label="Cancel"
534
- severity="secondary"
535
- icon="pi pi-times"
536
- [text]="true"
537
- (onClick)="onCancel()" />
538
- </div>
539
- </form>
540
- </div>
541
- `,
542
- }]
543
- }] });
544
-
545
- export { StorageConfigFormComponent };
546
- //# sourceMappingURL=flusys-ng-storage-storage-config-form.component-CjIAxfHC.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"flusys-ng-storage-storage-config-form.component-CjIAxfHC.mjs","sources":["../../../projects/ng-storage/pages/storage-config/storage-config-form.component.ts"],"sourcesContent":["import { Component, computed, inject, OnInit, signal } from '@angular/core';\nimport { form, FormField, required } from '@angular/forms/signals';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { AngularModule, PrimeModule } from '@flusys/ng-shared';\nimport { APP_CONFIG } from '@flusys/ng-core';\nimport { MessageService } from 'primeng/api';\nimport { StorageConfigApiService } from '../../services/storage-config-api.service';\nimport { IStorageConfig } from '../../interfaces/storage-config.interface';\nimport { FileLocationEnum } from '../../enums/file-location.enum';\n\n/** Storage config form model interface */\ninterface IStorageConfigFormModel {\n id: string;\n name: string;\n storage: FileLocationEnum;\n isActive: boolean;\n isDefault: boolean;\n // AWS S3\n awsRegion: string;\n awsBucket: string;\n awsAccessKeyId: string;\n awsSecretAccessKey: string;\n awsEndpoint: string;\n // Azure Blob\n azureAccountName: string;\n azureAccountKey: string;\n azureContainerName: string;\n // SFTP\n sftpHost: string;\n sftpPort: string;\n sftpUsername: string;\n sftpPassword: string;\n sftpBasePath: string;\n // Local\n localBasePath: string;\n}\n\n/**\n * Storage Config Form Component\n * Create and edit storage configurations\n */\n@Component({\n selector: 'lib-storage-config-form',\n standalone: true,\n imports: [AngularModule, PrimeModule, FormField],\n template: `\n <div class=\"card\">\n <div class=\"flex justify-between items-center mb-4\">\n <div>\n <h3 class=\"text-xl font-semibold\">\n {{ isEditMode() ? 'Edit Storage Configuration' : 'New Storage Configuration' }}\n </h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">\n Company: {{ currentCompanyName() }}\n </p>\n }\n </div>\n <p-button\n label=\"Back\"\n icon=\"pi pi-arrow-left\"\n severity=\"secondary\"\n [text]=\"true\"\n (onClick)=\"onCancel()\" />\n </div>\n\n <form (ngSubmit)=\"onSubmit()\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <!-- Name -->\n <div class=\"field md:col-span-2\">\n <label for=\"name\" class=\"block font-medium mb-2\">Configuration Name *</label>\n <input\n pInputText\n id=\"name\"\n [formField]=\"configForm.name\"\n placeholder=\"e.g., Production AWS S3\"\n class=\"w-full\" />\n </div>\n\n <!-- Storage Provider -->\n <div class=\"field md:col-span-2\">\n <label for=\"storage\" class=\"block font-medium mb-2\">Storage Provider *</label>\n <select\n id=\"storage\"\n class=\"p-select-native\"\n [formField]=\"configForm.storage\">\n @for (provider of storageProviders; track provider.value) {\n <option [value]=\"provider.value\">{{ provider.label }}</option>\n }\n </select>\n </div>\n\n <!-- Active Toggle -->\n <div class=\"field flex items-center gap-2\">\n <p-toggleswitch [formField]=\"configForm.isActive\" />\n <label>Active</label>\n </div>\n\n <!-- Default Toggle -->\n <div class=\"field flex items-center gap-2\">\n <p-toggleswitch [formField]=\"configForm.isDefault\" />\n <label>Set as Default</label>\n </div>\n </div>\n\n <!-- AWS S3 Fields -->\n @if (selectedProvider() === fileLocationEnum.AWS) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mt-4\">\n <div class=\"field\">\n <label for=\"awsRegion\" class=\"block font-medium mb-2\">AWS Region *</label>\n <input pInputText id=\"awsRegion\" [formField]=\"configForm.awsRegion\" placeholder=\"us-east-1\" class=\"w-full\" />\n </div>\n <div class=\"field\">\n <label for=\"awsBucket\" class=\"block font-medium mb-2\">Bucket Name *</label>\n <input pInputText id=\"awsBucket\" [formField]=\"configForm.awsBucket\" placeholder=\"my-bucket\" class=\"w-full\" />\n </div>\n <div class=\"field\">\n <label for=\"awsAccessKeyId\" class=\"block font-medium mb-2\">Access Key ID *</label>\n <input pInputText id=\"awsAccessKeyId\" [formField]=\"configForm.awsAccessKeyId\" class=\"w-full\" />\n </div>\n <div class=\"field\">\n <label for=\"awsSecretAccessKey\" class=\"block font-medium mb-2\">Secret Access Key *</label>\n <input type=\"password\" pInputText id=\"awsSecretAccessKey\" [formField]=\"configForm.awsSecretAccessKey\" class=\"w-full\" />\n </div>\n <div class=\"field md:col-span-2\">\n <label for=\"awsEndpoint\" class=\"block font-medium mb-2\">Custom Endpoint (Optional)</label>\n <input pInputText id=\"awsEndpoint\" [formField]=\"configForm.awsEndpoint\" placeholder=\"https://s3.custom-endpoint.com\" class=\"w-full\" />\n </div>\n </div>\n }\n\n <!-- Azure Blob Fields -->\n @if (selectedProvider() === fileLocationEnum.AZURE) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mt-4\">\n <div class=\"field\">\n <label for=\"azureAccountName\" class=\"block font-medium mb-2\">Account Name *</label>\n <input pInputText id=\"azureAccountName\" [formField]=\"configForm.azureAccountName\" class=\"w-full\" />\n </div>\n <div class=\"field\">\n <label for=\"azureContainerName\" class=\"block font-medium mb-2\">Container Name *</label>\n <input pInputText id=\"azureContainerName\" [formField]=\"configForm.azureContainerName\" class=\"w-full\" />\n </div>\n <div class=\"field md:col-span-2\">\n <label for=\"azureAccountKey\" class=\"block font-medium mb-2\">Account Key *</label>\n <input type=\"password\" pInputText id=\"azureAccountKey\" [formField]=\"configForm.azureAccountKey\" class=\"w-full\" />\n </div>\n </div>\n }\n\n <!-- SFTP Fields -->\n @if (selectedProvider() === fileLocationEnum.SFTP) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mt-4\">\n <div class=\"field\">\n <label for=\"sftpHost\" class=\"block font-medium mb-2\">Host *</label>\n <input pInputText id=\"sftpHost\" [formField]=\"configForm.sftpHost\" placeholder=\"sftp.example.com\" class=\"w-full\" />\n </div>\n <div class=\"field\">\n <label for=\"sftpPort\" class=\"block font-medium mb-2\">Port *</label>\n <input type=\"number\" pInputText id=\"sftpPort\" [formField]=\"configForm.sftpPort\" placeholder=\"22\" class=\"w-full\" />\n </div>\n <div class=\"field\">\n <label for=\"sftpUsername\" class=\"block font-medium mb-2\">Username *</label>\n <input pInputText id=\"sftpUsername\" [formField]=\"configForm.sftpUsername\" class=\"w-full\" />\n </div>\n <div class=\"field\">\n <label for=\"sftpPassword\" class=\"block font-medium mb-2\">Password *</label>\n <input type=\"password\" pInputText id=\"sftpPassword\" [formField]=\"configForm.sftpPassword\" class=\"w-full\" />\n </div>\n <div class=\"field md:col-span-2\">\n <label for=\"sftpBasePath\" class=\"block font-medium mb-2\">Base Path *</label>\n <input pInputText id=\"sftpBasePath\" [formField]=\"configForm.sftpBasePath\" placeholder=\"/uploads\" class=\"w-full\" />\n </div>\n </div>\n }\n\n <!-- Local Fields -->\n @if (selectedProvider() === fileLocationEnum.LOCAL) {\n <div class=\"grid grid-cols-1 gap-4 mt-4\">\n <div class=\"field\">\n <label for=\"localBasePath\" class=\"block font-medium mb-2\">Base Path *</label>\n <input pInputText id=\"localBasePath\" [formField]=\"configForm.localBasePath\" placeholder=\"/var/www/uploads\" class=\"w-full\" />\n </div>\n </div>\n }\n\n <div class=\"flex gap-2 mt-4\">\n <p-button\n type=\"submit\"\n [label]=\"isEditMode() ? 'Update' : 'Create'\"\n icon=\"pi pi-check\"\n [loading]=\"isLoading()\"\n [disabled]=\"!isFormValid() || isLoading()\" />\n <p-button\n type=\"button\"\n label=\"Cancel\"\n severity=\"secondary\"\n icon=\"pi pi-times\"\n [text]=\"true\"\n (onClick)=\"onCancel()\" />\n </div>\n </form>\n </div>\n `,\n})\nexport class StorageConfigFormComponent implements OnInit {\n private readonly router = inject(Router);\n private readonly route = inject(ActivatedRoute);\n private readonly messageService = inject(MessageService);\n private readonly configService = inject(StorageConfigApiService);\n private readonly appConfig = inject(APP_CONFIG);\n\n readonly fileLocationEnum = FileLocationEnum;\n readonly isLoading = signal(false);\n readonly existingConfig = signal<IStorageConfig | null>(null);\n readonly isEditMode = computed(() => !!this.existingConfig());\n\n readonly showCompanyInfo = computed(() => this.appConfig.enableCompanyFeature);\n readonly currentCompanyName = computed(() => 'Current Company');\n\n readonly storageProviders = [\n { label: 'AWS S3', value: FileLocationEnum.AWS },\n { label: 'Azure Blob Storage', value: FileLocationEnum.AZURE },\n { label: 'SFTP', value: FileLocationEnum.SFTP },\n { label: 'Local Storage', value: FileLocationEnum.LOCAL },\n ];\n\n // ============================================\n // Form (Signal Forms)\n // ============================================\n\n /** Form model */\n readonly formModel = signal<IStorageConfigFormModel>({\n id: '',\n name: '',\n storage: FileLocationEnum.AWS,\n isActive: true,\n isDefault: false,\n // AWS S3\n awsRegion: '',\n awsBucket: '',\n awsAccessKeyId: '',\n awsSecretAccessKey: '',\n awsEndpoint: '',\n // Azure\n azureAccountName: '',\n azureAccountKey: '',\n azureContainerName: '',\n // SFTP\n sftpHost: '',\n sftpPort: '22',\n sftpUsername: '',\n sftpPassword: '',\n sftpBasePath: '',\n // Local\n localBasePath: '',\n });\n\n /** Form with validation schema */\n readonly configForm = form(this.formModel, (f) => {\n required(f.name, { message: 'Configuration name is required' });\n });\n\n /** Selected provider */\n readonly selectedProvider = computed(() => this.formModel().storage);\n\n /** Check if form is valid */\n readonly isFormValid = computed(() => {\n const model = this.formModel();\n return model.name.trim().length > 0;\n });\n\n ngOnInit(): void {\n const configId = this.route.snapshot.paramMap.get('id');\n if (configId) {\n this.loadConfig(configId);\n }\n }\n\n async loadConfig(id: string): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await this.configService.findByIdAsync(id);\n if (response.success && response.data) {\n const config = response.data;\n this.existingConfig.set(config);\n\n // Base form values\n const formData: Partial<IStorageConfigFormModel> = {\n id: config.id,\n name: config.name,\n storage: config.storage,\n isActive: config.isActive ?? true,\n isDefault: config.isDefault ?? false,\n };\n\n // Load provider-specific config\n if (config.storage === FileLocationEnum.AWS && config.config) {\n formData.awsRegion = config.config['region'] || '';\n formData.awsBucket = config.config['bucket'] || '';\n formData.awsAccessKeyId = config.config['accessKeyId'] || '';\n formData.awsSecretAccessKey = config.config['secretAccessKey'] || '';\n formData.awsEndpoint = config.config['endpoint'] || '';\n } else if (config.storage === FileLocationEnum.AZURE && config.config) {\n formData.azureAccountName = config.config['accountName'] || '';\n formData.azureAccountKey = config.config['accountKey'] || '';\n formData.azureContainerName = config.config['containerName'] || '';\n } else if (config.storage === FileLocationEnum.SFTP && config.config) {\n formData.sftpHost = config.config['host'] || '';\n formData.sftpPort = (config.config['port'] || 22).toString();\n formData.sftpUsername = config.config['username'] || '';\n formData.sftpPassword = config.config['password'] || '';\n formData.sftpBasePath = config.config['basePath'] || '';\n } else if (config.storage === FileLocationEnum.LOCAL && config.config) {\n formData.localBasePath = config.config['basePath'] || '';\n }\n\n this.formModel.update((m) => ({ ...m, ...formData }));\n }\n } catch (error) {\n this.messageService.add({\n severity: 'error',\n summary: 'Error',\n detail: 'Failed to load storage configuration.',\n });\n this.router.navigate(['/storage/configs']);\n } finally {\n this.isLoading.set(false);\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 let config: Record<string, any> = {};\n\n // Build provider-specific config\n if (formValue.storage === FileLocationEnum.AWS) {\n config = {\n region: formValue.awsRegion,\n bucket: formValue.awsBucket,\n accessKeyId: formValue.awsAccessKeyId,\n secretAccessKey: formValue.awsSecretAccessKey,\n ...(formValue.awsEndpoint && { endpoint: formValue.awsEndpoint }),\n };\n } else if (formValue.storage === FileLocationEnum.AZURE) {\n config = {\n accountName: formValue.azureAccountName,\n accountKey: formValue.azureAccountKey,\n containerName: formValue.azureContainerName,\n };\n } else if (formValue.storage === FileLocationEnum.SFTP) {\n config = {\n host: formValue.sftpHost,\n port: formValue.sftpPort ? parseInt(formValue.sftpPort, 10) : 22,\n username: formValue.sftpUsername,\n password: formValue.sftpPassword,\n basePath: formValue.sftpBasePath,\n };\n } else if (formValue.storage === FileLocationEnum.LOCAL) {\n config = {\n basePath: formValue.localBasePath,\n };\n }\n\n if (this.isEditMode()) {\n await this.configService.updateAsync({\n id: formValue.id,\n name: formValue.name,\n storage: formValue.storage,\n config,\n isActive: formValue.isActive,\n isDefault: formValue.isDefault,\n });\n this.messageService.add({\n severity: 'success',\n summary: 'Success',\n detail: 'Storage configuration updated successfully.',\n });\n } else {\n await this.configService.insertAsync({\n name: formValue.name,\n storage: formValue.storage,\n config,\n isActive: formValue.isActive,\n isDefault: formValue.isDefault,\n } as any);\n this.messageService.add({\n severity: 'success',\n summary: 'Success',\n detail: 'Storage configuration created successfully.',\n });\n }\n\n this.router.navigate(['/storage/configs']);\n } catch (error) {\n this.messageService.add({\n severity: 'error',\n summary: 'Error',\n detail: `Failed to ${this.isEditMode() ? 'update' : 'create'} storage configuration.`,\n });\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onCancel(): void {\n this.router.navigate(['/storage/configs']);\n }\n}\n"],"names":["i2"],"mappings":"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"}