@flusys/ng-storage 1.0.0-rc → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/fesm2022/{flusys-ng-storage-file-manager-form.component-CMS_ddbs.mjs → flusys-ng-storage-file-manager-form.component-Bv8ER8J0.mjs} +1 -2
- package/fesm2022/flusys-ng-storage-file-manager-form.component-Bv8ER8J0.mjs.map +1 -0
- package/fesm2022/{flusys-ng-storage-file-manager-list.component-DDOFAPRD.mjs → flusys-ng-storage-file-manager-list.component-McM1zSlE.mjs} +1 -2
- package/fesm2022/flusys-ng-storage-file-manager-list.component-McM1zSlE.mjs.map +1 -0
- package/fesm2022/{flusys-ng-storage-folder-form.component-ClYATZkh.mjs → flusys-ng-storage-folder-form.component-fRFiMFev.mjs} +2 -4
- package/fesm2022/flusys-ng-storage-folder-form.component-fRFiMFev.mjs.map +1 -0
- package/fesm2022/{flusys-ng-storage-folder-list.component-CzONANHt.mjs → flusys-ng-storage-folder-list.component-C4xHI8SO.mjs} +2 -8
- package/fesm2022/flusys-ng-storage-folder-list.component-C4xHI8SO.mjs.map +1 -0
- package/fesm2022/{flusys-ng-storage-storage-config-form.component-CODLLCtg.mjs → flusys-ng-storage-storage-config-form.component-DEMexjmg.mjs} +67 -90
- package/fesm2022/flusys-ng-storage-storage-config-form.component-DEMexjmg.mjs.map +1 -0
- package/fesm2022/{flusys-ng-storage-storage-config-list.component-BbBx0iSL.mjs → flusys-ng-storage-storage-config-list.component-iJez-rII.mjs} +11 -37
- package/fesm2022/flusys-ng-storage-storage-config-list.component-iJez-rII.mjs.map +1 -0
- package/fesm2022/flusys-ng-storage.mjs +96 -220
- package/fesm2022/flusys-ng-storage.mjs.map +1 -1
- package/package.json +10 -10
- package/types/flusys-ng-storage.d.ts +32 -188
- package/fesm2022/flusys-ng-storage-file-manager-form.component-CMS_ddbs.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-file-manager-list.component-DDOFAPRD.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-folder-form.component-ClYATZkh.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-folder-list.component-CzONANHt.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-storage-config-form.component-CODLLCtg.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-storage-config-list.component-BbBx0iSL.mjs.map +0 -1
|
@@ -9,20 +9,12 @@ import * as i3 from 'primeng/tag';
|
|
|
9
9
|
import * as i4 from 'primeng/tooltip';
|
|
10
10
|
import * as i5 from '@angular/common';
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
* Storage Config List Component
|
|
14
|
-
* Displays all storage configurations with company filter (if enabled)
|
|
15
|
-
*/
|
|
16
12
|
class StorageConfigListComponent extends BaseStorageListPage {
|
|
17
|
-
// Permission constants for template
|
|
18
13
|
STORAGE_CONFIG_PERMISSIONS = STORAGE_CONFIG_PERMISSIONS;
|
|
19
14
|
configService = inject(StorageConfigApiService);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
getProviderIcon = (storage) => getProviderIcon(storage);
|
|
24
|
-
getProviderLabel = (storage) => getProviderLabel(storage);
|
|
25
|
-
getProviderSeverity = (storage) => getProviderSeverity(storage);
|
|
15
|
+
getProviderIcon = getProviderIcon;
|
|
16
|
+
getProviderLabel = getProviderLabel;
|
|
17
|
+
getProviderSeverity = getProviderSeverity;
|
|
26
18
|
getResourceRoute() {
|
|
27
19
|
return '/storage/configs';
|
|
28
20
|
}
|
|
@@ -32,12 +24,7 @@ class StorageConfigListComponent extends BaseStorageListPage {
|
|
|
32
24
|
async loadData() {
|
|
33
25
|
this.isLoading.set(true);
|
|
34
26
|
try {
|
|
35
|
-
const response = await firstValueFrom(this.configService.getAll('', {
|
|
36
|
-
pagination: this.getPaginationParams(),
|
|
37
|
-
filter: {},
|
|
38
|
-
select: [],
|
|
39
|
-
sort: {},
|
|
40
|
-
}));
|
|
27
|
+
const response = await firstValueFrom(this.configService.getAll('', { pagination: this.getPaginationParams() }));
|
|
41
28
|
if (response.success) {
|
|
42
29
|
this.items.set(response.data ?? []);
|
|
43
30
|
this.total.set(response.meta?.total ?? 0);
|
|
@@ -64,9 +51,7 @@ class StorageConfigListComponent extends BaseStorageListPage {
|
|
|
64
51
|
<div>
|
|
65
52
|
<h3 class="text-lg sm:text-xl font-semibold">Storage Configurations</h3>
|
|
66
53
|
@if (showCompanyInfo()) {
|
|
67
|
-
<p class="text-sm text-muted-color mt-1">
|
|
68
|
-
Company: {{ currentCompanyName() }}
|
|
69
|
-
</p>
|
|
54
|
+
<p class="text-sm text-muted-color mt-1">Company: {{ currentCompanyName() }}</p>
|
|
70
55
|
}
|
|
71
56
|
</div>
|
|
72
57
|
<p-button *hasPermission="STORAGE_CONFIG_PERMISSIONS.CREATE" label="New Configuration" icon="pi pi-plus" (onClick)="onCreate()" styleClass="w-full sm:w-auto" />
|
|
@@ -74,7 +59,7 @@ class StorageConfigListComponent extends BaseStorageListPage {
|
|
|
74
59
|
|
|
75
60
|
<div class="overflow-x-auto">
|
|
76
61
|
<p-table
|
|
77
|
-
[value]="
|
|
62
|
+
[value]="items()"
|
|
78
63
|
[loading]="isLoading()"
|
|
79
64
|
[paginator]="totalRecords() > 0"
|
|
80
65
|
[rows]="pageSize()"
|
|
@@ -116,11 +101,7 @@ class StorageConfigListComponent extends BaseStorageListPage {
|
|
|
116
101
|
<ng-template #emptymessage>
|
|
117
102
|
<tr>
|
|
118
103
|
<td colspan="4" class="text-center py-4 text-muted-color">
|
|
119
|
-
|
|
120
|
-
No storage configurations found in current company
|
|
121
|
-
} @else {
|
|
122
|
-
No storage configurations found
|
|
123
|
-
}
|
|
104
|
+
{{ showCompanyInfo() ? 'No storage configurations found in current company' : 'No storage configurations found' }}
|
|
124
105
|
</td>
|
|
125
106
|
</tr>
|
|
126
107
|
</ng-template>
|
|
@@ -133,7 +114,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
133
114
|
type: Component,
|
|
134
115
|
args: [{
|
|
135
116
|
selector: 'lib-storage-config-list',
|
|
136
|
-
standalone: true,
|
|
137
117
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
138
118
|
imports: [AngularModule, PrimeModule, HasPermissionDirective],
|
|
139
119
|
template: `
|
|
@@ -142,9 +122,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
142
122
|
<div>
|
|
143
123
|
<h3 class="text-lg sm:text-xl font-semibold">Storage Configurations</h3>
|
|
144
124
|
@if (showCompanyInfo()) {
|
|
145
|
-
<p class="text-sm text-muted-color mt-1">
|
|
146
|
-
Company: {{ currentCompanyName() }}
|
|
147
|
-
</p>
|
|
125
|
+
<p class="text-sm text-muted-color mt-1">Company: {{ currentCompanyName() }}</p>
|
|
148
126
|
}
|
|
149
127
|
</div>
|
|
150
128
|
<p-button *hasPermission="STORAGE_CONFIG_PERMISSIONS.CREATE" label="New Configuration" icon="pi pi-plus" (onClick)="onCreate()" styleClass="w-full sm:w-auto" />
|
|
@@ -152,7 +130,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
152
130
|
|
|
153
131
|
<div class="overflow-x-auto">
|
|
154
132
|
<p-table
|
|
155
|
-
[value]="
|
|
133
|
+
[value]="items()"
|
|
156
134
|
[loading]="isLoading()"
|
|
157
135
|
[paginator]="totalRecords() > 0"
|
|
158
136
|
[rows]="pageSize()"
|
|
@@ -194,11 +172,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
194
172
|
<ng-template #emptymessage>
|
|
195
173
|
<tr>
|
|
196
174
|
<td colspan="4" class="text-center py-4 text-muted-color">
|
|
197
|
-
|
|
198
|
-
No storage configurations found in current company
|
|
199
|
-
} @else {
|
|
200
|
-
No storage configurations found
|
|
201
|
-
}
|
|
175
|
+
{{ showCompanyInfo() ? 'No storage configurations found in current company' : 'No storage configurations found' }}
|
|
202
176
|
</td>
|
|
203
177
|
</tr>
|
|
204
178
|
</ng-template>
|
|
@@ -210,4 +184,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
210
184
|
}] });
|
|
211
185
|
|
|
212
186
|
export { StorageConfigListComponent };
|
|
213
|
-
//# sourceMappingURL=flusys-ng-storage-storage-config-list.component-
|
|
187
|
+
//# sourceMappingURL=flusys-ng-storage-storage-config-list.component-iJez-rII.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flusys-ng-storage-storage-config-list.component-iJez-rII.mjs","sources":["../../../projects/ng-storage/pages/storage-config/storage-config-list.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, inject } from '@angular/core';\nimport { AngularModule, HasPermissionDirective, PrimeModule, STORAGE_CONFIG_PERMISSIONS } from '@flusys/ng-shared';\nimport { firstValueFrom } from 'rxjs';\nimport { IStorageConfig } from '../../interfaces/storage-config.interface';\nimport { StorageConfigApiService } from '../../services/storage-config-api.service';\nimport { BaseStorageListPage } from '../../utils/base-storage-page';\nimport { getProviderIcon, getProviderLabel, getProviderSeverity } from '../../utils/storage-utils';\n\n@Component({\n selector: 'lib-storage-config-list',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [AngularModule, PrimeModule, HasPermissionDirective],\n template: `\n <div class=\"card\">\n <div class=\"flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 mb-4\">\n <div>\n <h3 class=\"text-lg sm:text-xl font-semibold\">Storage Configurations</h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">Company: {{ currentCompanyName() }}</p>\n }\n </div>\n <p-button *hasPermission=\"STORAGE_CONFIG_PERMISSIONS.CREATE\" label=\"New Configuration\" icon=\"pi pi-plus\" (onClick)=\"onCreate()\" styleClass=\"w-full sm:w-auto\" />\n </div>\n\n <div class=\"overflow-x-auto\">\n <p-table\n [value]=\"items()\"\n [loading]=\"isLoading()\"\n [paginator]=\"totalRecords() > 0\"\n [rows]=\"pageSize()\"\n [totalRecords]=\"totalRecords()\"\n [lazy]=\"true\"\n (onLazyLoad)=\"onPageChange($event)\"\n [rowsPerPageOptions]=\"[10, 25, 50]\"\n [scrollable]=\"true\"\n styleClass=\"p-datatable-sm\"\n >\n <ng-template #header>\n <tr>\n <th>Name</th>\n <th>Provider</th>\n <th class=\"hidden sm:table-cell\">Created</th>\n <th class=\"w-[120px]\">Actions</th>\n </tr>\n </ng-template>\n <ng-template #body let-config>\n <tr>\n <td>\n <div class=\"flex items-center gap-2\">\n <i [class]=\"getProviderIcon(config.storage)\"></i>\n <span class=\"truncate max-w-32 sm:max-w-none\">{{ config.name }}</span>\n </div>\n </td>\n <td>\n <p-tag [value]=\"getProviderLabel(config.storage)\" [severity]=\"getProviderSeverity(config.storage)\" />\n </td>\n <td class=\"hidden sm:table-cell\">{{ config.createdAt | date: 'short' }}</td>\n <td>\n <div class=\"flex gap-1\">\n <p-button *hasPermission=\"STORAGE_CONFIG_PERMISSIONS.UPDATE\" icon=\"pi pi-pencil\" [text]=\"true\" severity=\"secondary\" size=\"small\" (onClick)=\"onEdit(config.id)\" pTooltip=\"Edit\" tooltipPosition=\"top\" />\n <p-button *hasPermission=\"STORAGE_CONFIG_PERMISSIONS.DELETE\" icon=\"pi pi-trash\" [text]=\"true\" severity=\"danger\" size=\"small\" (onClick)=\"onDeleteConfig(config)\" pTooltip=\"Delete\" tooltipPosition=\"top\" />\n </div>\n </td>\n </tr>\n </ng-template>\n <ng-template #emptymessage>\n <tr>\n <td colspan=\"4\" class=\"text-center py-4 text-muted-color\">\n {{ showCompanyInfo() ? 'No storage configurations found in current company' : 'No storage configurations found' }}\n </td>\n </tr>\n </ng-template>\n </p-table>\n </div>\n </div>\n `,\n})\nexport class StorageConfigListComponent extends BaseStorageListPage<IStorageConfig> {\n readonly STORAGE_CONFIG_PERMISSIONS = STORAGE_CONFIG_PERMISSIONS;\n\n private readonly configService = inject(StorageConfigApiService);\n\n readonly getProviderIcon = getProviderIcon;\n readonly getProviderLabel = getProviderLabel;\n readonly getProviderSeverity = getProviderSeverity;\n\n getResourceRoute(): string {\n return '/storage/configs';\n }\n\n override getDeleteConfirmMessage(config: IStorageConfig): string {\n return `Are you sure you want to delete \"${config.name}\"?`;\n }\n\n async loadData(): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await firstValueFrom(\n this.configService.getAll('', { pagination: this.getPaginationParams() }),\n );\n if (response.success) {\n this.items.set(response.data ?? []);\n this.total.set(response.meta?.total ?? 0);\n }\n } catch {\n this.showError('Failed to load storage configurations.');\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onDeleteConfig(config: IStorageConfig): void {\n this.onDeleteAsync(\n config,\n (c) => c.id,\n (id) => this.configService.deleteAsync({ id, type: 'delete' }),\n {\n header: 'Delete Configuration',\n successMessage: 'Storage configuration deleted successfully.',\n errorMessage: 'Failed to delete storage configuration.',\n },\n );\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;AA6EM,MAAO,0BAA2B,SAAQ,mBAAmC,CAAA;IACxE,0BAA0B,GAAG,0BAA0B;AAE/C,IAAA,aAAa,GAAG,MAAM,CAAC,uBAAuB,CAAC;IAEvD,eAAe,GAAG,eAAe;IACjC,gBAAgB,GAAG,gBAAgB;IACnC,mBAAmB,GAAG,mBAAmB;IAElD,gBAAgB,GAAA;AACd,QAAA,OAAO,kBAAkB;IAC3B;AAES,IAAA,uBAAuB,CAAC,MAAsB,EAAA;AACrD,QAAA,OAAO,CAAA,iCAAA,EAAoC,MAAM,CAAC,IAAI,IAAI;IAC5D;AAEA,IAAA,MAAM,QAAQ,GAAA;AACZ,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;AACxB,QAAA,IAAI;YACF,MAAM,QAAQ,GAAG,MAAM,cAAc,CACnC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAC1E;AACD,YAAA,IAAI,QAAQ,CAAC,OAAO,EAAE;gBACpB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;AACnC,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC;YAC3C;QACF;AAAE,QAAA,MAAM;AACN,YAAA,IAAI,CAAC,SAAS,CAAC,wCAAwC,CAAC;QAC1D;gBAAU;AACR,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;QAC3B;IACF;AAEA,IAAA,cAAc,CAAC,MAAsB,EAAA;AACnC,QAAA,IAAI,CAAC,aAAa,CAChB,MAAM,EACN,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EACX,CAAC,EAAE,KAAK,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAC9D;AACE,YAAA,MAAM,EAAE,sBAAsB;AAC9B,YAAA,cAAc,EAAE,6CAA6C;AAC7D,YAAA,YAAY,EAAE,yCAAyC;AACxD,SAAA,CACF;IACH;uGA7CW,0BAA0B,EAAA,IAAA,EAAA,IAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA1B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,0BAA0B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,eAAA,EAAA,IAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAjE3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAhES,aAAa,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,WAAW,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,OAAA,EAAA,UAAA,EAAA,QAAA,EAAA,SAAA,EAAA,MAAA,EAAA,OAAA,EAAA,UAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,SAAA,EAAA,OAAA,EAAA,YAAA,EAAA,YAAA,EAAA,eAAA,EAAA,WAAA,EAAA,WAAA,EAAA,SAAA,EAAA,MAAA,EAAA,OAAA,EAAA,SAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,OAAA,CAAA,EAAA,OAAA,EAAA,CAAA,SAAA,EAAA,SAAA,EAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,QAAA,EAAA,SAAA,EAAA,MAAA,EAAA,CAAA,eAAA,EAAA,aAAA,EAAA,YAAA,EAAA,YAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,WAAA,EAAA,oBAAA,EAAA,qBAAA,EAAA,mBAAA,EAAA,qBAAA,EAAA,2BAAA,EAAA,+BAAA,EAAA,2BAAA,EAAA,uBAAA,EAAA,wBAAA,EAAA,qBAAA,EAAA,mBAAA,EAAA,eAAA,EAAA,kBAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,mBAAA,EAAA,sBAAA,EAAA,0BAAA,EAAA,SAAA,EAAA,kBAAA,EAAA,eAAA,EAAA,YAAA,EAAA,MAAA,EAAA,gBAAA,EAAA,oBAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,SAAA,EAAA,oBAAA,EAAA,aAAA,EAAA,cAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,eAAA,EAAA,YAAA,EAAA,cAAA,EAAA,cAAA,EAAA,eAAA,EAAA,uBAAA,EAAA,sBAAA,EAAA,oBAAA,EAAA,aAAA,EAAA,aAAA,EAAA,kBAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,SAAA,EAAA,aAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,sBAAA,EAAA,gBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,UAAA,EAAA,aAAA,EAAA,MAAA,EAAA,eAAA,EAAA,aAAA,EAAA,kBAAA,EAAA,kBAAA,EAAA,YAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,SAAA,EAAA,OAAA,EAAA,MAAA,EAAA,cAAA,EAAA,WAAA,EAAA,WAAA,EAAA,eAAA,EAAA,WAAA,EAAA,WAAA,CAAA,EAAA,OAAA,EAAA,CAAA,4BAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,eAAA,EAAA,QAAA,EAAA,QAAA,EAAA,UAAA,EAAA,YAAA,EAAA,aAAA,EAAA,eAAA,EAAA,qBAAA,EAAA,aAAA,EAAA,cAAA,EAAA,cAAA,EAAA,YAAA,EAAA,gBAAA,EAAA,cAAA,EAAA,wBAAA,EAAA,cAAA,EAAA,aAAA,EAAA,YAAA,EAAA,aAAA,EAAA,gBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,GAAA,EAAA,QAAA,EAAA,OAAA,EAAA,MAAA,EAAA,CAAA,YAAA,EAAA,UAAA,EAAA,OAAA,EAAA,MAAA,EAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,CAAA,iBAAA,EAAA,cAAA,EAAA,eAAA,EAAA,mBAAA,EAAA,eAAA,EAAA,QAAA,EAAA,WAAA,EAAA,WAAA,EAAA,MAAA,EAAA,aAAA,EAAA,cAAA,EAAA,UAAA,EAAA,YAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,WAAA,EAAA,YAAA,EAAA,kBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,sBAAsB,EAAA,QAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,CAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,EAAA,CAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAkEjD,0BAA0B,EAAA,UAAA,EAAA,CAAA;kBArEtC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,yBAAyB;oBACnC,eAAe,EAAE,uBAAuB,CAAC,MAAM;AAC/C,oBAAA,OAAO,EAAE,CAAC,aAAa,EAAE,WAAW,EAAE,sBAAsB,CAAC;AAC7D,oBAAA,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DT,EAAA,CAAA;AACF,iBAAA;;;;;"}
|
|
@@ -3,7 +3,7 @@ import { inject, signal, computed, Directive, Injectable, ChangeDetectionStrateg
|
|
|
3
3
|
import { Router, RouterOutlet, RouterLink, RouterLinkActive } from '@angular/router';
|
|
4
4
|
import { APP_CONFIG, DEFAULT_APP_NAME, BaseApiService, getDefaultStorageConfigId } from '@flusys/ng-core';
|
|
5
5
|
import { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';
|
|
6
|
-
import { BaseListPage, ApiResourceService, PROFILE_UPLOAD_PROVIDER } from '@flusys/ng-shared';
|
|
6
|
+
import { BaseListPage, ApiResourceService, PROFILE_UPLOAD_PROVIDER, permissionGuard, FILE_PERMISSIONS, FOLDER_PERMISSIONS, STORAGE_CONFIG_PERMISSIONS, PermissionValidatorService } from '@flusys/ng-shared';
|
|
7
7
|
import { MessageService } from 'primeng/api';
|
|
8
8
|
import { map } from 'rxjs/operators';
|
|
9
9
|
import { firstValueFrom, switchMap } from 'rxjs';
|
|
@@ -118,32 +118,20 @@ const STORAGE_PROVIDERS = [
|
|
|
118
118
|
{ label: 'Local Storage', value: FileLocationEnum.LOCAL },
|
|
119
119
|
];
|
|
120
120
|
|
|
121
|
-
/**
|
|
122
|
-
* Base Storage Page
|
|
123
|
-
*
|
|
124
|
-
* Provides common signals, computed values, and utilities for storage pages.
|
|
125
|
-
* Used by form components that need company context and message utilities.
|
|
126
|
-
*/
|
|
127
121
|
class BaseStoragePage {
|
|
128
122
|
router = inject(Router);
|
|
129
123
|
messageService = inject(MessageService);
|
|
130
124
|
appConfig = inject(APP_CONFIG);
|
|
131
125
|
companyContext = inject(LAYOUT_AUTH_STATE);
|
|
132
|
-
/** Loading state */
|
|
133
126
|
isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
134
|
-
/** Show company info if company feature enabled */
|
|
135
127
|
showCompanyInfo = computed(() => this.appConfig.enableCompanyFeature, ...(ngDevMode ? [{ debugName: "showCompanyInfo" }] : []));
|
|
136
|
-
/** Current company name */
|
|
137
128
|
currentCompanyName = computed(() => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME, ...(ngDevMode ? [{ debugName: "currentCompanyName" }] : []));
|
|
138
|
-
/** Show success message */
|
|
139
129
|
showSuccess(detail, summary = 'Success') {
|
|
140
130
|
this.messageService.add({ severity: 'success', summary, detail });
|
|
141
131
|
}
|
|
142
|
-
/** Show error message */
|
|
143
132
|
showError(detail, summary = 'Error') {
|
|
144
133
|
this.messageService.add({ severity: 'error', summary, detail });
|
|
145
134
|
}
|
|
146
|
-
/** Navigate to a route */
|
|
147
135
|
navigateTo(path) {
|
|
148
136
|
this.router.navigate(path);
|
|
149
137
|
}
|
|
@@ -153,35 +141,11 @@ class BaseStoragePage {
|
|
|
153
141
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BaseStoragePage, decorators: [{
|
|
154
142
|
type: Directive
|
|
155
143
|
}] });
|
|
156
|
-
/**
|
|
157
|
-
* Base Storage List Page
|
|
158
|
-
*
|
|
159
|
-
* Extends the shared BaseListPage with storage-specific functionality:
|
|
160
|
-
* - Company context integration via LAYOUT_AUTH_STATE
|
|
161
|
-
* - Current company name computed signal
|
|
162
|
-
* - Storage-specific defaults (pageSize: 50)
|
|
163
|
-
*
|
|
164
|
-
* Usage:
|
|
165
|
-
* ```typescript
|
|
166
|
-
* @Component({ ... })
|
|
167
|
-
* export class FolderListComponent extends BaseStorageListPage<IFolder> {
|
|
168
|
-
* getResourceRoute(): string { return '/storage/folders'; }
|
|
169
|
-
* getDeleteConfirmMessage(folder: IFolder): string { return `Delete "${folder.name}"?`; }
|
|
170
|
-
* async loadData(): Promise<void> { ... }
|
|
171
|
-
* }
|
|
172
|
-
* ```
|
|
173
|
-
*/
|
|
174
144
|
class BaseStorageListPage extends BaseListPage {
|
|
175
145
|
companyContext = inject(LAYOUT_AUTH_STATE);
|
|
176
|
-
/** Override default page size for storage pages */
|
|
177
146
|
pageSize = signal(50, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
|
|
178
|
-
/** Total records alias for backward compatibility */
|
|
179
147
|
totalRecords = this.total;
|
|
180
|
-
/** Current company name */
|
|
181
148
|
currentCompanyName = computed(() => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME, ...(ngDevMode ? [{ debugName: "currentCompanyName" }] : []));
|
|
182
|
-
/**
|
|
183
|
-
* Default implementation - subclasses should override if needed
|
|
184
|
-
*/
|
|
185
149
|
getDeleteConfirmMessage(item) {
|
|
186
150
|
const name = item.name ?? 'this item';
|
|
187
151
|
return `Are you sure you want to delete "${name}"?`;
|
|
@@ -193,65 +157,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
193
157
|
type: Directive
|
|
194
158
|
}] });
|
|
195
159
|
|
|
196
|
-
/**
|
|
197
|
-
* File Manager API Service
|
|
198
|
-
* Handles file metadata CRUD operations
|
|
199
|
-
* Endpoint: POST /storage/file-manager/*
|
|
200
|
-
*
|
|
201
|
-
* Note: Company feature enabled - all queries automatically scoped to user's company
|
|
202
|
-
*/
|
|
203
160
|
class FileManagerApiService extends ApiResourceService {
|
|
204
161
|
constructor() {
|
|
205
|
-
|
|
206
|
-
super('storage/file-manager', http);
|
|
162
|
+
super('storage/file-manager', inject(HttpClient));
|
|
207
163
|
}
|
|
208
|
-
/**
|
|
209
|
-
* Get multiple files with valid URLs
|
|
210
|
-
* POST /storage/file-manager/get-files
|
|
211
|
-
* Regenerates presigned URLs if expired
|
|
212
|
-
*/
|
|
213
164
|
getFiles(fileIds) {
|
|
214
165
|
const requests = fileIds.map((id) => ({ id }));
|
|
215
166
|
return this.http.post(`${this.baseUrl}/get-files`, requests);
|
|
216
167
|
}
|
|
217
|
-
/**
|
|
218
|
-
* Get files by folder
|
|
219
|
-
* POST /storage/file-manager/get-all
|
|
220
|
-
* Filtered by folder ID (UUID) and company (if enabled)
|
|
221
|
-
*/
|
|
222
|
-
getFilesByFolder(folderId, page = 1, limit = 50) {
|
|
223
|
-
return this.getAll('', {
|
|
224
|
-
filter: folderId ? { folderId } : {},
|
|
225
|
-
pagination: { currentPage: page - 1, pageSize: limit },
|
|
226
|
-
select: [],
|
|
227
|
-
sort: {},
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Get private files (requires permission)
|
|
232
|
-
* POST /storage/file-manager/get-all
|
|
233
|
-
* Filtered by isPrivate and user permission 'storage.file.viewPrivate'
|
|
234
|
-
*/
|
|
235
|
-
getPrivateFiles(page = 1, limit = 50) {
|
|
236
|
-
return this.getAll('', {
|
|
237
|
-
filter: { isPrivate: true },
|
|
238
|
-
pagination: { currentPage: page - 1, pageSize: limit },
|
|
239
|
-
select: [],
|
|
240
|
-
sort: {},
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Create a new file record
|
|
245
|
-
* POST /storage/file-manager/insert
|
|
246
|
-
* Uses ICreateFileManagerDto which has different required fields than update
|
|
247
|
-
*/
|
|
248
168
|
createFile(dto) {
|
|
249
169
|
return this.http.post(`${this.baseUrl}/insert`, dto);
|
|
250
170
|
}
|
|
251
|
-
/**
|
|
252
|
-
* Create a new file record (async/await version)
|
|
253
|
-
* POST /storage/file-manager/insert
|
|
254
|
-
*/
|
|
255
171
|
async createFileAsync(dto) {
|
|
256
172
|
return firstValueFrom(this.createFile(dto));
|
|
257
173
|
}
|
|
@@ -260,77 +176,77 @@ class FileManagerApiService extends ApiResourceService {
|
|
|
260
176
|
}
|
|
261
177
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: FileManagerApiService, decorators: [{
|
|
262
178
|
type: Injectable,
|
|
263
|
-
args: [{
|
|
264
|
-
providedIn: 'root',
|
|
265
|
-
}]
|
|
179
|
+
args: [{ providedIn: 'root' }]
|
|
266
180
|
}], ctorParameters: () => [] });
|
|
267
181
|
|
|
268
182
|
/**
|
|
269
|
-
* Upload Service
|
|
270
|
-
* Handles file upload/delete operations
|
|
183
|
+
* Upload Service - File upload/delete operations
|
|
271
184
|
* Endpoint: POST /storage/upload/*
|
|
272
|
-
*
|
|
273
|
-
* Features:
|
|
274
|
-
* - Company-scoped uploads (if company feature enabled)
|
|
275
|
-
* - Image compression
|
|
276
|
-
* - Multiple storage providers
|
|
277
|
-
* - File validation (size, type)
|
|
278
|
-
* - Default storage config from environment (services.storage.defaultStorageConfigId)
|
|
279
185
|
*/
|
|
280
186
|
class UploadService extends BaseApiService {
|
|
281
187
|
fileManagerApi = inject(FileManagerApiService);
|
|
282
188
|
constructor() {
|
|
283
189
|
super('storage');
|
|
284
190
|
}
|
|
285
|
-
/**
|
|
286
|
-
* Get default storage config ID from app config
|
|
287
|
-
* Used when no storageConfigId is provided in upload options
|
|
288
|
-
*/
|
|
191
|
+
/** Get default storage config ID from app config */
|
|
289
192
|
getDefaultConfigId() {
|
|
290
193
|
return getDefaultStorageConfigId(this.appConfig);
|
|
291
194
|
}
|
|
292
|
-
/**
|
|
293
|
-
* Upload single file
|
|
294
|
-
* POST /storage/upload/single-file?storageConfigId=x&folderPath=y
|
|
295
|
-
*
|
|
296
|
-
* @param file - File to upload
|
|
297
|
-
* @param options - Upload options (storage config, compression, etc.)
|
|
298
|
-
*/
|
|
195
|
+
/** Upload single file - POST /storage/upload/single-file */
|
|
299
196
|
uploadSingleFile(file, options) {
|
|
300
197
|
const formData = new FormData();
|
|
301
198
|
formData.append('file', file);
|
|
302
|
-
|
|
303
|
-
const url = queryParams
|
|
304
|
-
? `${this.getUrl('upload/single-file')}?${queryParams}`
|
|
305
|
-
: this.getUrl('upload/single-file');
|
|
306
|
-
return this.http.post(url, formData);
|
|
199
|
+
return this.http.post(this.buildUploadUrl('single-file', options), formData);
|
|
307
200
|
}
|
|
308
|
-
/**
|
|
309
|
-
* Upload multiple files (max 50)
|
|
310
|
-
* POST /storage/upload/multiple-file?storageConfigId=x&folderPath=y
|
|
311
|
-
*
|
|
312
|
-
* @param files - Array of files to upload
|
|
313
|
-
* @param options - Upload options
|
|
314
|
-
*/
|
|
201
|
+
/** Upload multiple files (max 50) - POST /storage/upload/multiple-file */
|
|
315
202
|
uploadMultipleFiles(files, options) {
|
|
316
203
|
const formData = new FormData();
|
|
317
204
|
files.forEach((file) => formData.append('files', file));
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
return this.http.post(
|
|
205
|
+
return this.http.post(this.buildUploadUrl('multiple-file', options), formData);
|
|
206
|
+
}
|
|
207
|
+
/** Delete single file - POST /storage/upload/delete-single-file */
|
|
208
|
+
deleteSingleFile(key, storageConfigId) {
|
|
209
|
+
return this.http.post(this.getUrl('upload/delete-single-file'), this.buildDeleteBody({ key }, storageConfigId));
|
|
210
|
+
}
|
|
211
|
+
/** Delete multiple files - POST /storage/upload/delete-multiple-file */
|
|
212
|
+
deleteMultipleFiles(keys, storageConfigId) {
|
|
213
|
+
return this.http.post(this.getUrl('upload/delete-multiple-file'), this.buildDeleteBody({ keys }, storageConfigId));
|
|
214
|
+
}
|
|
215
|
+
/** Get file download URL - GET /storage/upload/file/:filePath */
|
|
216
|
+
getFileUrl(key) {
|
|
217
|
+
return this.getUrl(`upload/file/${key}`);
|
|
218
|
+
}
|
|
219
|
+
/** Upload file and register in file manager - returns file manager ID (UUID) */
|
|
220
|
+
uploadAndRegister(file, options) {
|
|
221
|
+
return this.uploadSingleFile(file, options).pipe(switchMap((response) => {
|
|
222
|
+
if (!response.success || !response.data) {
|
|
223
|
+
throw new Error(response.message || 'Upload failed');
|
|
224
|
+
}
|
|
225
|
+
return this.fileManagerApi.createFile({
|
|
226
|
+
name: response.data.name,
|
|
227
|
+
key: response.data.key,
|
|
228
|
+
size: String(response.data.size),
|
|
229
|
+
contentType: response.data.contentType,
|
|
230
|
+
isPrivate: options?.isPrivate ?? false,
|
|
231
|
+
folderId: options?.folderId,
|
|
232
|
+
storageConfigId: this.resolveConfigId(options?.storageConfigId),
|
|
233
|
+
});
|
|
234
|
+
}));
|
|
235
|
+
}
|
|
236
|
+
// ─── Private Helpers ───────────────────────────────────────────────────────
|
|
237
|
+
resolveConfigId(storageConfigId) {
|
|
238
|
+
return storageConfigId ?? this.getDefaultConfigId();
|
|
239
|
+
}
|
|
240
|
+
buildUploadUrl(endpoint, options) {
|
|
241
|
+
const params = this.buildQueryParams(options);
|
|
242
|
+
const baseUrl = this.getUrl(`upload/${endpoint}`);
|
|
243
|
+
return params ? `${baseUrl}?${params}` : baseUrl;
|
|
323
244
|
}
|
|
324
|
-
/**
|
|
325
|
-
* Build query string from upload options
|
|
326
|
-
* Uses default storageConfigId from app config if not provided in options
|
|
327
|
-
*/
|
|
328
245
|
buildQueryParams(options) {
|
|
329
246
|
const params = new URLSearchParams();
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
params.append('storageConfigId', storageConfigId);
|
|
247
|
+
const configId = this.resolveConfigId(options?.storageConfigId);
|
|
248
|
+
if (configId)
|
|
249
|
+
params.append('storageConfigId', configId);
|
|
334
250
|
if (options?.folderPath)
|
|
335
251
|
params.append('folderPath', options.folderPath);
|
|
336
252
|
if (options?.maxWidth)
|
|
@@ -345,73 +261,16 @@ class UploadService extends BaseApiService {
|
|
|
345
261
|
params.append('compress', options.compress.toString());
|
|
346
262
|
return params.toString();
|
|
347
263
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
*
|
|
352
|
-
* @param key - File key/path to delete
|
|
353
|
-
* @param storageConfigId - Optional storage config ID (uses default from config if not provided)
|
|
354
|
-
*/
|
|
355
|
-
deleteSingleFile(key, storageConfigId) {
|
|
356
|
-
const configId = storageConfigId ?? this.getDefaultConfigId();
|
|
357
|
-
return this.http.post(this.getUrl('upload/delete-single-file'), { key, ...(configId && { storageConfigId: configId }) });
|
|
358
|
-
}
|
|
359
|
-
/**
|
|
360
|
-
* Delete multiple files
|
|
361
|
-
* POST /storage/upload/delete-multiple-file
|
|
362
|
-
*
|
|
363
|
-
* @param keys - Array of file keys/paths to delete
|
|
364
|
-
* @param storageConfigId - Optional storage config ID (uses default from config if not provided)
|
|
365
|
-
*/
|
|
366
|
-
deleteMultipleFiles(keys, storageConfigId) {
|
|
367
|
-
const configId = storageConfigId ?? this.getDefaultConfigId();
|
|
368
|
-
return this.http.post(this.getUrl('upload/delete-multiple-file'), { keys, ...(configId && { storageConfigId: configId }) });
|
|
369
|
-
}
|
|
370
|
-
/**
|
|
371
|
-
* Get file download URL
|
|
372
|
-
* GET /storage/upload/file/:filePath
|
|
373
|
-
*
|
|
374
|
-
* @param key - File key/path
|
|
375
|
-
* @returns URL for direct file access
|
|
376
|
-
*/
|
|
377
|
-
getFileUrl(key) {
|
|
378
|
-
return this.getUrl(`upload/file/${key}`);
|
|
379
|
-
}
|
|
380
|
-
/**
|
|
381
|
-
* Upload file and register in file manager
|
|
382
|
-
* Returns file manager ID (UUID) for storing in references like profilePictureId
|
|
383
|
-
*
|
|
384
|
-
* @param file - File to upload
|
|
385
|
-
* @param options - Upload options (storage config, compression, etc.)
|
|
386
|
-
* @returns Observable with file manager record (id is the UUID to store)
|
|
387
|
-
*/
|
|
388
|
-
uploadAndRegister(file, options) {
|
|
389
|
-
return this.uploadSingleFile(file, options).pipe(switchMap((uploadResponse) => {
|
|
390
|
-
if (!uploadResponse.success || !uploadResponse.data) {
|
|
391
|
-
throw new Error(uploadResponse.message || 'Upload failed');
|
|
392
|
-
}
|
|
393
|
-
const uploadedFile = uploadResponse.data;
|
|
394
|
-
const storageConfigId = options?.storageConfigId ?? this.getDefaultConfigId();
|
|
395
|
-
// Create file manager record using proper DTO
|
|
396
|
-
return this.fileManagerApi.createFile({
|
|
397
|
-
name: uploadedFile.name,
|
|
398
|
-
key: uploadedFile.key,
|
|
399
|
-
size: String(uploadedFile.size),
|
|
400
|
-
contentType: uploadedFile.contentType,
|
|
401
|
-
isPrivate: options?.isPrivate ?? false,
|
|
402
|
-
folderId: options?.folderId,
|
|
403
|
-
storageConfigId,
|
|
404
|
-
});
|
|
405
|
-
}));
|
|
264
|
+
buildDeleteBody(data, storageConfigId) {
|
|
265
|
+
const configId = this.resolveConfigId(storageConfigId);
|
|
266
|
+
return { ...data, ...(configId && { storageConfigId: configId }) };
|
|
406
267
|
}
|
|
407
268
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UploadService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
408
269
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UploadService, providedIn: 'root' });
|
|
409
270
|
}
|
|
410
271
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UploadService, decorators: [{
|
|
411
272
|
type: Injectable,
|
|
412
|
-
args: [{
|
|
413
|
-
providedIn: 'root',
|
|
414
|
-
}]
|
|
273
|
+
args: [{ providedIn: 'root' }]
|
|
415
274
|
}], ctorParameters: () => [] });
|
|
416
275
|
|
|
417
276
|
/**
|
|
@@ -532,9 +391,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
532
391
|
|
|
533
392
|
/**
|
|
534
393
|
* Storage Module Routes
|
|
535
|
-
* All
|
|
536
|
-
*
|
|
537
|
-
* All routes are protected by permission guards to prevent direct URL access.
|
|
394
|
+
* All routes protected by permission guards
|
|
538
395
|
*/
|
|
539
396
|
const STORAGE_ROUTES = [
|
|
540
397
|
{
|
|
@@ -544,63 +401,68 @@ const STORAGE_ROUTES = [
|
|
|
544
401
|
// File Manager Routes
|
|
545
402
|
{
|
|
546
403
|
path: 'files',
|
|
404
|
+
canActivate: [permissionGuard(FILE_PERMISSIONS.READ)],
|
|
547
405
|
children: [
|
|
548
406
|
{
|
|
549
407
|
path: '',
|
|
550
|
-
loadComponent: () => import('./flusys-ng-storage-file-manager-list.component-
|
|
408
|
+
loadComponent: () => import('./flusys-ng-storage-file-manager-list.component-McM1zSlE.mjs').then((m) => m.FileManagerListComponent),
|
|
551
409
|
},
|
|
552
410
|
{
|
|
553
411
|
path: 'new',
|
|
554
|
-
|
|
412
|
+
canActivate: [permissionGuard(FILE_PERMISSIONS.CREATE)],
|
|
413
|
+
loadComponent: () => import('./flusys-ng-storage-file-manager-form.component-Bv8ER8J0.mjs').then((m) => m.FileManagerFormComponent),
|
|
555
414
|
},
|
|
556
415
|
{
|
|
557
416
|
path: ':id',
|
|
558
|
-
|
|
417
|
+
canActivate: [permissionGuard(FILE_PERMISSIONS.UPDATE)],
|
|
418
|
+
loadComponent: () => import('./flusys-ng-storage-file-manager-form.component-Bv8ER8J0.mjs').then((m) => m.FileManagerFormComponent),
|
|
559
419
|
},
|
|
560
420
|
],
|
|
561
421
|
},
|
|
562
422
|
// Folder Routes
|
|
563
423
|
{
|
|
564
424
|
path: 'folders',
|
|
425
|
+
canActivate: [permissionGuard(FOLDER_PERMISSIONS.READ)],
|
|
565
426
|
children: [
|
|
566
427
|
{
|
|
567
428
|
path: '',
|
|
568
|
-
loadComponent: () => import('./flusys-ng-storage-folder-list.component-
|
|
429
|
+
loadComponent: () => import('./flusys-ng-storage-folder-list.component-C4xHI8SO.mjs').then((m) => m.FolderListComponent),
|
|
569
430
|
},
|
|
570
431
|
{
|
|
571
432
|
path: 'new',
|
|
572
|
-
|
|
433
|
+
canActivate: [permissionGuard(FOLDER_PERMISSIONS.CREATE)],
|
|
434
|
+
loadComponent: () => import('./flusys-ng-storage-folder-form.component-fRFiMFev.mjs').then((m) => m.FolderFormComponent),
|
|
573
435
|
},
|
|
574
436
|
{
|
|
575
437
|
path: ':id',
|
|
576
|
-
|
|
438
|
+
canActivate: [permissionGuard(FOLDER_PERMISSIONS.UPDATE)],
|
|
439
|
+
loadComponent: () => import('./flusys-ng-storage-folder-form.component-fRFiMFev.mjs').then((m) => m.FolderFormComponent),
|
|
577
440
|
},
|
|
578
441
|
],
|
|
579
442
|
},
|
|
580
443
|
// Storage Config Routes
|
|
581
444
|
{
|
|
582
445
|
path: 'configs',
|
|
446
|
+
canActivate: [permissionGuard(STORAGE_CONFIG_PERMISSIONS.READ)],
|
|
583
447
|
children: [
|
|
584
448
|
{
|
|
585
449
|
path: '',
|
|
586
|
-
loadComponent: () => import('./flusys-ng-storage-storage-config-list.component-
|
|
450
|
+
loadComponent: () => import('./flusys-ng-storage-storage-config-list.component-iJez-rII.mjs').then((m) => m.StorageConfigListComponent),
|
|
587
451
|
},
|
|
588
452
|
{
|
|
589
453
|
path: 'new',
|
|
590
|
-
|
|
454
|
+
canActivate: [permissionGuard(STORAGE_CONFIG_PERMISSIONS.CREATE)],
|
|
455
|
+
loadComponent: () => import('./flusys-ng-storage-storage-config-form.component-DEMexjmg.mjs').then((m) => m.StorageConfigFormComponent),
|
|
591
456
|
},
|
|
592
457
|
{
|
|
593
458
|
path: ':id',
|
|
594
|
-
|
|
459
|
+
canActivate: [permissionGuard(STORAGE_CONFIG_PERMISSIONS.UPDATE)],
|
|
460
|
+
loadComponent: () => import('./flusys-ng-storage-storage-config-form.component-DEMexjmg.mjs').then((m) => m.StorageConfigFormComponent),
|
|
595
461
|
},
|
|
596
462
|
],
|
|
597
463
|
},
|
|
598
|
-
// Default redirect
|
|
599
|
-
{
|
|
600
|
-
path: '',
|
|
601
|
-
redirectTo: 'files',
|
|
602
|
-
pathMatch: 'full',
|
|
603
|
-
},
|
|
464
|
+
// Default redirect
|
|
465
|
+
{ path: '', redirectTo: 'files', pathMatch: 'full' },
|
|
604
466
|
],
|
|
605
467
|
},
|
|
606
468
|
];
|
|
@@ -610,39 +472,53 @@ const STORAGE_ROUTES = [
|
|
|
610
472
|
*
|
|
611
473
|
* Main container for Storage module with tab navigation
|
|
612
474
|
* Routes: Files | Folders | Configurations
|
|
475
|
+
* Tabs are filtered based on user permissions
|
|
613
476
|
*/
|
|
614
477
|
class StorageContainerComponent {
|
|
615
|
-
|
|
616
|
-
tabs
|
|
478
|
+
permissionValidator = inject(PermissionValidatorService);
|
|
479
|
+
/** All available tabs with required permissions */
|
|
480
|
+
allTabs = [
|
|
617
481
|
{
|
|
618
482
|
id: 'files',
|
|
619
483
|
label: 'Files',
|
|
620
484
|
icon: 'pi pi-file',
|
|
621
485
|
route: 'files',
|
|
486
|
+
permission: FILE_PERMISSIONS.READ,
|
|
622
487
|
},
|
|
623
488
|
{
|
|
624
489
|
id: 'folders',
|
|
625
490
|
label: 'Folders',
|
|
626
491
|
icon: 'pi pi-folder',
|
|
627
492
|
route: 'folders',
|
|
493
|
+
permission: FOLDER_PERMISSIONS.READ,
|
|
628
494
|
},
|
|
629
495
|
{
|
|
630
496
|
id: 'configs',
|
|
631
497
|
label: 'Configurations',
|
|
632
498
|
icon: 'pi pi-cog',
|
|
633
499
|
route: 'configs',
|
|
500
|
+
permission: STORAGE_CONFIG_PERMISSIONS.READ,
|
|
634
501
|
},
|
|
635
502
|
];
|
|
503
|
+
/** Visible tabs based on user permissions */
|
|
504
|
+
visibleTabs = computed(() => this.allTabs.filter((tab) => this.permissionValidator.hasPermission(tab.permission)), ...(ngDevMode ? [{ debugName: "visibleTabs" }] : []));
|
|
505
|
+
/** Dynamic subtitle based on visible tabs */
|
|
506
|
+
subtitle = computed(() => {
|
|
507
|
+
const tabs = this.visibleTabs();
|
|
508
|
+
if (tabs.length === 0)
|
|
509
|
+
return 'No permissions available';
|
|
510
|
+
return `Manage ${tabs.map((t) => t.label.toLowerCase()).join(', ')}`;
|
|
511
|
+
}, ...(ngDevMode ? [{ debugName: "subtitle" }] : []));
|
|
636
512
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: StorageContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
637
513
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: StorageContainerComponent, isStandalone: true, selector: "lib-storage-container", ngImport: i0, template: `
|
|
638
514
|
<div class="p-2 sm:p-4">
|
|
639
515
|
<div class="mb-4">
|
|
640
516
|
<h1 class="text-xl sm:text-2xl font-bold m-0">Storage</h1>
|
|
641
|
-
<p class="text-muted-color mt-1 text-sm sm:text-base">
|
|
517
|
+
<p class="text-muted-color mt-1 text-sm sm:text-base">{{ subtitle() }}</p>
|
|
642
518
|
</div>
|
|
643
519
|
|
|
644
520
|
<div class="scrollbar-hide flex gap-1 mb-4 border-b border-surface overflow-x-auto flex-nowrap">
|
|
645
|
-
@for (tab of
|
|
521
|
+
@for (tab of visibleTabs(); track tab.id) {
|
|
646
522
|
<a
|
|
647
523
|
[routerLink]="tab.route"
|
|
648
524
|
routerLinkActive="tab-active"
|
|
@@ -660,15 +536,15 @@ class StorageContainerComponent {
|
|
|
660
536
|
}
|
|
661
537
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: StorageContainerComponent, decorators: [{
|
|
662
538
|
type: Component,
|
|
663
|
-
args: [{ selector: 'lib-storage-container',
|
|
539
|
+
args: [{ selector: 'lib-storage-container', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, RouterOutlet, RouterLink, RouterLinkActive], template: `
|
|
664
540
|
<div class="p-2 sm:p-4">
|
|
665
541
|
<div class="mb-4">
|
|
666
542
|
<h1 class="text-xl sm:text-2xl font-bold m-0">Storage</h1>
|
|
667
|
-
<p class="text-muted-color mt-1 text-sm sm:text-base">
|
|
543
|
+
<p class="text-muted-color mt-1 text-sm sm:text-base">{{ subtitle() }}</p>
|
|
668
544
|
</div>
|
|
669
545
|
|
|
670
546
|
<div class="scrollbar-hide flex gap-1 mb-4 border-b border-surface overflow-x-auto flex-nowrap">
|
|
671
|
-
@for (tab of
|
|
547
|
+
@for (tab of visibleTabs(); track tab.id) {
|
|
672
548
|
<a
|
|
673
549
|
[routerLink]="tab.route"
|
|
674
550
|
routerLinkActive="tab-active"
|