@flusys/ng-storage 1.1.0 → 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.
- package/README.md +36 -762
- package/fesm2022/flusys-ng-storage-file-manager-form.component-DhqZmpuX.mjs +671 -0
- package/fesm2022/flusys-ng-storage-file-manager-form.component-DhqZmpuX.mjs.map +1 -0
- package/fesm2022/flusys-ng-storage-file-manager-list.component-nZDj1UfS.mjs +464 -0
- package/fesm2022/flusys-ng-storage-file-manager-list.component-nZDj1UfS.mjs.map +1 -0
- package/fesm2022/flusys-ng-storage-folder-form.component-Bru9NQyr.mjs +218 -0
- package/fesm2022/flusys-ng-storage-folder-form.component-Bru9NQyr.mjs.map +1 -0
- package/fesm2022/flusys-ng-storage-folder-list.component-fuJMWYWZ.mjs +263 -0
- package/fesm2022/flusys-ng-storage-folder-list.component-fuJMWYWZ.mjs.map +1 -0
- package/fesm2022/flusys-ng-storage-storage-config-form.component-Da-pWR7d.mjs +891 -0
- package/fesm2022/flusys-ng-storage-storage-config-form.component-Da-pWR7d.mjs.map +1 -0
- package/fesm2022/flusys-ng-storage-storage-config-list.component-D59X4sae.mjs +288 -0
- package/fesm2022/flusys-ng-storage-storage-config-list.component-D59X4sae.mjs.map +1 -0
- package/fesm2022/flusys-ng-storage.mjs +533 -216
- package/fesm2022/flusys-ng-storage.mjs.map +1 -1
- package/package.json +11 -10
- package/types/flusys-ng-storage.d.ts +99 -48
- package/fesm2022/flusys-ng-storage-file-manager-form.component-CXVB9G-f.mjs +0 -484
- package/fesm2022/flusys-ng-storage-file-manager-form.component-CXVB9G-f.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-file-manager-list.component-0O_b4EjN.mjs +0 -304
- package/fesm2022/flusys-ng-storage-file-manager-list.component-0O_b4EjN.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-folder-form.component-BTQGEqNu.mjs +0 -155
- package/fesm2022/flusys-ng-storage-folder-form.component-BTQGEqNu.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-folder-list.component-B8GoIh6Z.mjs +0 -194
- package/fesm2022/flusys-ng-storage-folder-list.component-B8GoIh6Z.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-storage-config-form.component-CorNWrmF.mjs +0 -463
- package/fesm2022/flusys-ng-storage-storage-config-form.component-CorNWrmF.mjs.map +0 -1
- package/fesm2022/flusys-ng-storage-storage-config-list.component-YXzz3Tvo.mjs +0 -187
- package/fesm2022/flusys-ng-storage-storage-config-list.component-YXzz3Tvo.mjs.map +0 -1
|
@@ -1,14 +1,166 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, signal, computed, Directive,
|
|
3
|
-
import {
|
|
2
|
+
import { inject, signal, computed, Directive, DestroyRef, Injectable, Component } from '@angular/core';
|
|
3
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
4
|
+
import { Router, RouterOutlet } from '@angular/router';
|
|
4
5
|
import { APP_CONFIG, DEFAULT_APP_NAME, BaseApiService, getDefaultStorageConfigId } from '@flusys/ng-core';
|
|
5
6
|
import { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';
|
|
6
|
-
import {
|
|
7
|
-
import { MessageService } from '
|
|
8
|
-
import { map } from 'rxjs
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
import { TranslateService, ApiResourceService, FILE_PROVIDER, permissionGuard, FILE_PERMISSIONS, FOLDER_PERMISSIONS, STORAGE_CONFIG_PERMISSIONS, resolveTranslationModule, SHARED_MESSAGES, PermissionValidatorService, RouterTabsComponent, TranslatePipe } from '@flusys/ng-shared';
|
|
8
|
+
import { MessageService, ConfirmationService } from '@flusys/ng-ui';
|
|
9
|
+
import { from, switchMap, map } from 'rxjs';
|
|
10
|
+
|
|
11
|
+
const STORAGE_MESSAGES = {
|
|
12
|
+
// File entity CRUD (API keys)
|
|
13
|
+
'file.create.success': 'File created successfully',
|
|
14
|
+
'file.create.many.success': '{{count}} files created successfully',
|
|
15
|
+
'file.get.success': 'File retrieved successfully',
|
|
16
|
+
'file.get.by.ids.success': 'Files retrieved successfully by Ids',
|
|
17
|
+
'file.get.by.filter.success': 'Files retrieved successfully by filter',
|
|
18
|
+
'file.get.all.success': 'Files retrieved successfully',
|
|
19
|
+
'file.update.success': 'File updated successfully',
|
|
20
|
+
'file.update.many.success': '{{count}} files updated successfully',
|
|
21
|
+
'file.delete.success': 'File deleted successfully',
|
|
22
|
+
'file.restore.success': 'File restored successfully',
|
|
23
|
+
'file.not.found': 'File not found',
|
|
24
|
+
// Folder entity CRUD (API keys)
|
|
25
|
+
'folder.create.success': 'Folder created successfully',
|
|
26
|
+
'folder.create.many.success': '{{count}} folders created successfully',
|
|
27
|
+
'folder.get.success': 'Folder retrieved successfully',
|
|
28
|
+
'folder.get.by.ids.success': 'Folders retrieved successfully by Ids',
|
|
29
|
+
'folder.get.by.filter.success': 'Folders retrieved successfully by filter',
|
|
30
|
+
'folder.get.all.success': 'Folders retrieved successfully',
|
|
31
|
+
'folder.update.success': 'Folder updated successfully',
|
|
32
|
+
'folder.update.many.success': '{{count}} folders updated successfully',
|
|
33
|
+
'folder.delete.success': 'Folder deleted successfully',
|
|
34
|
+
'folder.restore.success': 'Folder restored successfully',
|
|
35
|
+
'folder.not.found': 'Folder not found',
|
|
36
|
+
// Storage config CRUD (API keys)
|
|
37
|
+
'storage.config.create.success': 'Storage configuration created successfully',
|
|
38
|
+
'storage.config.create.many.success': '{{count}} storage configurations created successfully',
|
|
39
|
+
'storage.config.get.success': 'Storage configuration retrieved successfully',
|
|
40
|
+
'storage.config.get.by.ids.success': 'Storage configurations retrieved successfully by Ids',
|
|
41
|
+
'storage.config.get.by.filter.success': 'Storage configurations retrieved successfully by filter',
|
|
42
|
+
'storage.config.get.all.success': 'Storage configurations retrieved successfully',
|
|
43
|
+
'storage.config.update.success': 'Storage configuration updated successfully',
|
|
44
|
+
'storage.config.update.many.success': '{{count}} storage configurations updated successfully',
|
|
45
|
+
'storage.config.delete.success': 'Storage configuration deleted successfully',
|
|
46
|
+
'storage.config.restore.success': 'Storage configuration restored successfully',
|
|
47
|
+
// Upload (API keys)
|
|
48
|
+
'upload.success': 'File uploaded successfully',
|
|
49
|
+
'upload.many.success': 'Files uploaded successfully',
|
|
50
|
+
'upload.file.too.large': 'File size ({{fileSize}}MB) exceeds maximum {{maxSize}}MB',
|
|
51
|
+
'upload.invalid.type': 'File type "{{mimeType}}" not allowed. Allowed: {{allowedTypes}}',
|
|
52
|
+
'upload.no.files.provided': 'No files provided',
|
|
53
|
+
'upload.no.file.path': 'File path is required',
|
|
54
|
+
'upload.invalid.file.path': 'Invalid file path',
|
|
55
|
+
'upload.config.not.found': 'Upload configuration not found',
|
|
56
|
+
// pages/storage-container/storage-container.component.ts
|
|
57
|
+
'storage.title': 'Storage',
|
|
58
|
+
'storage.subtitle': 'Manage files, folders, and storage configurations',
|
|
59
|
+
'storage.file.title': 'Files',
|
|
60
|
+
'storage.folder.title': 'Folder Setup',
|
|
61
|
+
'storage.config.title': 'Storage Configurations',
|
|
62
|
+
// pages/storage-config/storage-config-list.component.ts
|
|
63
|
+
'storage.button.new.configuration': 'New Configuration',
|
|
64
|
+
'storage.table.provider': 'Provider',
|
|
65
|
+
'storage.table.created': 'Created',
|
|
66
|
+
'storage.empty.configs.in.company': 'No storage configurations found in current company',
|
|
67
|
+
'storage.empty.configs': 'No storage configurations found',
|
|
68
|
+
'storage.config.load.failed': 'Failed to load storage configurations',
|
|
69
|
+
'storage.config.delete.title': 'Delete Configuration',
|
|
70
|
+
// pages/storage-config/storage-config-form.component.ts
|
|
71
|
+
'storage.config.edit.config': 'Edit Storage Configuration',
|
|
72
|
+
'storage.config.new.config': 'New Configuration',
|
|
73
|
+
'storage.config.config.name.required': 'Configuration Name *',
|
|
74
|
+
'storage.config.config.name.placeholder': 'e.g., Production AWS S3',
|
|
75
|
+
'storage.config.provider.required': 'Storage Provider *',
|
|
76
|
+
'storage.set.as.default': 'Set as Default',
|
|
77
|
+
'storage.aws.title': 'AWS S3 Configuration',
|
|
78
|
+
'storage.config.region.required': 'AWS Region *',
|
|
79
|
+
'storage.aws.region.placeholder': 'us-east-1',
|
|
80
|
+
'storage.config.bucket.required': 'Bucket Name *',
|
|
81
|
+
'storage.aws.bucket.placeholder': 'my-bucket',
|
|
82
|
+
'storage.config.access.key.required': 'Access Key ID *',
|
|
83
|
+
'storage.config.secret.key.required': 'Secret Access Key *',
|
|
84
|
+
'storage.config.endpoint.optional': 'Custom Endpoint (Optional)',
|
|
85
|
+
'storage.config.endpoint.placeholder': 'https://s3.custom-endpoint.com',
|
|
86
|
+
'storage.azure.title': 'Azure Blob Configuration',
|
|
87
|
+
'storage.azure.account.name.required': 'Account Name *',
|
|
88
|
+
'storage.azure.container.name.required': 'Container Name *',
|
|
89
|
+
'storage.azure.account.key.required': 'Account Key *',
|
|
90
|
+
'storage.sftp.title': 'SFTP Configuration',
|
|
91
|
+
'storage.sftp.host.required': 'Host *',
|
|
92
|
+
'storage.sftp.host.placeholder': 'sftp.example.com',
|
|
93
|
+
'storage.sftp.port.required': 'Port *',
|
|
94
|
+
'storage.sftp.port.placeholder': '22',
|
|
95
|
+
'storage.sftp.username.required': 'Username *',
|
|
96
|
+
'storage.sftp.password.required': 'Password *',
|
|
97
|
+
'storage.sftp.base.path.required': 'Base Path *',
|
|
98
|
+
'storage.sftp.base.path.placeholder': '/uploads',
|
|
99
|
+
'storage.local.title': 'Local Storage Configuration',
|
|
100
|
+
'storage.local.base.path.required': 'Base Path *',
|
|
101
|
+
'storage.local.base.path.placeholder': '/var/www/uploads',
|
|
102
|
+
'storage.config.endpoint': 'Endpoint URL',
|
|
103
|
+
'storage.validation.config.name.required': 'Configuration name is required',
|
|
104
|
+
// pages/file-manager/file-manager-list.component.ts
|
|
105
|
+
'storage.file.manager.title': 'File Manager',
|
|
106
|
+
'storage.button.upload.file': 'Upload File',
|
|
107
|
+
'storage.table.size': 'Size',
|
|
108
|
+
'storage.table.location': 'Location',
|
|
109
|
+
'storage.table.config': 'Config',
|
|
110
|
+
'storage.table.private': 'Private',
|
|
111
|
+
'storage.private': 'Private',
|
|
112
|
+
'storage.public': 'Public',
|
|
113
|
+
'storage.tooltip.trash': 'Trash',
|
|
114
|
+
'storage.empty.files.in.company': 'No files found in current company',
|
|
115
|
+
'storage.empty.files': 'No files found',
|
|
116
|
+
'storage.file.url.not.available': 'File URL is not available',
|
|
117
|
+
'storage.delete.move.to.trash.confirm': 'Move "{{name}}" to trash? You can recover it later.',
|
|
118
|
+
'storage.delete.move.to.trash': 'Move to Trash',
|
|
119
|
+
'storage.delete.permanent.delete.confirm': 'Permanently delete "{{name}}"? This action CANNOT be undone and will delete the file from storage.',
|
|
120
|
+
'storage.delete.permanent.delete': 'Permanent Delete',
|
|
121
|
+
'storage.delete.permanent.delete.button': 'Delete Permanently',
|
|
122
|
+
// pages/file-manager/file-manager-form.component.ts
|
|
123
|
+
'storage.file.manager.edit.file': 'Edit File',
|
|
124
|
+
'storage.file.manager.upload.file': 'Upload File',
|
|
125
|
+
'storage.config.select.config': 'Select storage configuration...',
|
|
126
|
+
'storage.config.no.configs': 'No storage configurations found. Please create one first.',
|
|
127
|
+
'storage.folder.optional': 'Folder (Optional)',
|
|
128
|
+
'storage.folder.no.folder': 'No folder (root level)',
|
|
129
|
+
'storage.folder.no.folders.available': 'No folders available. File will be uploaded to root level.',
|
|
130
|
+
'storage.folder.no.folders.edit': 'No folders available.',
|
|
131
|
+
'storage.file.select.required': 'Select File *',
|
|
132
|
+
'storage.button.choose.file': 'Choose File',
|
|
133
|
+
'storage.upload.drag.drop': 'Drag and drop file here or click to browse',
|
|
134
|
+
'storage.upload.max.size': 'Maximum file size: {{size}}',
|
|
135
|
+
'storage.upload.please.select': 'Please select a file to upload',
|
|
136
|
+
'storage.file.name.required': 'File Name *',
|
|
137
|
+
'storage.file.placeholder.edit': 'Enter file name',
|
|
138
|
+
'storage.file.placeholder': 'Will be auto-filled from selected file',
|
|
139
|
+
'storage.file.private': 'Private File',
|
|
140
|
+
'storage.file.private.hint': 'Only users with permission can access',
|
|
141
|
+
'storage.file.public.hint': 'File is publicly accessible',
|
|
142
|
+
'storage.validation.file.name.required': 'File name is required',
|
|
143
|
+
'storage.error.no.file': 'Please select a file',
|
|
144
|
+
'storage.error.no.config': 'Please select a storage configuration',
|
|
145
|
+
'storage.upload.failed': 'Failed to upload file',
|
|
146
|
+
// pages/folder/folder-list.component.ts
|
|
147
|
+
'storage.button.new.folder': 'New Folder',
|
|
148
|
+
'storage.table.slug': 'Slug',
|
|
149
|
+
'storage.empty.folders.in.company': 'No folders found in current company',
|
|
150
|
+
'storage.empty.folders': 'No folders found',
|
|
151
|
+
'storage.folder.delete.title': 'Delete Folder',
|
|
152
|
+
// pages/folder/folder-form.component.ts
|
|
153
|
+
'storage.folder.edit.folder': 'Edit Folder',
|
|
154
|
+
'storage.folder.new.folder': 'New Folder',
|
|
155
|
+
'storage.folder.name.required': 'Folder Name *',
|
|
156
|
+
'storage.folder.name.placeholder': 'Enter folder name',
|
|
157
|
+
'storage.validation.folder.name.required': 'Folder name is required',
|
|
158
|
+
// utils/base-storage-page.ts
|
|
159
|
+
'storage.delete.this.item': 'this item',
|
|
160
|
+
// utils/storage-utils.ts
|
|
161
|
+
'storage.size.bytes': 'Bytes',
|
|
162
|
+
'storage.size.gb': 'GB',
|
|
163
|
+
};
|
|
12
164
|
|
|
13
165
|
/**
|
|
14
166
|
* File Location Enum
|
|
@@ -33,47 +185,56 @@ var ImageFormat;
|
|
|
33
185
|
ImageFormat["WEBP"] = "webp";
|
|
34
186
|
})(ImageFormat || (ImageFormat = {}));
|
|
35
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Provider label translation keys
|
|
190
|
+
*/
|
|
191
|
+
const PROVIDER_LABEL_KEYS = {
|
|
192
|
+
[FileLocationEnum.LOCAL]: 'storage.local.title',
|
|
193
|
+
[FileLocationEnum.AWS]: 'storage.aws.title',
|
|
194
|
+
[FileLocationEnum.AZURE]: 'storage.azure.title',
|
|
195
|
+
[FileLocationEnum.SFTP]: 'storage.sftp.title',
|
|
196
|
+
};
|
|
36
197
|
/**
|
|
37
198
|
* Provider configurations for all storage types
|
|
38
199
|
*/
|
|
39
200
|
const PROVIDER_CONFIGS = {
|
|
40
201
|
[FileLocationEnum.LOCAL]: {
|
|
41
|
-
|
|
42
|
-
icon: '
|
|
202
|
+
labelKey: 'storage.local.title',
|
|
203
|
+
icon: 'folder',
|
|
43
204
|
severity: 'secondary',
|
|
44
205
|
},
|
|
45
206
|
[FileLocationEnum.AWS]: {
|
|
46
|
-
|
|
47
|
-
icon: '
|
|
207
|
+
labelKey: 'storage.aws.title',
|
|
208
|
+
icon: 'cloud',
|
|
48
209
|
severity: 'warn',
|
|
49
210
|
},
|
|
50
211
|
[FileLocationEnum.AZURE]: {
|
|
51
|
-
|
|
52
|
-
icon: '
|
|
212
|
+
labelKey: 'storage.azure.title',
|
|
213
|
+
icon: 'cloud',
|
|
53
214
|
severity: 'info',
|
|
54
215
|
},
|
|
55
216
|
[FileLocationEnum.SFTP]: {
|
|
56
|
-
|
|
57
|
-
icon: '
|
|
217
|
+
labelKey: 'storage.sftp.title',
|
|
218
|
+
icon: 'server',
|
|
58
219
|
severity: 'contrast',
|
|
59
220
|
},
|
|
60
221
|
};
|
|
61
222
|
/**
|
|
62
|
-
* Get provider label
|
|
223
|
+
* Get provider label translation key
|
|
63
224
|
*/
|
|
64
|
-
function
|
|
225
|
+
function getProviderLabelKey(storage) {
|
|
65
226
|
const enumValue = storage;
|
|
66
|
-
return PROVIDER_CONFIGS[enumValue]?.
|
|
227
|
+
return PROVIDER_CONFIGS[enumValue]?.labelKey ?? storage;
|
|
67
228
|
}
|
|
68
229
|
/**
|
|
69
230
|
* Get provider icon class
|
|
70
231
|
*/
|
|
71
232
|
function getProviderIcon(storage) {
|
|
72
233
|
const enumValue = storage;
|
|
73
|
-
return PROVIDER_CONFIGS[enumValue]?.icon ?? '
|
|
234
|
+
return PROVIDER_CONFIGS[enumValue]?.icon ?? 'database';
|
|
74
235
|
}
|
|
75
236
|
/**
|
|
76
|
-
* Get provider severity for
|
|
237
|
+
* Get provider severity for f-tag
|
|
77
238
|
*/
|
|
78
239
|
function getProviderSeverity(storage) {
|
|
79
240
|
const enumValue = storage;
|
|
@@ -84,38 +245,62 @@ function getProviderSeverity(storage) {
|
|
|
84
245
|
*/
|
|
85
246
|
function getFileIcon(contentType) {
|
|
86
247
|
if (contentType.startsWith('image/'))
|
|
87
|
-
return '
|
|
248
|
+
return 'image';
|
|
88
249
|
if (contentType.startsWith('video/'))
|
|
89
|
-
return '
|
|
250
|
+
return 'video';
|
|
90
251
|
if (contentType.startsWith('audio/'))
|
|
91
|
-
return '
|
|
252
|
+
return 'volume-up';
|
|
92
253
|
if (contentType.includes('pdf'))
|
|
93
|
-
return '
|
|
254
|
+
return 'file-pdf';
|
|
94
255
|
if (contentType.includes('word') || contentType.includes('document'))
|
|
95
|
-
return '
|
|
256
|
+
return 'file-word';
|
|
96
257
|
if (contentType.includes('excel') || contentType.includes('spreadsheet'))
|
|
97
|
-
return '
|
|
98
|
-
return '
|
|
258
|
+
return 'file-excel';
|
|
259
|
+
return 'file';
|
|
99
260
|
}
|
|
261
|
+
/** File size unit keys for translation */
|
|
262
|
+
const FILE_SIZE_UNIT_KEYS = [
|
|
263
|
+
'storage.size.bytes',
|
|
264
|
+
'shared.size.kb',
|
|
265
|
+
'shared.size.mb',
|
|
266
|
+
'storage.size.gb',
|
|
267
|
+
];
|
|
100
268
|
/**
|
|
101
|
-
* Format file size from bytes to human readable
|
|
269
|
+
* Format file size from bytes to human readable format
|
|
270
|
+
* Returns an object with value and unitKey for translation
|
|
102
271
|
*/
|
|
103
|
-
function
|
|
272
|
+
function formatFileSizeWithKey(bytes) {
|
|
104
273
|
if (bytes <= 0)
|
|
105
|
-
return '0
|
|
274
|
+
return { value: '0', unitKey: 'storage.size.bytes' };
|
|
106
275
|
const k = 1024;
|
|
107
|
-
const
|
|
108
|
-
const
|
|
109
|
-
return
|
|
276
|
+
const i = Math.min(Math.floor(Math.log(bytes) / Math.log(k)), FILE_SIZE_UNIT_KEYS.length - 1);
|
|
277
|
+
const value = (Math.round((bytes / Math.pow(k, i)) * 100) / 100).toString();
|
|
278
|
+
return { value, unitKey: FILE_SIZE_UNIT_KEYS[i] };
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Format file size from bytes to human readable string
|
|
282
|
+
* @deprecated Use formatFileSizeWithKey for localization support
|
|
283
|
+
*/
|
|
284
|
+
function formatFileSize(bytes) {
|
|
285
|
+
const { value, unitKey } = formatFileSizeWithKey(bytes);
|
|
286
|
+
// Fallback to non-translated units for backward compatibility
|
|
287
|
+
const unitMap = {
|
|
288
|
+
'storage.size.bytes': 'Bytes',
|
|
289
|
+
'shared.size.kb': 'KB',
|
|
290
|
+
'shared.size.mb': 'MB',
|
|
291
|
+
'storage.size.gb': 'GB',
|
|
292
|
+
};
|
|
293
|
+
return `${value} ${unitMap[unitKey]}`;
|
|
110
294
|
}
|
|
111
295
|
/**
|
|
112
296
|
* Storage provider options for dropdown selects
|
|
297
|
+
* Labels are translation keys - components should translate them
|
|
113
298
|
*/
|
|
114
|
-
const
|
|
115
|
-
{
|
|
116
|
-
{
|
|
117
|
-
{
|
|
118
|
-
{
|
|
299
|
+
const STORAGE_PROVIDER_OPTIONS = [
|
|
300
|
+
{ labelKey: 'storage.aws.title', value: FileLocationEnum.AWS },
|
|
301
|
+
{ labelKey: 'storage.azure.title', value: FileLocationEnum.AZURE },
|
|
302
|
+
{ labelKey: 'storage.sftp.title', value: FileLocationEnum.SFTP },
|
|
303
|
+
{ labelKey: 'storage.local.title', value: FileLocationEnum.LOCAL },
|
|
119
304
|
];
|
|
120
305
|
|
|
121
306
|
class BaseStoragePage {
|
|
@@ -123,43 +308,151 @@ class BaseStoragePage {
|
|
|
123
308
|
messageService = inject(MessageService);
|
|
124
309
|
appConfig = inject(APP_CONFIG);
|
|
125
310
|
companyContext = inject(LAYOUT_AUTH_STATE);
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
311
|
+
translateAdapter = inject(TranslateService);
|
|
312
|
+
isLoading = signal(false, /* @ts-ignore */
|
|
313
|
+
...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
|
|
314
|
+
showCompanyInfo = computed(() => this.appConfig.enableCompanyFeature, /* @ts-ignore */
|
|
315
|
+
...(ngDevMode ? [{ debugName: "showCompanyInfo" }] : /* istanbul ignore next */ []));
|
|
316
|
+
currentCompanyName = computed(() => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME, /* @ts-ignore */
|
|
317
|
+
...(ngDevMode ? [{ debugName: "currentCompanyName" }] : /* istanbul ignore next */ []));
|
|
318
|
+
showSuccess(detail, summaryKey = 'shared.success') {
|
|
319
|
+
const summary = this.translateAdapter.translate(summaryKey);
|
|
130
320
|
this.messageService.add({ severity: 'success', summary, detail });
|
|
131
321
|
}
|
|
132
|
-
showError(detail,
|
|
322
|
+
showError(detail, summaryKey = 'shared.error') {
|
|
323
|
+
const summary = this.translateAdapter.translate(summaryKey);
|
|
133
324
|
this.messageService.add({ severity: 'error', summary, detail });
|
|
134
325
|
}
|
|
135
326
|
navigateTo(path) {
|
|
136
327
|
this.router.navigate(path);
|
|
137
328
|
}
|
|
138
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
139
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
329
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: BaseStoragePage, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
330
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.6", type: BaseStoragePage, isStandalone: true, ngImport: i0 });
|
|
140
331
|
}
|
|
141
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
332
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: BaseStoragePage, decorators: [{
|
|
142
333
|
type: Directive
|
|
143
334
|
}] });
|
|
144
|
-
class BaseStorageListPage
|
|
335
|
+
class BaseStorageListPage {
|
|
336
|
+
router = inject(Router);
|
|
337
|
+
messageService = inject(MessageService);
|
|
338
|
+
appConfig = inject(APP_CONFIG);
|
|
339
|
+
confirmationService = inject(ConfirmationService);
|
|
340
|
+
destroyRef = inject(DestroyRef);
|
|
341
|
+
translateAdapter = inject(TranslateService);
|
|
145
342
|
companyContext = inject(LAYOUT_AUTH_STATE);
|
|
146
|
-
|
|
343
|
+
items = signal([], /* @ts-ignore */
|
|
344
|
+
...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
345
|
+
isLoading = signal(false, /* @ts-ignore */
|
|
346
|
+
...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
|
|
347
|
+
total = signal(0, /* @ts-ignore */
|
|
348
|
+
...(ngDevMode ? [{ debugName: "total" }] : /* istanbul ignore next */ []));
|
|
349
|
+
pageSize = signal(50, /* @ts-ignore */
|
|
350
|
+
...(ngDevMode ? [{ debugName: "pageSize" }] : /* istanbul ignore next */ []));
|
|
351
|
+
first = signal(0, /* @ts-ignore */
|
|
352
|
+
...(ngDevMode ? [{ debugName: "first" }] : /* istanbul ignore next */ []));
|
|
353
|
+
currentPage = computed(() => Math.floor(this.first() / this.pageSize()), /* @ts-ignore */
|
|
354
|
+
...(ngDevMode ? [{ debugName: "currentPage" }] : /* istanbul ignore next */ []));
|
|
355
|
+
showCompanyInfo = computed(() => this.appConfig.enableCompanyFeature, /* @ts-ignore */
|
|
356
|
+
...(ngDevMode ? [{ debugName: "showCompanyInfo" }] : /* istanbul ignore next */ []));
|
|
147
357
|
totalRecords = this.total;
|
|
148
|
-
currentCompanyName = computed(() => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME,
|
|
358
|
+
currentCompanyName = computed(() => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME, /* @ts-ignore */
|
|
359
|
+
...(ngDevMode ? [{ debugName: "currentCompanyName" }] : /* istanbul ignore next */ []));
|
|
149
360
|
getDeleteConfirmMessage(item) {
|
|
150
|
-
const
|
|
151
|
-
|
|
361
|
+
const itemName = item.name;
|
|
362
|
+
const name = itemName ?? this.translateAdapter.translate('storage.delete.this.item');
|
|
363
|
+
return this.translateAdapter.translate('shared.confirm.delete.item', { name });
|
|
364
|
+
}
|
|
365
|
+
onCreate() {
|
|
366
|
+
this.router.navigate([this.getResourceRoute(), 'new']);
|
|
367
|
+
}
|
|
368
|
+
onEdit(id) {
|
|
369
|
+
this.router.navigate([this.getResourceRoute(), id]);
|
|
370
|
+
}
|
|
371
|
+
onPageChange(event) {
|
|
372
|
+
this.first.set(event.first ?? 0);
|
|
373
|
+
this.pageSize.set(event.rows ?? 10);
|
|
374
|
+
this.loadData();
|
|
375
|
+
}
|
|
376
|
+
getPaginationParams() {
|
|
377
|
+
return { currentPage: this.currentPage(), pageSize: this.pageSize() };
|
|
378
|
+
}
|
|
379
|
+
showSuccess(detail, summary) {
|
|
380
|
+
this.messageService.add({
|
|
381
|
+
severity: 'success',
|
|
382
|
+
summary: summary ?? this.t('shared.success'),
|
|
383
|
+
detail,
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
showError(detail, summary) {
|
|
387
|
+
this.messageService.add({
|
|
388
|
+
severity: 'error',
|
|
389
|
+
summary: summary ?? this.t('shared.error'),
|
|
390
|
+
detail,
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
showInfo(detail, summary) {
|
|
394
|
+
this.messageService.add({
|
|
395
|
+
severity: 'info',
|
|
396
|
+
summary: summary ?? this.t('shared.info'),
|
|
397
|
+
detail,
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
showWarn(detail, summary) {
|
|
401
|
+
this.messageService.add({
|
|
402
|
+
severity: 'warn',
|
|
403
|
+
summary: summary ?? this.t('shared.warning'),
|
|
404
|
+
detail,
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
onDelete(item, idGetter, deleteApiCall, options) {
|
|
408
|
+
this.confirmationService.confirm({
|
|
409
|
+
message: this.getDeleteConfirmMessage(item),
|
|
410
|
+
header: options?.header ?? this.t('shared.confirm.delete.header'),
|
|
411
|
+
icon: 'exclamation-triangle',
|
|
412
|
+
acceptButtonStyleClass: 'p-button-danger',
|
|
413
|
+
accept: () => {
|
|
414
|
+
from(deleteApiCall(idGetter(item)))
|
|
415
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
416
|
+
.subscribe({
|
|
417
|
+
next: (res) => {
|
|
418
|
+
const r = res;
|
|
419
|
+
this.showSuccess(r?.messageKey ? this.t(r.messageKey, r.messageVariables) : (r?.message ?? ''));
|
|
420
|
+
this.loadData();
|
|
421
|
+
},
|
|
422
|
+
});
|
|
423
|
+
},
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
async onDeleteAsync(item, idGetter, deleteApiCall, options) {
|
|
427
|
+
this.confirmationService.confirm({
|
|
428
|
+
message: this.getDeleteConfirmMessage(item),
|
|
429
|
+
header: options?.header ?? this.t('shared.confirm.delete.header'),
|
|
430
|
+
icon: 'exclamation-triangle',
|
|
431
|
+
acceptButtonStyleClass: 'p-button-danger',
|
|
432
|
+
accept: async () => {
|
|
433
|
+
const res = await deleteApiCall(idGetter(item));
|
|
434
|
+
const r = res;
|
|
435
|
+
this.showSuccess(r?.messageKey ? this.t(r.messageKey, r.messageVariables) : (r?.message ?? ''));
|
|
436
|
+
await this.loadData();
|
|
437
|
+
},
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
navigateTo(path) {
|
|
441
|
+
this.router.navigate(path);
|
|
152
442
|
}
|
|
153
|
-
|
|
154
|
-
|
|
443
|
+
t(key, variables) {
|
|
444
|
+
return this.translateAdapter?.translate(key, variables) ?? key;
|
|
445
|
+
}
|
|
446
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: BaseStorageListPage, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
447
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.6", type: BaseStorageListPage, isStandalone: true, ngImport: i0 });
|
|
155
448
|
}
|
|
156
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
449
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: BaseStorageListPage, decorators: [{
|
|
157
450
|
type: Directive
|
|
158
451
|
}] });
|
|
159
452
|
|
|
160
453
|
class FileManagerApiService extends ApiResourceService {
|
|
161
454
|
constructor() {
|
|
162
|
-
super('file-manager',
|
|
455
|
+
super('file-manager', 'storage');
|
|
163
456
|
}
|
|
164
457
|
getFiles(fileIds) {
|
|
165
458
|
const requests = fileIds.map((id) => ({ id }));
|
|
@@ -168,17 +461,59 @@ class FileManagerApiService extends ApiResourceService {
|
|
|
168
461
|
createFile(dto) {
|
|
169
462
|
return this.http.post(`${this.baseUrl}/insert`, dto);
|
|
170
463
|
}
|
|
171
|
-
|
|
172
|
-
return
|
|
464
|
+
createFiles(dtos) {
|
|
465
|
+
return this.http.post(`${this.baseUrl}/insert-many`, dtos);
|
|
173
466
|
}
|
|
174
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
175
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
467
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: FileManagerApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
468
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: FileManagerApiService, providedIn: 'root' });
|
|
176
469
|
}
|
|
177
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
470
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: FileManagerApiService, decorators: [{
|
|
178
471
|
type: Injectable,
|
|
179
472
|
args: [{ providedIn: 'root' }]
|
|
180
473
|
}], ctorParameters: () => [] });
|
|
181
474
|
|
|
475
|
+
/**
|
|
476
|
+
* Folder API Service
|
|
477
|
+
* Handles folder CRUD operations
|
|
478
|
+
* Endpoint: POST /storage/folder/*
|
|
479
|
+
*
|
|
480
|
+
* Note: Company feature enabled - all queries automatically scoped to user's company
|
|
481
|
+
*/
|
|
482
|
+
class FolderApiService extends ApiResourceService {
|
|
483
|
+
constructor() {
|
|
484
|
+
super('folder', 'storage');
|
|
485
|
+
}
|
|
486
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: FolderApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
487
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: FolderApiService, providedIn: 'root' });
|
|
488
|
+
}
|
|
489
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: FolderApiService, decorators: [{
|
|
490
|
+
type: Injectable,
|
|
491
|
+
args: [{
|
|
492
|
+
providedIn: 'root',
|
|
493
|
+
}]
|
|
494
|
+
}], ctorParameters: () => [] });
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Storage Config API Service
|
|
498
|
+
* Handles storage configuration CRUD operations
|
|
499
|
+
* Endpoint: POST /storage/storage-config/*
|
|
500
|
+
*
|
|
501
|
+
* Note: Company feature enabled - all queries automatically scoped to user's company
|
|
502
|
+
*/
|
|
503
|
+
class StorageConfigApiService extends ApiResourceService {
|
|
504
|
+
constructor() {
|
|
505
|
+
super('storage-config', 'storage');
|
|
506
|
+
}
|
|
507
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: StorageConfigApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
508
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: StorageConfigApiService, providedIn: 'root' });
|
|
509
|
+
}
|
|
510
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: StorageConfigApiService, decorators: [{
|
|
511
|
+
type: Injectable,
|
|
512
|
+
args: [{
|
|
513
|
+
providedIn: 'root',
|
|
514
|
+
}]
|
|
515
|
+
}], ctorParameters: () => [] });
|
|
516
|
+
|
|
182
517
|
/**
|
|
183
518
|
* Upload Service - File upload/delete operations
|
|
184
519
|
* Endpoint: POST /storage/upload/*
|
|
@@ -220,23 +555,40 @@ class UploadService extends BaseApiService {
|
|
|
220
555
|
uploadAndRegister(file, options) {
|
|
221
556
|
return this.uploadSingleFile(file, options).pipe(switchMap((response) => {
|
|
222
557
|
if (!response.success || !response.data) {
|
|
223
|
-
throw new Error(response.message || '
|
|
558
|
+
throw new Error(response.message || 'upload.failed');
|
|
559
|
+
}
|
|
560
|
+
return this.fileManagerApi.createFile(this.toCreateFileDto(response.data, options));
|
|
561
|
+
}));
|
|
562
|
+
}
|
|
563
|
+
/** Upload multiple files and register in file manager - batch upload (2 API calls total) */
|
|
564
|
+
uploadAndRegisterMultiple(files, options) {
|
|
565
|
+
return this.uploadMultipleFiles(files, options).pipe(switchMap((response) => {
|
|
566
|
+
if (!response.success || !response.data) {
|
|
567
|
+
throw new Error(response.message || 'upload.failed');
|
|
224
568
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
folderId: options?.folderId,
|
|
232
|
-
storageConfigId: this.resolveConfigId(options?.storageConfigId),
|
|
233
|
-
});
|
|
569
|
+
const dtos = response.data.map((fileInfo) => this.toCreateFileDto(fileInfo, options));
|
|
570
|
+
return this.fileManagerApi.createFiles(dtos).pipe(map((bulkResponse) => ({
|
|
571
|
+
success: bulkResponse.success,
|
|
572
|
+
data: bulkResponse.data ?? [],
|
|
573
|
+
message: bulkResponse.message,
|
|
574
|
+
})));
|
|
234
575
|
}));
|
|
235
576
|
}
|
|
236
577
|
// ─── Private Helpers ───────────────────────────────────────────────────────
|
|
237
578
|
resolveConfigId(storageConfigId) {
|
|
238
579
|
return storageConfigId ?? this.getDefaultConfigId();
|
|
239
580
|
}
|
|
581
|
+
toCreateFileDto(fileInfo, options) {
|
|
582
|
+
return {
|
|
583
|
+
name: fileInfo.name,
|
|
584
|
+
key: fileInfo.key,
|
|
585
|
+
size: String(fileInfo.size),
|
|
586
|
+
contentType: fileInfo.contentType,
|
|
587
|
+
isPrivate: options?.isPrivate ?? false,
|
|
588
|
+
folderId: options?.folderId,
|
|
589
|
+
storageConfigId: this.resolveConfigId(options?.storageConfigId),
|
|
590
|
+
};
|
|
591
|
+
}
|
|
240
592
|
buildUploadUrl(endpoint, options) {
|
|
241
593
|
const params = this.buildQueryParams(options);
|
|
242
594
|
const baseUrl = this.getUrl(`upload/${endpoint}`);
|
|
@@ -265,58 +617,80 @@ class UploadService extends BaseApiService {
|
|
|
265
617
|
const configId = this.resolveConfigId(storageConfigId);
|
|
266
618
|
return { ...data, ...(configId && { storageConfigId: configId }) };
|
|
267
619
|
}
|
|
268
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
269
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
620
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: UploadService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
621
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: UploadService, providedIn: 'root' });
|
|
270
622
|
}
|
|
271
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
623
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: UploadService, decorators: [{
|
|
272
624
|
type: Injectable,
|
|
273
625
|
args: [{ providedIn: 'root' }]
|
|
274
626
|
}], ctorParameters: () => [] });
|
|
275
627
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
*
|
|
279
|
-
* Implements IProfileUploadProvider interface for ng-auth profile page.
|
|
280
|
-
* Uses UploadService.uploadAndRegister() to upload files and register in file manager.
|
|
281
|
-
*
|
|
282
|
-
* @example
|
|
283
|
-
* // In app.config.ts
|
|
284
|
-
* providers: [
|
|
285
|
-
* ...provideStorageProviders(),
|
|
286
|
-
* ]
|
|
287
|
-
*/
|
|
288
|
-
class ProfileUploadProviderAdapter {
|
|
628
|
+
class FileProviderAdapter {
|
|
629
|
+
fileManagerApi = inject(FileManagerApiService);
|
|
289
630
|
uploadService = inject(UploadService);
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
631
|
+
folderApi = inject(FolderApiService);
|
|
632
|
+
storageConfigApi = inject(StorageConfigApiService);
|
|
633
|
+
loadFiles(filter) {
|
|
634
|
+
const filterObj = this.buildFileFilter(filter);
|
|
635
|
+
return from(this.fileManagerApi
|
|
636
|
+
.getAll({ pagination: { currentPage: filter.page, pageSize: filter.pageSize }, filter: Object.keys(filterObj).length > 0 ? filterObj : undefined }, filter.search || ''))
|
|
637
|
+
.pipe(map((res) => ({ ...res, data: res.data?.map(this.mapToFileBasicInfo) })));
|
|
638
|
+
}
|
|
639
|
+
uploadFile(file, options) {
|
|
640
|
+
return this.uploadService
|
|
641
|
+
.uploadAndRegister(file, options)
|
|
642
|
+
.pipe(map((res) => ({ ...res, data: res.data ? this.mapToUploadedFile(res.data) : undefined })));
|
|
643
|
+
}
|
|
644
|
+
uploadMultipleFiles(files, options) {
|
|
295
645
|
return this.uploadService
|
|
296
|
-
.
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
.
|
|
303
|
-
success: response.success,
|
|
304
|
-
message: response.message,
|
|
305
|
-
data: response.data
|
|
306
|
-
? {
|
|
307
|
-
id: response.data.id,
|
|
308
|
-
name: response.data.name,
|
|
309
|
-
key: response.data.key,
|
|
310
|
-
size: parseFloat(response.data.size) * 1024, // Convert KB to bytes
|
|
311
|
-
contentType: response.data.contentType,
|
|
312
|
-
}
|
|
313
|
-
: undefined,
|
|
646
|
+
.uploadAndRegisterMultiple(files, options)
|
|
647
|
+
.pipe(map((res) => ({ ...res, data: res.data?.map(this.mapToUploadedFile) })));
|
|
648
|
+
}
|
|
649
|
+
getFileUrls(fileIds) {
|
|
650
|
+
return this.fileManagerApi.getFiles(fileIds).pipe(map((res) => ({
|
|
651
|
+
...res,
|
|
652
|
+
data: res.data?.map((f) => ({ id: f.id, name: f.name, contentType: f.contentType, size: '0', url: f.url })),
|
|
314
653
|
})));
|
|
315
654
|
}
|
|
316
|
-
|
|
317
|
-
|
|
655
|
+
loadFolders(filter) {
|
|
656
|
+
return from(this.folderApi
|
|
657
|
+
.getAll({ pagination: { currentPage: filter.page, pageSize: filter.pageSize } }, filter.search || ''))
|
|
658
|
+
.pipe(map((res) => ({ ...res, data: res.data?.map((f) => ({ id: f.id, name: f.name, slug: f.slug })) })));
|
|
659
|
+
}
|
|
660
|
+
loadStorageConfigs(filter) {
|
|
661
|
+
return from(this.storageConfigApi
|
|
662
|
+
.getAll({ pagination: { currentPage: filter.page, pageSize: filter.pageSize } }, filter.search || ''))
|
|
663
|
+
.pipe(map((res) => ({ ...res, data: res.data?.map((c) => ({ id: c.id, name: c.name, isDefault: c.isDefault })) })));
|
|
664
|
+
}
|
|
665
|
+
// ─── Private Helpers ────────────────────────────────────────────────────────
|
|
666
|
+
buildFileFilter(filter) {
|
|
667
|
+
const filterObj = {};
|
|
668
|
+
if (filter.folderId)
|
|
669
|
+
filterObj['folderId'] = filter.folderId;
|
|
670
|
+
if (filter.storageConfigId)
|
|
671
|
+
filterObj['storageConfigId'] = filter.storageConfigId;
|
|
672
|
+
if (filter.contentTypes?.length)
|
|
673
|
+
filterObj['contentType'] = filter.contentTypes.join(',');
|
|
674
|
+
return filterObj;
|
|
675
|
+
}
|
|
676
|
+
mapToFileBasicInfo = (f) => ({
|
|
677
|
+
id: f.id,
|
|
678
|
+
name: f.name,
|
|
679
|
+
contentType: f.contentType,
|
|
680
|
+
size: f.size,
|
|
681
|
+
url: f.url,
|
|
682
|
+
});
|
|
683
|
+
mapToUploadedFile = (f) => ({
|
|
684
|
+
id: f.id,
|
|
685
|
+
name: f.name,
|
|
686
|
+
key: f.key,
|
|
687
|
+
size: parseFloat(f.size) * 1024,
|
|
688
|
+
contentType: f.contentType,
|
|
689
|
+
});
|
|
690
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: FileProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
691
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: FileProviderAdapter });
|
|
318
692
|
}
|
|
319
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
693
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: FileProviderAdapter, decorators: [{
|
|
320
694
|
type: Injectable
|
|
321
695
|
}] });
|
|
322
696
|
|
|
@@ -339,54 +713,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
339
713
|
function provideStorageProviders() {
|
|
340
714
|
return [
|
|
341
715
|
{
|
|
342
|
-
provide:
|
|
343
|
-
useClass:
|
|
716
|
+
provide: FILE_PROVIDER,
|
|
717
|
+
useClass: FileProviderAdapter,
|
|
344
718
|
},
|
|
345
719
|
];
|
|
346
720
|
}
|
|
347
721
|
|
|
348
|
-
/**
|
|
349
|
-
* Folder API Service
|
|
350
|
-
* Handles folder CRUD operations
|
|
351
|
-
* Endpoint: POST /storage/folder/*
|
|
352
|
-
*
|
|
353
|
-
* Note: Company feature enabled - all queries automatically scoped to user's company
|
|
354
|
-
*/
|
|
355
|
-
class FolderApiService extends ApiResourceService {
|
|
356
|
-
constructor() {
|
|
357
|
-
super('folder', inject(HttpClient), 'storage');
|
|
358
|
-
}
|
|
359
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FolderApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
360
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FolderApiService, providedIn: 'root' });
|
|
361
|
-
}
|
|
362
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: FolderApiService, decorators: [{
|
|
363
|
-
type: Injectable,
|
|
364
|
-
args: [{
|
|
365
|
-
providedIn: 'root',
|
|
366
|
-
}]
|
|
367
|
-
}], ctorParameters: () => [] });
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Storage Config API Service
|
|
371
|
-
* Handles storage configuration CRUD operations
|
|
372
|
-
* Endpoint: POST /storage/storage-config/*
|
|
373
|
-
*
|
|
374
|
-
* Note: Company feature enabled - all queries automatically scoped to user's company
|
|
375
|
-
*/
|
|
376
|
-
class StorageConfigApiService extends ApiResourceService {
|
|
377
|
-
constructor() {
|
|
378
|
-
super('storage-config', inject(HttpClient), 'storage');
|
|
379
|
-
}
|
|
380
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: StorageConfigApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
381
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: StorageConfigApiService, providedIn: 'root' });
|
|
382
|
-
}
|
|
383
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: StorageConfigApiService, decorators: [{
|
|
384
|
-
type: Injectable,
|
|
385
|
-
args: [{
|
|
386
|
-
providedIn: 'root',
|
|
387
|
-
}]
|
|
388
|
-
}], ctorParameters: () => [] });
|
|
389
|
-
|
|
390
722
|
/**
|
|
391
723
|
* Storage Module Routes
|
|
392
724
|
* All routes protected by permission guards
|
|
@@ -394,6 +726,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
394
726
|
const STORAGE_ROUTES = [
|
|
395
727
|
{
|
|
396
728
|
path: '',
|
|
729
|
+
resolve: { translations: resolveTranslationModule({ modules: ['storage'], fallbackMessages: { ...STORAGE_MESSAGES, ...SHARED_MESSAGES } }) },
|
|
397
730
|
loadComponent: () => Promise.resolve().then(function () { return storageContainer_component; }).then((m) => m.StorageContainerComponent),
|
|
398
731
|
children: [
|
|
399
732
|
// File Manager Routes
|
|
@@ -403,17 +736,17 @@ const STORAGE_ROUTES = [
|
|
|
403
736
|
children: [
|
|
404
737
|
{
|
|
405
738
|
path: '',
|
|
406
|
-
loadComponent: () => import('./flusys-ng-storage-file-manager-list.component-
|
|
739
|
+
loadComponent: () => import('./flusys-ng-storage-file-manager-list.component-nZDj1UfS.mjs').then((m) => m.FileManagerListComponent),
|
|
407
740
|
},
|
|
408
741
|
{
|
|
409
742
|
path: 'new',
|
|
410
743
|
canActivate: [permissionGuard(FILE_PERMISSIONS.CREATE)],
|
|
411
|
-
loadComponent: () => import('./flusys-ng-storage-file-manager-form.component-
|
|
744
|
+
loadComponent: () => import('./flusys-ng-storage-file-manager-form.component-DhqZmpuX.mjs').then((m) => m.FileManagerFormComponent),
|
|
412
745
|
},
|
|
413
746
|
{
|
|
414
747
|
path: ':id',
|
|
415
748
|
canActivate: [permissionGuard(FILE_PERMISSIONS.UPDATE)],
|
|
416
|
-
loadComponent: () => import('./flusys-ng-storage-file-manager-form.component-
|
|
749
|
+
loadComponent: () => import('./flusys-ng-storage-file-manager-form.component-DhqZmpuX.mjs').then((m) => m.FileManagerFormComponent),
|
|
417
750
|
},
|
|
418
751
|
],
|
|
419
752
|
},
|
|
@@ -424,17 +757,17 @@ const STORAGE_ROUTES = [
|
|
|
424
757
|
children: [
|
|
425
758
|
{
|
|
426
759
|
path: '',
|
|
427
|
-
loadComponent: () => import('./flusys-ng-storage-folder-list.component-
|
|
760
|
+
loadComponent: () => import('./flusys-ng-storage-folder-list.component-fuJMWYWZ.mjs').then((m) => m.FolderListComponent),
|
|
428
761
|
},
|
|
429
762
|
{
|
|
430
763
|
path: 'new',
|
|
431
764
|
canActivate: [permissionGuard(FOLDER_PERMISSIONS.CREATE)],
|
|
432
|
-
loadComponent: () => import('./flusys-ng-storage-folder-form.component-
|
|
765
|
+
loadComponent: () => import('./flusys-ng-storage-folder-form.component-Bru9NQyr.mjs').then((m) => m.FolderFormComponent),
|
|
433
766
|
},
|
|
434
767
|
{
|
|
435
768
|
path: ':id',
|
|
436
769
|
canActivate: [permissionGuard(FOLDER_PERMISSIONS.UPDATE)],
|
|
437
|
-
loadComponent: () => import('./flusys-ng-storage-folder-form.component-
|
|
770
|
+
loadComponent: () => import('./flusys-ng-storage-folder-form.component-Bru9NQyr.mjs').then((m) => m.FolderFormComponent),
|
|
438
771
|
},
|
|
439
772
|
],
|
|
440
773
|
},
|
|
@@ -445,17 +778,17 @@ const STORAGE_ROUTES = [
|
|
|
445
778
|
children: [
|
|
446
779
|
{
|
|
447
780
|
path: '',
|
|
448
|
-
loadComponent: () => import('./flusys-ng-storage-storage-config-list.component-
|
|
781
|
+
loadComponent: () => import('./flusys-ng-storage-storage-config-list.component-D59X4sae.mjs').then((m) => m.StorageConfigListComponent),
|
|
449
782
|
},
|
|
450
783
|
{
|
|
451
784
|
path: 'new',
|
|
452
785
|
canActivate: [permissionGuard(STORAGE_CONFIG_PERMISSIONS.CREATE)],
|
|
453
|
-
loadComponent: () => import('./flusys-ng-storage-storage-config-form.component-
|
|
786
|
+
loadComponent: () => import('./flusys-ng-storage-storage-config-form.component-Da-pWR7d.mjs').then((m) => m.StorageConfigFormComponent),
|
|
454
787
|
},
|
|
455
788
|
{
|
|
456
789
|
path: ':id',
|
|
457
790
|
canActivate: [permissionGuard(STORAGE_CONFIG_PERMISSIONS.UPDATE)],
|
|
458
|
-
loadComponent: () => import('./flusys-ng-storage-storage-config-form.component-
|
|
791
|
+
loadComponent: () => import('./flusys-ng-storage-storage-config-form.component-Da-pWR7d.mjs').then((m) => m.StorageConfigFormComponent),
|
|
459
792
|
},
|
|
460
793
|
],
|
|
461
794
|
},
|
|
@@ -474,89 +807,73 @@ const STORAGE_ROUTES = [
|
|
|
474
807
|
*/
|
|
475
808
|
class StorageContainerComponent {
|
|
476
809
|
permissionValidator = inject(PermissionValidatorService);
|
|
810
|
+
translateService = inject(TranslateService);
|
|
477
811
|
/** All available tabs with required permissions */
|
|
478
812
|
allTabs = [
|
|
479
813
|
{
|
|
480
814
|
id: 'files',
|
|
481
|
-
|
|
482
|
-
icon: '
|
|
815
|
+
labelKey: 'storage.file.title',
|
|
816
|
+
icon: 'file',
|
|
483
817
|
route: 'files',
|
|
484
818
|
permission: FILE_PERMISSIONS.READ,
|
|
485
819
|
},
|
|
486
820
|
{
|
|
487
821
|
id: 'folders',
|
|
488
|
-
|
|
489
|
-
icon: '
|
|
822
|
+
labelKey: 'storage.folder.title',
|
|
823
|
+
icon: 'folder',
|
|
490
824
|
route: 'folders',
|
|
491
825
|
permission: FOLDER_PERMISSIONS.READ,
|
|
492
826
|
},
|
|
493
827
|
{
|
|
494
828
|
id: 'configs',
|
|
495
|
-
|
|
496
|
-
icon: '
|
|
829
|
+
labelKey: 'storage.config.title',
|
|
830
|
+
icon: 'cog',
|
|
497
831
|
route: 'configs',
|
|
498
832
|
permission: STORAGE_CONFIG_PERMISSIONS.READ,
|
|
499
833
|
},
|
|
500
834
|
];
|
|
501
835
|
/** Visible tabs based on user permissions */
|
|
502
|
-
visibleTabs = computed(() => this.allTabs
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
},
|
|
510
|
-
|
|
511
|
-
static
|
|
836
|
+
visibleTabs = computed(() => this.allTabs
|
|
837
|
+
.filter((tab) => this.permissionValidator.hasPermission(tab.permission))
|
|
838
|
+
.map((tab) => ({
|
|
839
|
+
id: tab.id,
|
|
840
|
+
label: this.translateService.translate(tab.labelKey),
|
|
841
|
+
icon: tab.icon,
|
|
842
|
+
route: tab.route,
|
|
843
|
+
})), /* @ts-ignore */
|
|
844
|
+
...(ngDevMode ? [{ debugName: "visibleTabs" }] : /* istanbul ignore next */ []));
|
|
845
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: StorageContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
846
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.6", type: StorageContainerComponent, isStandalone: true, selector: "lib-storage-container", ngImport: i0, template: `
|
|
512
847
|
<div class="p-2 sm:p-4">
|
|
513
848
|
<div class="mb-4">
|
|
514
|
-
<h1 class="text-xl sm:text-2xl font-bold m-0">
|
|
515
|
-
<p class="text-muted-color mt-1 text-sm sm:text-base">{{ subtitle
|
|
849
|
+
<h1 class="text-xl sm:text-2xl font-bold m-0">{{ 'storage.title' | translate }}</h1>
|
|
850
|
+
<p class="text-muted-color mt-1 text-sm sm:text-base">{{ 'storage.subtitle' | translate }}</p>
|
|
516
851
|
</div>
|
|
517
852
|
|
|
518
|
-
<
|
|
519
|
-
@for (tab of visibleTabs(); track tab.id) {
|
|
520
|
-
<a
|
|
521
|
-
[routerLink]="tab.route"
|
|
522
|
-
routerLinkActive="tab-active"
|
|
523
|
-
class="flex items-center gap-2 px-4 py-2 rounded-t-lg cursor-pointer transition-colors text-muted-color no-underline border-b-2 border-transparent -mb-px hover:bg-surface-hover [&.tab-active]:text-primary [&.tab-active]:border-primary [&.tab-active]:bg-surface-ground whitespace-nowrap shrink-0"
|
|
524
|
-
>
|
|
525
|
-
<i [class]="tab.icon"></i>
|
|
526
|
-
<span>{{ tab.label }}</span>
|
|
527
|
-
</a>
|
|
528
|
-
}
|
|
529
|
-
</div>
|
|
853
|
+
<lib-router-tabs [tabs]="visibleTabs()" class="mb-4" />
|
|
530
854
|
|
|
531
855
|
<router-outlet />
|
|
532
856
|
</div>
|
|
533
|
-
`, isInline: true,
|
|
857
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: RouterTabsComponent, selector: "lib-router-tabs", inputs: ["tabs"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
534
858
|
}
|
|
535
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
859
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: StorageContainerComponent, decorators: [{
|
|
536
860
|
type: Component,
|
|
537
|
-
args: [{
|
|
861
|
+
args: [{
|
|
862
|
+
selector: 'lib-storage-container',
|
|
863
|
+
imports: [RouterOutlet, TranslatePipe, RouterTabsComponent],
|
|
864
|
+
template: `
|
|
538
865
|
<div class="p-2 sm:p-4">
|
|
539
866
|
<div class="mb-4">
|
|
540
|
-
<h1 class="text-xl sm:text-2xl font-bold m-0">
|
|
541
|
-
<p class="text-muted-color mt-1 text-sm sm:text-base">{{ subtitle
|
|
867
|
+
<h1 class="text-xl sm:text-2xl font-bold m-0">{{ 'storage.title' | translate }}</h1>
|
|
868
|
+
<p class="text-muted-color mt-1 text-sm sm:text-base">{{ 'storage.subtitle' | translate }}</p>
|
|
542
869
|
</div>
|
|
543
870
|
|
|
544
|
-
<
|
|
545
|
-
@for (tab of visibleTabs(); track tab.id) {
|
|
546
|
-
<a
|
|
547
|
-
[routerLink]="tab.route"
|
|
548
|
-
routerLinkActive="tab-active"
|
|
549
|
-
class="flex items-center gap-2 px-4 py-2 rounded-t-lg cursor-pointer transition-colors text-muted-color no-underline border-b-2 border-transparent -mb-px hover:bg-surface-hover [&.tab-active]:text-primary [&.tab-active]:border-primary [&.tab-active]:bg-surface-ground whitespace-nowrap shrink-0"
|
|
550
|
-
>
|
|
551
|
-
<i [class]="tab.icon"></i>
|
|
552
|
-
<span>{{ tab.label }}</span>
|
|
553
|
-
</a>
|
|
554
|
-
}
|
|
555
|
-
</div>
|
|
871
|
+
<lib-router-tabs [tabs]="visibleTabs()" class="mb-4" />
|
|
556
872
|
|
|
557
873
|
<router-outlet />
|
|
558
874
|
</div>
|
|
559
|
-
`,
|
|
875
|
+
`,
|
|
876
|
+
}]
|
|
560
877
|
}] });
|
|
561
878
|
|
|
562
879
|
var storageContainer_component = /*#__PURE__*/Object.freeze({
|
|
@@ -567,11 +884,11 @@ var storageContainer_component = /*#__PURE__*/Object.freeze({
|
|
|
567
884
|
// =============================================================================
|
|
568
885
|
// @flusys/ng-storage - Storage Package
|
|
569
886
|
// =============================================================================
|
|
570
|
-
//
|
|
887
|
+
// Constants
|
|
571
888
|
|
|
572
889
|
/**
|
|
573
890
|
* Generated bundle index. Do not edit.
|
|
574
891
|
*/
|
|
575
892
|
|
|
576
|
-
export { BaseStorageListPage, BaseStoragePage, FileLocationEnum, FileManagerApiService, FolderApiService, ImageFormat,
|
|
893
|
+
export { BaseStorageListPage, BaseStoragePage, FILE_SIZE_UNIT_KEYS, FileLocationEnum, FileManagerApiService, FileProviderAdapter, FolderApiService, ImageFormat, PROVIDER_LABEL_KEYS, STORAGE_MESSAGES, STORAGE_PROVIDER_OPTIONS, STORAGE_ROUTES, StorageConfigApiService, StorageContainerComponent, UploadService, formatFileSize, formatFileSizeWithKey, getFileIcon, getProviderIcon, getProviderLabelKey, getProviderSeverity, provideStorageProviders };
|
|
577
894
|
//# sourceMappingURL=flusys-ng-storage.mjs.map
|