@flusys/ng-storage 9.1.2 → 9.2.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.
@@ -26,6 +26,7 @@ var FileManagerListComponent = class FileManagerListComponent extends BaseStorag
26
26
  return this.translateService.translate("shared.confirm.delete.item", { name: file.name });
27
27
  }
28
28
  async loadData() {
29
+ const token = this.beginLoad();
29
30
  this.isLoading.set(true);
30
31
  try {
31
32
  const response = await this.fileService.getAll({
@@ -34,12 +35,13 @@ var FileManagerListComponent = class FileManagerListComponent extends BaseStorag
34
35
  select: [],
35
36
  sort: {}
36
37
  }, this.searchTerm());
38
+ if (!this.isLatestLoad(token)) return;
37
39
  if (response.success) {
38
40
  this.items.set(response.data ?? []);
39
41
  this.total.set(response.meta?.total ?? 0);
40
42
  }
41
43
  } finally {
42
- this.isLoading.set(false);
44
+ if (this.isLatestLoad(token)) this.isLoading.set(false);
43
45
  }
44
46
  }
45
47
  onSearchChange(term) {
@@ -725,4 +727,4 @@ i0.ɵɵngDeclareClassMetadata({
725
727
  });
726
728
  export { FileManagerListComponent };
727
729
 
728
- //# sourceMappingURL=flusys-ng-storage-file-manager-list.component-4_LdJOtH.mjs.map
730
+ //# sourceMappingURL=flusys-ng-storage-file-manager-list.component-BjlsjxSH.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"flusys-ng-storage-file-manager-list.component-4_LdJOtH.mjs","names":[],"sources":["../../../projects/ng-storage/pages/file-manager/file-manager-list.component.ts"],"sourcesContent":["import { Component, inject, signal } from '@angular/core';\nimport { DatePipe } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport {\n FILE_PERMISSIONS,\n HasPermissionDirective,\n TranslatePipe,\n TranslateService,\n} from '@flusys/ng-shared';\nimport {\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TableComponent,\n TagComponent,\n TooltipDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\nimport { firstValueFrom } from 'rxjs';\nimport { IFileManager } from '../../interfaces/file-manager.interface';\nimport { FileManagerApiService } from '../../services/file-manager-api.service';\nimport { BaseStorageListPage } from '../../utils/base-storage-page';\n\nimport {\n getFileIcon,\n getProviderLabelKey,\n getProviderSeverity,\n} from '../../utils/storage-utils';\n\n@Component({\n selector: 'lib-file-manager-list',\n imports: [\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TableComponent,\n TagComponent,\n TooltipDirective,\n UiIconComponent,\n DatePipe,\n FormsModule,\n HasPermissionDirective,\n TranslatePipe,\n ],\n template: `\n <div class=\"card\">\n <div\n class=\"flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 mb-4\"\n >\n <div>\n <h3 class=\"text-lg sm:text-xl font-semibold\">\n {{ 'storage.file.manager.title' | translate }}\n </h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">\n {{ 'shared.company' | translate }}: {{ currentCompanyName() }}\n </p>\n }\n </div>\n <div\n class=\"flex flex-col sm:flex-row items-stretch sm:items-center gap-2 w-full sm:w-auto\"\n >\n <f-iconfield class=\"w-full sm:w-64\">\n <f-inputicon icon=\"search\" />\n <input\n fInputText\n type=\"text\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onSearchChange($event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [placeholder]=\"'shared.search' | translate\"\n class=\"w-full\"\n />\n </f-iconfield>\n <button\n fButton\n *hasPermission=\"FILE_PERMISSIONS.CREATE\"\n (click)=\"onUpload()\"\n class=\"w-full sm:w-auto\"\n >\n <ui-icon pButtonIcon name=\"upload\"></ui-icon>\n <span pButtonLabel>{{ 'storage.button.upload.file' | translate }}</span>\n </button>\n </div>\n </div>\n\n <div class=\"overflow-x-auto\">\n <f-table\n [value]=\"files()\"\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 >\n <ng-template #header>\n <tr>\n <th>{{ 'shared.name' | translate }}</th>\n <th class=\"hidden lg:table-cell\">\n {{ 'shared.type' | translate }}\n </th>\n <th>{{ 'storage.table.size' | translate }}</th>\n <th>{{ 'storage.table.location' | translate }}</th>\n <th class=\"hidden xl:table-cell\">\n {{ 'storage.table.config' | translate }}\n </th>\n <th>{{ 'storage.table.private' | translate }}</th>\n <th class=\"hidden md:table-cell\">\n {{ 'storage.table.created' | translate }}\n </th>\n <th class=\"w-[120px]\">{{ 'shared.actions' | translate }}</th>\n </tr>\n </ng-template>\n <ng-template #body let-file>\n @let isViewing = viewingFileId() === file.id;\n <tr>\n <td>\n <div class=\"flex items-center gap-2\">\n <ui-icon [name]=\"getFileIcon(file.contentType)\"></ui-icon>\n <span class=\"truncate max-w-32 sm:max-w-none\">{{\n file.name\n }}</span>\n </div>\n </td>\n <td class=\"hidden lg:table-cell\">\n <span class=\"text-sm text-muted-color\">{{\n file.contentType\n }}</span>\n </td>\n <td>{{ file.size }} {{ 'shared.size.kb' | translate }}</td>\n <td>\n <f-tag\n [value]=\"getProviderLabelKey(file.location) | translate\"\n [severity]=\"getProviderSeverity(file.location)\"\n />\n </td>\n <td class=\"hidden xl:table-cell\">\n {{ file.providerName || '-' }}\n </td>\n <td>\n @if (file.isPrivate) {\n <f-tag\n [value]=\"'storage.private' | translate\"\n severity=\"warn\"\n />\n } @else {\n <f-tag\n [value]=\"'storage.public' | translate\"\n severity=\"success\"\n />\n }\n </td>\n <td class=\"hidden md:table-cell\">\n {{ file.createdAt | date: 'short' }}\n </td>\n <td>\n <div class=\"flex gap-1\">\n <button\n fButton\n *hasPermission=\"FILE_PERMISSIONS.READ\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n [disabled]=\"isViewing\"\n (click)=\"onView(file)\"\n [fTooltip]=\"'shared.view' | translate\"\n tooltipPosition=\"top\"\n >\n @if (isViewing) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n } @else {\n <ui-icon pButtonIcon name=\"eye\"></ui-icon>\n }\n </button>\n <button\n fButton\n *hasPermission=\"FILE_PERMISSIONS.UPDATE\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n (click)=\"onEdit(file.id)\"\n [fTooltip]=\"'shared.edit' | translate\"\n tooltipPosition=\"top\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n <button\n fButton\n *hasPermission=\"FILE_PERMISSIONS.DELETE\"\n [text]=\"true\"\n severity=\"warn\"\n size=\"small\"\n (click)=\"onSoftDelete(file)\"\n [fTooltip]=\"'storage.tooltip.trash' | translate\"\n tooltipPosition=\"top\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\n <button\n fButton\n *hasPermission=\"FILE_PERMISSIONS.DELETE\"\n [text]=\"true\"\n severity=\"danger\"\n size=\"small\"\n (click)=\"onPermanentDelete(file)\"\n [fTooltip]=\"'shared.delete' | translate\"\n tooltipPosition=\"top\"\n >\n <ui-icon pButtonIcon name=\"times-circle\"></ui-icon>\n </button>\n </div>\n </td>\n </tr>\n </ng-template>\n <ng-template #emptymessage>\n <tr>\n <td colspan=\"8\" class=\"text-center py-4 text-muted-color\">\n @if (showCompanyInfo()) {\n {{ 'storage.empty.files.in.company' | translate }}\n } @else {\n {{ 'storage.empty.files' | translate }}\n }\n </td>\n </tr>\n </ng-template>\n </f-table>\n </div>\n </div>\n `,\n})\nexport class FileManagerListComponent extends BaseStorageListPage<IFileManager> {\n readonly FILE_PERMISSIONS = FILE_PERMISSIONS;\n\n private readonly fileService = inject(FileManagerApiService);\n private readonly translateService = inject(TranslateService);\n\n readonly files = this.items;\n readonly viewingFileId = signal<string | null>(null);\n\n private readonly _searchTerm = signal('');\n readonly searchTerm = this._searchTerm.asReadonly();\n\n readonly getFileIcon = getFileIcon;\n readonly getProviderLabelKey = getProviderLabelKey;\n readonly getProviderSeverity = getProviderSeverity;\n\n getResourceRoute(): string {\n return '/storage/files';\n }\n\n override getDeleteConfirmMessage(file: IFileManager): string {\n return this.translateService.translate('shared.confirm.delete.item', {\n name: file.name,\n });\n }\n\n async loadData(): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await this.fileService.getAll(\n {\n pagination: this.getPaginationParams(),\n filter: {},\n select: [],\n sort: {},\n },\n this.searchTerm(),\n );\n\n if (response.success) {\n this.items.set(response.data ?? []);\n this.total.set(response.meta?.total ?? 0);\n }\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onSearchChange(term: string): void {\n this._searchTerm.set(term);\n this.first.set(0);\n this.loadData();\n }\n\n onUpload(): void {\n this.navigateTo(['/storage/files/new']);\n }\n\n async onView(file: IFileManager): Promise<void> {\n this.viewingFileId.set(file.id);\n try {\n const response = await firstValueFrom(\n this.fileService.getFiles([file.id]),\n );\n\n if (response.success && response.data?.length && response.data[0].url) {\n window.open(response.data[0].url, '_blank');\n } else {\n this.showError(\n this.translateService.translate('storage.file.url.not.available'),\n );\n }\n } finally {\n this.viewingFileId.set(null);\n }\n }\n\n onSoftDelete(file: IFileManager): void {\n this.confirmationService.confirm({\n message: this.translateService.translate(\n 'storage.delete.move.to.trash.confirm',\n { name: file.name },\n ),\n header: this.translateService.translate('storage.delete.move.to.trash'),\n icon: 'trash',\n acceptLabel: this.translateService.translate(\n 'storage.delete.move.to.trash',\n ),\n acceptButtonStyleClass: 'p-button-warning',\n accept: async () => {\n try {\n const response = await this.fileService.delete({\n id: file.id,\n type: 'delete',\n });\n this.showSuccess(\n response?.messageKey\n ? this.translateService.translate(\n response.messageKey,\n response.messageVariables as Record<string, string | number>,\n )\n : (response?.message ?? ''),\n );\n this.loadData();\n } catch {}\n },\n });\n }\n\n onPermanentDelete(file: IFileManager): void {\n this.confirmationService.confirm({\n message: this.translateService.translate(\n 'storage.delete.permanent.delete.confirm',\n { name: file.name },\n ),\n header: this.translateService.translate(\n 'storage.delete.permanent.delete',\n ),\n icon: 'exclamation-triangle',\n acceptLabel: this.translateService.translate(\n 'storage.delete.permanent.delete.button',\n ),\n rejectLabel: this.translateService.translate('shared.cancel'),\n acceptButtonStyleClass: 'p-button-danger',\n accept: async () => {\n try {\n const response = await this.fileService.delete({\n id: file.id,\n type: 'permanent',\n });\n this.showSuccess(\n response?.messageKey\n ? this.translateService.translate(\n response.messageKey,\n response.messageVariables as Record<string, string | number>,\n )\n : (response?.message ?? ''),\n );\n this.loadData();\n } catch {}\n },\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"flusys-ng-storage-file-manager-list.component-BjlsjxSH.mjs","names":[],"sources":["../../../projects/ng-storage/pages/file-manager/file-manager-list.component.ts"],"sourcesContent":["import { Component, inject, signal } from '@angular/core';\nimport { DatePipe } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport {\n FILE_PERMISSIONS,\n HasPermissionDirective,\n TranslatePipe,\n TranslateService,\n} from '@flusys/ng-shared';\nimport {\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TableComponent,\n TagComponent,\n TooltipDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\nimport { firstValueFrom } from 'rxjs';\nimport { IFileManager } from '../../interfaces/file-manager.interface';\nimport { FileManagerApiService } from '../../services/file-manager-api.service';\nimport { BaseStorageListPage } from '../../utils/base-storage-page';\n\nimport {\n getFileIcon,\n getProviderLabelKey,\n getProviderSeverity,\n} from '../../utils/storage-utils';\n\n@Component({\n selector: 'lib-file-manager-list',\n imports: [\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TableComponent,\n TagComponent,\n TooltipDirective,\n UiIconComponent,\n DatePipe,\n FormsModule,\n HasPermissionDirective,\n TranslatePipe,\n ],\n template: `\n <div class=\"card\">\n <div\n class=\"flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 mb-4\"\n >\n <div>\n <h3 class=\"text-lg sm:text-xl font-semibold\">\n {{ 'storage.file.manager.title' | translate }}\n </h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">\n {{ 'shared.company' | translate }}: {{ currentCompanyName() }}\n </p>\n }\n </div>\n <div\n class=\"flex flex-col sm:flex-row items-stretch sm:items-center gap-2 w-full sm:w-auto\"\n >\n <f-iconfield class=\"w-full sm:w-64\">\n <f-inputicon icon=\"search\" />\n <input\n fInputText\n type=\"text\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onSearchChange($event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [placeholder]=\"'shared.search' | translate\"\n class=\"w-full\"\n />\n </f-iconfield>\n <button\n fButton\n *hasPermission=\"FILE_PERMISSIONS.CREATE\"\n (click)=\"onUpload()\"\n class=\"w-full sm:w-auto\"\n >\n <ui-icon pButtonIcon name=\"upload\"></ui-icon>\n <span pButtonLabel>{{ 'storage.button.upload.file' | translate }}</span>\n </button>\n </div>\n </div>\n\n <div class=\"overflow-x-auto\">\n <f-table\n [value]=\"files()\"\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 >\n <ng-template #header>\n <tr>\n <th>{{ 'shared.name' | translate }}</th>\n <th class=\"hidden lg:table-cell\">\n {{ 'shared.type' | translate }}\n </th>\n <th>{{ 'storage.table.size' | translate }}</th>\n <th>{{ 'storage.table.location' | translate }}</th>\n <th class=\"hidden xl:table-cell\">\n {{ 'storage.table.config' | translate }}\n </th>\n <th>{{ 'storage.table.private' | translate }}</th>\n <th class=\"hidden md:table-cell\">\n {{ 'storage.table.created' | translate }}\n </th>\n <th class=\"w-[120px]\">{{ 'shared.actions' | translate }}</th>\n </tr>\n </ng-template>\n <ng-template #body let-file>\n @let isViewing = viewingFileId() === file.id;\n <tr>\n <td>\n <div class=\"flex items-center gap-2\">\n <ui-icon [name]=\"getFileIcon(file.contentType)\"></ui-icon>\n <span class=\"truncate max-w-32 sm:max-w-none\">{{\n file.name\n }}</span>\n </div>\n </td>\n <td class=\"hidden lg:table-cell\">\n <span class=\"text-sm text-muted-color\">{{\n file.contentType\n }}</span>\n </td>\n <td>{{ file.size }} {{ 'shared.size.kb' | translate }}</td>\n <td>\n <f-tag\n [value]=\"getProviderLabelKey(file.location) | translate\"\n [severity]=\"getProviderSeverity(file.location)\"\n />\n </td>\n <td class=\"hidden xl:table-cell\">\n {{ file.providerName || '-' }}\n </td>\n <td>\n @if (file.isPrivate) {\n <f-tag\n [value]=\"'storage.private' | translate\"\n severity=\"warn\"\n />\n } @else {\n <f-tag\n [value]=\"'storage.public' | translate\"\n severity=\"success\"\n />\n }\n </td>\n <td class=\"hidden md:table-cell\">\n {{ file.createdAt | date: 'short' }}\n </td>\n <td>\n <div class=\"flex gap-1\">\n <button\n fButton\n *hasPermission=\"FILE_PERMISSIONS.READ\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n [disabled]=\"isViewing\"\n (click)=\"onView(file)\"\n [fTooltip]=\"'shared.view' | translate\"\n tooltipPosition=\"top\"\n >\n @if (isViewing) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n } @else {\n <ui-icon pButtonIcon name=\"eye\"></ui-icon>\n }\n </button>\n <button\n fButton\n *hasPermission=\"FILE_PERMISSIONS.UPDATE\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n (click)=\"onEdit(file.id)\"\n [fTooltip]=\"'shared.edit' | translate\"\n tooltipPosition=\"top\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n <button\n fButton\n *hasPermission=\"FILE_PERMISSIONS.DELETE\"\n [text]=\"true\"\n severity=\"warn\"\n size=\"small\"\n (click)=\"onSoftDelete(file)\"\n [fTooltip]=\"'storage.tooltip.trash' | translate\"\n tooltipPosition=\"top\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\n <button\n fButton\n *hasPermission=\"FILE_PERMISSIONS.DELETE\"\n [text]=\"true\"\n severity=\"danger\"\n size=\"small\"\n (click)=\"onPermanentDelete(file)\"\n [fTooltip]=\"'shared.delete' | translate\"\n tooltipPosition=\"top\"\n >\n <ui-icon pButtonIcon name=\"times-circle\"></ui-icon>\n </button>\n </div>\n </td>\n </tr>\n </ng-template>\n <ng-template #emptymessage>\n <tr>\n <td colspan=\"8\" class=\"text-center py-4 text-muted-color\">\n @if (showCompanyInfo()) {\n {{ 'storage.empty.files.in.company' | translate }}\n } @else {\n {{ 'storage.empty.files' | translate }}\n }\n </td>\n </tr>\n </ng-template>\n </f-table>\n </div>\n </div>\n `,\n})\nexport class FileManagerListComponent extends BaseStorageListPage<IFileManager> {\n readonly FILE_PERMISSIONS = FILE_PERMISSIONS;\n\n private readonly fileService = inject(FileManagerApiService);\n private readonly translateService = inject(TranslateService);\n\n readonly files = this.items;\n readonly viewingFileId = signal<string | null>(null);\n\n private readonly _searchTerm = signal('');\n readonly searchTerm = this._searchTerm.asReadonly();\n\n readonly getFileIcon = getFileIcon;\n readonly getProviderLabelKey = getProviderLabelKey;\n readonly getProviderSeverity = getProviderSeverity;\n\n getResourceRoute(): string {\n return '/storage/files';\n }\n\n override getDeleteConfirmMessage(file: IFileManager): string {\n return this.translateService.translate('shared.confirm.delete.item', {\n name: file.name,\n });\n }\n\n async loadData(): Promise<void> {\n const token = this.beginLoad();\n this.isLoading.set(true);\n try {\n const response = await this.fileService.getAll(\n {\n pagination: this.getPaginationParams(),\n filter: {},\n select: [],\n sort: {},\n },\n this.searchTerm(),\n );\n\n if (!this.isLatestLoad(token)) return;\n\n if (response.success) {\n this.items.set(response.data ?? []);\n this.total.set(response.meta?.total ?? 0);\n }\n } finally {\n if (this.isLatestLoad(token)) this.isLoading.set(false);\n }\n }\n\n onSearchChange(term: string): void {\n this._searchTerm.set(term);\n this.first.set(0);\n this.loadData();\n }\n\n onUpload(): void {\n this.navigateTo(['/storage/files/new']);\n }\n\n async onView(file: IFileManager): Promise<void> {\n this.viewingFileId.set(file.id);\n try {\n const response = await firstValueFrom(\n this.fileService.getFiles([file.id]),\n );\n\n if (response.success && response.data?.length && response.data[0].url) {\n window.open(response.data[0].url, '_blank');\n } else {\n this.showError(\n this.translateService.translate('storage.file.url.not.available'),\n );\n }\n } finally {\n this.viewingFileId.set(null);\n }\n }\n\n onSoftDelete(file: IFileManager): void {\n this.confirmationService.confirm({\n message: this.translateService.translate(\n 'storage.delete.move.to.trash.confirm',\n { name: file.name },\n ),\n header: this.translateService.translate('storage.delete.move.to.trash'),\n icon: 'trash',\n acceptLabel: this.translateService.translate(\n 'storage.delete.move.to.trash',\n ),\n acceptButtonStyleClass: 'p-button-warning',\n accept: async () => {\n try {\n const response = await this.fileService.delete({\n id: file.id,\n type: 'delete',\n });\n this.showSuccess(\n response?.messageKey\n ? this.translateService.translate(\n response.messageKey,\n response.messageVariables as Record<string, string | number>,\n )\n : (response?.message ?? ''),\n );\n this.loadData();\n } catch {}\n },\n });\n }\n\n onPermanentDelete(file: IFileManager): void {\n this.confirmationService.confirm({\n message: this.translateService.translate(\n 'storage.delete.permanent.delete.confirm',\n { name: file.name },\n ),\n header: this.translateService.translate(\n 'storage.delete.permanent.delete',\n ),\n icon: 'exclamation-triangle',\n acceptLabel: this.translateService.translate(\n 'storage.delete.permanent.delete.button',\n ),\n rejectLabel: this.translateService.translate('shared.cancel'),\n acceptButtonStyleClass: 'p-button-danger',\n accept: async () => {\n try {\n const response = await this.fileService.delete({\n id: file.id,\n type: 'permanent',\n });\n this.showSuccess(\n response?.messageKey\n ? this.translateService.translate(\n response.messageKey,\n response.messageVariables as Record<string, string | number>,\n )\n : (response?.message ?? ''),\n );\n this.loadData();\n } catch {}\n },\n });\n }\n}\n"],"mappings":"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"}
@@ -45,6 +45,8 @@ var FolderFormComponent = class FolderFormComponent extends BaseStoragePage {
45
45
  name: folder.name
46
46
  });
47
47
  }
48
+ } catch {
49
+ this.navigateTo(["/storage/folders"]);
48
50
  } finally {
49
51
  this.isLoading.set(false);
50
52
  }
@@ -295,4 +297,4 @@ i0.ɵɵngDeclareClassMetadata({
295
297
  });
296
298
  export { FolderFormComponent };
297
299
 
298
- //# sourceMappingURL=flusys-ng-storage-folder-form.component-7C2oWijb.mjs.map
300
+ //# sourceMappingURL=flusys-ng-storage-folder-form.component-D9qZ47dk.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"flusys-ng-storage-folder-form.component-7C2oWijb.mjs","names":[],"sources":["../../../projects/ng-storage/pages/folder/folder-form.component.ts"],"sourcesContent":["import { Component, computed, effect, inject, signal } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { form, FormField, required } from '@angular/forms/signals';\nimport { ActivatedRoute } from '@angular/router';\nimport {\n TranslatePipe,\n TranslateService,\n} from '@flusys/ng-shared';\nimport { IFolder } from '../../interfaces/folder.interface';\nimport { FolderApiService } from '../../services/folder-api.service';\nimport { BaseStoragePage } from '../../utils/base-storage-page';\nimport {\n FButtonDirective,\n InputTextDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\n\ninterface IFolderFormModel {\n id: string;\n name: string;\n}\n\n@Component({\n selector: 'lib-folder-form',\n imports: [\n InputTextDirective,\n FButtonDirective,\n UiIconComponent,\n FormField,\n TranslatePipe,\n ],\n template: `\n <div class=\"card\">\n <div class=\"mb-4\">\n <h3 class=\"text-lg sm:text-xl font-semibold\">\n {{\n (isEditMode()\n ? 'storage.folder.edit.folder'\n : 'storage.folder.new.folder'\n ) | translate\n }}\n </h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">\n {{ 'shared.company' | translate }}: {{ currentCompanyName() }}\n </p>\n }\n </div>\n\n <form (submit)=\"onSubmit($event)\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div class=\"field\">\n <label\n for=\"name\"\n class=\"block font-medium mb-2 text-sm sm:text-base\"\n >{{ 'storage.folder.name.required' | translate }}</label\n >\n <input\n fInputText\n id=\"name\"\n [formField]=\"folderForm.name\"\n [placeholder]=\"'storage.folder.name.placeholder' | translate\"\n class=\"w-full\"\n />\n </div>\n </div>\n\n <div class=\"flex justify-end gap-2 mt-4\">\n <button\n fButton\n type=\"button\"\n severity=\"secondary\"\n [outlined]=\"true\"\n (click)=\"onCancel()\"\n >\n <span pButtonLabel>{{ 'shared.cancel' | translate }}</span>\n </button>\n <button\n fButton\n type=\"submit\"\n [disabled]=\"!isFormValid() || isLoading()\"\n >\n @if (isLoading()) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n }\n <span pButtonLabel>{{ \n (isEditMode() ? 'shared.update' : 'shared.create') | translate\n }}</span>\n </button>\n </div>\n </form>\n </div>\n `,\n})\nexport class FolderFormComponent extends BaseStoragePage {\n private readonly route = inject(ActivatedRoute);\n private readonly folderService = inject(FolderApiService);\n private readonly translateService = inject(TranslateService);\n\n private readonly routeParams = toSignal(this.route.paramMap);\n private initialized = false;\n\n readonly existingFolder = signal<IFolder | null>(null);\n readonly isEditMode = computed(() => !!this.existingFolder());\n\n readonly formModel = signal<IFolderFormModel>({\n id: '',\n name: '',\n });\n\n readonly folderForm = form(this.formModel, (f) => {\n required(f.name, {\n message: this.translateService.translate(\n 'storage.validation.folder.name.required',\n ),\n });\n });\n\n readonly isFormValid = computed(\n () => this.formModel().name.trim().length > 0,\n );\n\n constructor() {\n super();\n effect(() => {\n const params = this.routeParams();\n if (!params || this.initialized) return;\n\n this.initialized = true;\n const folderId = params.get('id');\n if (folderId && folderId !== 'new') {\n this.loadFolder(folderId);\n }\n });\n }\n\n async loadFolder(id: string): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await this.folderService.findById(id);\n if (response.success && response.data) {\n const folder = response.data;\n this.existingFolder.set(folder);\n this.formModel.set({ id: folder.id, name: folder.name });\n }\n } finally {\n this.isLoading.set(false);\n }\n }\n\n async onSubmit(event: Event): Promise<void> {\n event.preventDefault();\n\n if (!this.isFormValid()) return;\n\n this.isLoading.set(true);\n try {\n const formValue = this.formModel();\n\n const response = this.isEditMode()\n ? await this.folderService.update({\n id: formValue.id,\n name: formValue.name,\n })\n : await this.folderService.insert({ name: formValue.name });\n\n this.showSuccess(\n response.messageKey\n ? this.translateService.translate(\n response.messageKey,\n response.messageVariables as Record<string, string | number>,\n )\n : (response.message ?? ''),\n );\n\n this.navigateTo(['/storage/folders']);\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onCancel(): void {\n this.navigateTo(['/storage/folders']);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"flusys-ng-storage-folder-form.component-D9qZ47dk.mjs","names":[],"sources":["../../../projects/ng-storage/pages/folder/folder-form.component.ts"],"sourcesContent":["import { Component, computed, effect, inject, signal } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { form, FormField, required } from '@angular/forms/signals';\nimport { ActivatedRoute } from '@angular/router';\nimport {\n TranslatePipe,\n TranslateService,\n} from '@flusys/ng-shared';\nimport { IFolder } from '../../interfaces/folder.interface';\nimport { FolderApiService } from '../../services/folder-api.service';\nimport { BaseStoragePage } from '../../utils/base-storage-page';\nimport {\n FButtonDirective,\n InputTextDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\n\ninterface IFolderFormModel {\n id: string;\n name: string;\n}\n\n@Component({\n selector: 'lib-folder-form',\n imports: [\n InputTextDirective,\n FButtonDirective,\n UiIconComponent,\n FormField,\n TranslatePipe,\n ],\n template: `\n <div class=\"card\">\n <div class=\"mb-4\">\n <h3 class=\"text-lg sm:text-xl font-semibold\">\n {{\n (isEditMode()\n ? 'storage.folder.edit.folder'\n : 'storage.folder.new.folder'\n ) | translate\n }}\n </h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">\n {{ 'shared.company' | translate }}: {{ currentCompanyName() }}\n </p>\n }\n </div>\n\n <form (submit)=\"onSubmit($event)\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div class=\"field\">\n <label\n for=\"name\"\n class=\"block font-medium mb-2 text-sm sm:text-base\"\n >{{ 'storage.folder.name.required' | translate }}</label\n >\n <input\n fInputText\n id=\"name\"\n [formField]=\"folderForm.name\"\n [placeholder]=\"'storage.folder.name.placeholder' | translate\"\n class=\"w-full\"\n />\n </div>\n </div>\n\n <div class=\"flex justify-end gap-2 mt-4\">\n <button\n fButton\n type=\"button\"\n severity=\"secondary\"\n [outlined]=\"true\"\n (click)=\"onCancel()\"\n >\n <span pButtonLabel>{{ 'shared.cancel' | translate }}</span>\n </button>\n <button\n fButton\n type=\"submit\"\n [disabled]=\"!isFormValid() || isLoading()\"\n >\n @if (isLoading()) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n }\n <span pButtonLabel>{{ \n (isEditMode() ? 'shared.update' : 'shared.create') | translate\n }}</span>\n </button>\n </div>\n </form>\n </div>\n `,\n})\nexport class FolderFormComponent extends BaseStoragePage {\n private readonly route = inject(ActivatedRoute);\n private readonly folderService = inject(FolderApiService);\n private readonly translateService = inject(TranslateService);\n\n private readonly routeParams = toSignal(this.route.paramMap);\n private initialized = false;\n\n readonly existingFolder = signal<IFolder | null>(null);\n readonly isEditMode = computed(() => !!this.existingFolder());\n\n readonly formModel = signal<IFolderFormModel>({\n id: '',\n name: '',\n });\n\n readonly folderForm = form(this.formModel, (f) => {\n required(f.name, {\n message: this.translateService.translate(\n 'storage.validation.folder.name.required',\n ),\n });\n });\n\n readonly isFormValid = computed(\n () => this.formModel().name.trim().length > 0,\n );\n\n constructor() {\n super();\n effect(() => {\n const params = this.routeParams();\n if (!params || this.initialized) return;\n\n this.initialized = true;\n const folderId = params.get('id');\n if (folderId && folderId !== 'new') {\n this.loadFolder(folderId);\n }\n });\n }\n\n async loadFolder(id: string): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await this.folderService.findById(id);\n if (response.success && response.data) {\n const folder = response.data;\n this.existingFolder.set(folder);\n this.formModel.set({ id: folder.id, name: folder.name });\n }\n } catch {\n this.navigateTo(['/storage/folders']);\n } finally {\n this.isLoading.set(false);\n }\n }\n\n async onSubmit(event: Event): Promise<void> {\n event.preventDefault();\n\n if (!this.isFormValid()) return;\n\n this.isLoading.set(true);\n try {\n const formValue = this.formModel();\n\n const response = this.isEditMode()\n ? await this.folderService.update({\n id: formValue.id,\n name: formValue.name,\n })\n : await this.folderService.insert({ name: formValue.name });\n\n this.showSuccess(\n response.messageKey\n ? this.translateService.translate(\n response.messageKey,\n response.messageVariables as Record<string, string | number>,\n )\n : (response.message ?? ''),\n );\n\n this.navigateTo(['/storage/folders']);\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onCancel(): void {\n this.navigateTo(['/storage/folders']);\n }\n}\n"],"mappings":"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"}
@@ -21,15 +21,17 @@ var FolderListComponent = class FolderListComponent extends BaseStorageListPage
21
21
  return this.translateService.translate("shared.confirm.delete.item", { name: folder.name });
22
22
  }
23
23
  async loadData() {
24
+ const token = this.beginLoad();
24
25
  this.isLoading.set(true);
25
26
  try {
26
27
  const response = await this.folderService.getAll({ pagination: this.getPaginationParams() }, this.searchTerm());
28
+ if (!this.isLatestLoad(token)) return;
27
29
  if (response.success) {
28
30
  this.items.set(response.data ?? []);
29
31
  this.total.set(response.meta?.total ?? 0);
30
32
  }
31
33
  } finally {
32
- this.isLoading.set(false);
34
+ if (this.isLatestLoad(token)) this.isLoading.set(false);
33
35
  }
34
36
  }
35
37
  onSearchChange(term) {
@@ -520,4 +522,4 @@ i0.ɵɵngDeclareClassMetadata({
520
522
  });
521
523
  export { FolderListComponent };
522
524
 
523
- //# sourceMappingURL=flusys-ng-storage-folder-list.component-BdSBM_DB.mjs.map
525
+ //# sourceMappingURL=flusys-ng-storage-folder-list.component-B0kQQRFm.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"flusys-ng-storage-folder-list.component-BdSBM_DB.mjs","names":[],"sources":["../../../projects/ng-storage/pages/folder/folder-list.component.ts"],"sourcesContent":["import { Component, inject, signal } from '@angular/core';\nimport { DatePipe } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport {\n FOLDER_PERMISSIONS,\n HasPermissionDirective,\n TranslatePipe,\n TranslateService,\n} from '@flusys/ng-shared';\nimport { IFolder } from '../../interfaces/folder.interface';\nimport { FolderApiService } from '../../services/folder-api.service';\nimport { BaseStorageListPage } from '../../utils/base-storage-page';\nimport {\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TableComponent,\n TooltipDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\n\n@Component({\n selector: 'lib-folder-list',\n imports: [\n DatePipe,\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TableComponent,\n TooltipDirective,\n UiIconComponent,\n FormsModule,\n HasPermissionDirective,\n TranslatePipe,\n ],\n template: `\n <div class=\"card\">\n <div\n class=\"flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 mb-4\"\n >\n <div>\n <h3 class=\"text-lg sm:text-xl font-semibold\">\n {{ 'storage.folder.title' | translate }}\n </h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">\n {{ 'shared.company' | translate }}: {{ currentCompanyName() }}\n </p>\n }\n </div>\n <div\n class=\"flex flex-col sm:flex-row items-stretch sm:items-center gap-2 w-full sm:w-auto\"\n >\n <f-iconfield class=\"w-full sm:w-64\">\n <f-inputicon icon=\"search\" />\n <input\n fInputText\n type=\"text\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onSearchChange($event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [placeholder]=\"'shared.search' | translate\"\n class=\"w-full\"\n />\n </f-iconfield>\n <button\n fButton\n *hasPermission=\"FOLDER_PERMISSIONS.CREATE\"\n (click)=\"onCreate()\"\n class=\"w-full sm:w-auto\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{ 'storage.button.new.folder' | translate }}</span>\n </button>\n </div>\n </div>\n\n <div class=\"overflow-x-auto\">\n <f-table\n [value]=\"folders()\"\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 >\n <ng-template #header>\n <tr>\n <th>{{ 'shared.name' | translate }}</th>\n <th>{{ 'storage.table.slug' | translate }}</th>\n <th class=\"hidden sm:table-cell\">\n {{ 'storage.table.created' | translate }}\n </th>\n <th class=\"w-[120px]\">\n {{ 'shared.actions' | translate }}\n </th>\n </tr>\n </ng-template>\n <ng-template #body let-folder>\n <tr>\n <td>\n <ui-icon name=\"folder\" class=\"mr-2\"></ui-icon>\n {{ folder.name }}\n </td>\n <td>{{ folder.slug }}</td>\n <td class=\"hidden sm:table-cell\">\n {{ folder.createdAt | date: 'short' }}\n </td>\n <td>\n <div class=\"flex gap-1\">\n <button\n fButton\n *hasPermission=\"FOLDER_PERMISSIONS.UPDATE\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n (click)=\"onEdit(folder.id)\"\n [fTooltip]=\"'shared.edit' | translate\"\n tooltipPosition=\"top\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n <button\n fButton\n *hasPermission=\"FOLDER_PERMISSIONS.DELETE\"\n [text]=\"true\"\n severity=\"danger\"\n size=\"small\"\n (click)=\"onDeleteFolder(folder)\"\n [fTooltip]=\"'shared.delete' | translate\"\n tooltipPosition=\"top\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\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 @if (showCompanyInfo()) {\n {{ 'storage.empty.folders.in.company' | translate }}\n } @else {\n {{ 'storage.empty.folders' | translate }}\n }\n </td>\n </tr>\n </ng-template>\n </f-table>\n </div>\n </div>\n `,\n})\nexport class FolderListComponent extends BaseStorageListPage<IFolder> {\n readonly FOLDER_PERMISSIONS = FOLDER_PERMISSIONS;\n\n private readonly folderService = inject(FolderApiService);\n private readonly translateService = inject(TranslateService);\n\n readonly folders = this.items;\n\n private readonly _searchTerm = signal('');\n readonly searchTerm = this._searchTerm.asReadonly();\n\n getResourceRoute(): string {\n return '/storage/folders';\n }\n\n override getDeleteConfirmMessage(folder: IFolder): string {\n return this.translateService.translate('shared.confirm.delete.item', {\n name: folder.name,\n });\n }\n\n async loadData(): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await this.folderService.getAll(\n {\n pagination: this.getPaginationParams(),\n },\n this.searchTerm(),\n );\n if (response.success) {\n this.items.set(response.data ?? []);\n this.total.set(response.meta?.total ?? 0);\n }\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onSearchChange(term: string): void {\n this._searchTerm.set(term);\n this.first.set(0);\n this.loadData();\n }\n\n onDeleteFolder(folder: IFolder): void {\n this.onDeleteAsync(\n folder,\n (f) => f.id,\n (id) => this.folderService.delete({ id, type: 'delete' }),\n {\n header: this.translateService.translate('storage.folder.delete.title'),\n },\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"flusys-ng-storage-folder-list.component-B0kQQRFm.mjs","names":[],"sources":["../../../projects/ng-storage/pages/folder/folder-list.component.ts"],"sourcesContent":["import { Component, inject, signal } from '@angular/core';\nimport { DatePipe } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport {\n FOLDER_PERMISSIONS,\n HasPermissionDirective,\n TranslatePipe,\n TranslateService,\n} from '@flusys/ng-shared';\nimport { IFolder } from '../../interfaces/folder.interface';\nimport { FolderApiService } from '../../services/folder-api.service';\nimport { BaseStorageListPage } from '../../utils/base-storage-page';\nimport {\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TableComponent,\n TooltipDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\n\n@Component({\n selector: 'lib-folder-list',\n imports: [\n DatePipe,\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TableComponent,\n TooltipDirective,\n UiIconComponent,\n FormsModule,\n HasPermissionDirective,\n TranslatePipe,\n ],\n template: `\n <div class=\"card\">\n <div\n class=\"flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 mb-4\"\n >\n <div>\n <h3 class=\"text-lg sm:text-xl font-semibold\">\n {{ 'storage.folder.title' | translate }}\n </h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">\n {{ 'shared.company' | translate }}: {{ currentCompanyName() }}\n </p>\n }\n </div>\n <div\n class=\"flex flex-col sm:flex-row items-stretch sm:items-center gap-2 w-full sm:w-auto\"\n >\n <f-iconfield class=\"w-full sm:w-64\">\n <f-inputicon icon=\"search\" />\n <input\n fInputText\n type=\"text\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onSearchChange($event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [placeholder]=\"'shared.search' | translate\"\n class=\"w-full\"\n />\n </f-iconfield>\n <button\n fButton\n *hasPermission=\"FOLDER_PERMISSIONS.CREATE\"\n (click)=\"onCreate()\"\n class=\"w-full sm:w-auto\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{ 'storage.button.new.folder' | translate }}</span>\n </button>\n </div>\n </div>\n\n <div class=\"overflow-x-auto\">\n <f-table\n [value]=\"folders()\"\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 >\n <ng-template #header>\n <tr>\n <th>{{ 'shared.name' | translate }}</th>\n <th>{{ 'storage.table.slug' | translate }}</th>\n <th class=\"hidden sm:table-cell\">\n {{ 'storage.table.created' | translate }}\n </th>\n <th class=\"w-[120px]\">\n {{ 'shared.actions' | translate }}\n </th>\n </tr>\n </ng-template>\n <ng-template #body let-folder>\n <tr>\n <td>\n <ui-icon name=\"folder\" class=\"mr-2\"></ui-icon>\n {{ folder.name }}\n </td>\n <td>{{ folder.slug }}</td>\n <td class=\"hidden sm:table-cell\">\n {{ folder.createdAt | date: 'short' }}\n </td>\n <td>\n <div class=\"flex gap-1\">\n <button\n fButton\n *hasPermission=\"FOLDER_PERMISSIONS.UPDATE\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n (click)=\"onEdit(folder.id)\"\n [fTooltip]=\"'shared.edit' | translate\"\n tooltipPosition=\"top\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n <button\n fButton\n *hasPermission=\"FOLDER_PERMISSIONS.DELETE\"\n [text]=\"true\"\n severity=\"danger\"\n size=\"small\"\n (click)=\"onDeleteFolder(folder)\"\n [fTooltip]=\"'shared.delete' | translate\"\n tooltipPosition=\"top\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\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 @if (showCompanyInfo()) {\n {{ 'storage.empty.folders.in.company' | translate }}\n } @else {\n {{ 'storage.empty.folders' | translate }}\n }\n </td>\n </tr>\n </ng-template>\n </f-table>\n </div>\n </div>\n `,\n})\nexport class FolderListComponent extends BaseStorageListPage<IFolder> {\n readonly FOLDER_PERMISSIONS = FOLDER_PERMISSIONS;\n\n private readonly folderService = inject(FolderApiService);\n private readonly translateService = inject(TranslateService);\n\n readonly folders = this.items;\n\n private readonly _searchTerm = signal('');\n readonly searchTerm = this._searchTerm.asReadonly();\n\n getResourceRoute(): string {\n return '/storage/folders';\n }\n\n override getDeleteConfirmMessage(folder: IFolder): string {\n return this.translateService.translate('shared.confirm.delete.item', {\n name: folder.name,\n });\n }\n\n async loadData(): Promise<void> {\n const token = this.beginLoad();\n this.isLoading.set(true);\n try {\n const response = await this.folderService.getAll(\n {\n pagination: this.getPaginationParams(),\n },\n this.searchTerm(),\n );\n if (!this.isLatestLoad(token)) return;\n if (response.success) {\n this.items.set(response.data ?? []);\n this.total.set(response.meta?.total ?? 0);\n }\n } finally {\n if (this.isLatestLoad(token)) this.isLoading.set(false);\n }\n }\n\n onSearchChange(term: string): void {\n this._searchTerm.set(term);\n this.first.set(0);\n this.loadData();\n }\n\n onDeleteFolder(folder: IFolder): void {\n this.onDeleteAsync(\n folder,\n (f) => f.id,\n (id) => this.folderService.delete({ id, type: 'delete' }),\n {\n header: this.translateService.translate('storage.folder.delete.title'),\n },\n );\n }\n}\n"],"mappings":"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"}
@@ -23,17 +23,19 @@ var StorageConfigListComponent = class StorageConfigListComponent extends BaseSt
23
23
  return this.translateService.translate("shared.confirm.delete.item", { name: config.name });
24
24
  }
25
25
  async loadData() {
26
+ const token = this.beginLoad();
26
27
  this.isLoading.set(true);
27
28
  try {
28
29
  const response = await this.configService.getAll({ pagination: this.getPaginationParams() }, this.searchTerm());
30
+ if (!this.isLatestLoad(token)) return;
29
31
  if (response.success) {
30
32
  this.items.set(response.data ?? []);
31
33
  this.total.set(response.meta?.total ?? 0);
32
34
  }
33
35
  } catch {
34
- this.showError(this.translateService.translate("storage.config.load.failed"));
36
+ if (this.isLatestLoad(token)) this.showError(this.translateService.translate("storage.config.load.failed"));
35
37
  } finally {
36
- this.isLoading.set(false);
38
+ if (this.isLatestLoad(token)) this.isLoading.set(false);
37
39
  }
38
40
  }
39
41
  onSearchChange(term) {
@@ -571,4 +573,4 @@ i0.ɵɵngDeclareClassMetadata({
571
573
  });
572
574
  export { StorageConfigListComponent };
573
575
 
574
- //# sourceMappingURL=flusys-ng-storage-storage-config-list.component-Dh9JkuZP.mjs.map
576
+ //# sourceMappingURL=flusys-ng-storage-storage-config-list.component-B6uawDtd.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"flusys-ng-storage-storage-config-list.component-Dh9JkuZP.mjs","names":[],"sources":["../../../projects/ng-storage/pages/storage-config/storage-config-list.component.ts"],"sourcesContent":["import { Component, inject, signal } from '@angular/core';\nimport { DatePipe } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport {\n HasPermissionDirective,\n STORAGE_CONFIG_PERMISSIONS,\n TranslatePipe,\n TranslateService,\n} from '@flusys/ng-shared';\nimport {\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TableComponent,\n TagComponent,\n TooltipDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\nimport { IStorageConfig } from '../../interfaces/storage-config.interface';\nimport { StorageConfigApiService } from '../../services/storage-config-api.service';\nimport { BaseStorageListPage } from '../../utils/base-storage-page';\nimport {\n getProviderIcon,\n getProviderLabelKey,\n getProviderSeverity,\n} from '../../utils/storage-utils';\n\n@Component({\n selector: 'lib-storage-config-list',\n imports: [\n FButtonDirective,\n UiIconComponent,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TableComponent,\n TagComponent,\n TooltipDirective,\n DatePipe,\n FormsModule,\n HasPermissionDirective,\n TranslatePipe,\n ],\n template: `\n <div class=\"card\">\n <div\n class=\"flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 mb-4\"\n >\n <div>\n <h3 class=\"text-lg sm:text-xl font-semibold\">\n {{ 'storage.config.title' | translate }}\n </h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">\n {{ 'shared.company' | translate }}: {{ currentCompanyName() }}\n </p>\n }\n </div>\n <div\n class=\"flex flex-col sm:flex-row items-stretch sm:items-center gap-2 w-full sm:w-auto\"\n >\n <f-iconfield class=\"w-full sm:w-64\">\n <f-inputicon icon=\"search\" />\n <input\n fInputText\n type=\"text\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onSearchChange($event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [placeholder]=\"'shared.search' | translate\"\n class=\"w-full\"\n />\n </f-iconfield>\n <button\n fButton\n *hasPermission=\"STORAGE_CONFIG_PERMISSIONS.CREATE\"\n (click)=\"onCreate()\"\n class=\"w-full sm:w-auto\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{ 'storage.button.new.configuration' | translate }}</span>\n </button>\n </div>\n </div>\n\n <div class=\"overflow-x-auto\">\n <f-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 >\n <ng-template #header>\n <tr>\n <th>{{ 'shared.name' | translate }}</th>\n <th>{{ 'storage.table.provider' | translate }}</th>\n <th class=\"hidden sm:table-cell\">\n {{ 'storage.table.created' | translate }}\n </th>\n <th class=\"w-[120px]\">\n {{ 'shared.actions' | translate }}\n </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 <ui-icon [name]=\"getProviderIcon(config.storage)\"></ui-icon>\n <span class=\"truncate max-w-32 sm:max-w-none\">{{\n config.name\n }}</span>\n </div>\n </td>\n <td>\n <f-tag\n [value]=\"getProviderLabelKey(config.storage) | translate\"\n [severity]=\"getProviderSeverity(config.storage)\"\n />\n </td>\n <td class=\"hidden sm:table-cell\">\n {{ config.createdAt | date: 'short' }}\n </td>\n <td>\n <div class=\"flex gap-1\">\n <button\n fButton\n *hasPermission=\"STORAGE_CONFIG_PERMISSIONS.UPDATE\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n (click)=\"onEdit(config.id)\"\n [fTooltip]=\"'shared.edit' | translate\"\n tooltipPosition=\"top\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n <button\n fButton\n *hasPermission=\"STORAGE_CONFIG_PERMISSIONS.DELETE\"\n [text]=\"true\"\n severity=\"danger\"\n size=\"small\"\n [disabled]=\"config.isDefault\"\n (click)=\"onDeleteConfig(config)\"\n [fTooltip]=\"\n (config.isDefault\n ? 'storage.config.default.delete.forbidden'\n : 'shared.delete'\n ) | translate\n \"\n tooltipPosition=\"top\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\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 {{\n (showCompanyInfo()\n ? 'storage.empty.configs.in.company'\n : 'storage.empty.configs'\n ) | translate\n }}\n </td>\n </tr>\n </ng-template>\n </f-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 private readonly translateService = inject(TranslateService);\n\n readonly getProviderIcon = getProviderIcon;\n readonly getProviderLabelKey = getProviderLabelKey;\n readonly getProviderSeverity = getProviderSeverity;\n\n private readonly _searchTerm = signal('');\n readonly searchTerm = this._searchTerm.asReadonly();\n\n getResourceRoute(): string {\n return '/storage/configs';\n }\n\n override getDeleteConfirmMessage(config: IStorageConfig): string {\n return this.translateService.translate('shared.confirm.delete.item', {\n name: config.name,\n });\n }\n\n async loadData(): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await this.configService.getAll(\n {\n pagination: this.getPaginationParams(),\n },\n this.searchTerm(),\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(\n this.translateService.translate('storage.config.load.failed'),\n );\n } finally {\n this.isLoading.set(false);\n }\n }\n\n onSearchChange(term: string): void {\n this._searchTerm.set(term);\n this.first.set(0);\n this.loadData();\n }\n\n onDeleteConfig(config: IStorageConfig): void {\n this.onDeleteAsync(\n config,\n (c) => c.id,\n (id) => this.configService.delete({ id, type: 'delete' }),\n {\n header: this.translateService.translate('storage.config.delete.title'),\n },\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"flusys-ng-storage-storage-config-list.component-B6uawDtd.mjs","names":[],"sources":["../../../projects/ng-storage/pages/storage-config/storage-config-list.component.ts"],"sourcesContent":["import { Component, inject, signal } from '@angular/core';\nimport { DatePipe } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport {\n HasPermissionDirective,\n STORAGE_CONFIG_PERMISSIONS,\n TranslatePipe,\n TranslateService,\n} from '@flusys/ng-shared';\nimport {\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TableComponent,\n TagComponent,\n TooltipDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\nimport { IStorageConfig } from '../../interfaces/storage-config.interface';\nimport { StorageConfigApiService } from '../../services/storage-config-api.service';\nimport { BaseStorageListPage } from '../../utils/base-storage-page';\nimport {\n getProviderIcon,\n getProviderLabelKey,\n getProviderSeverity,\n} from '../../utils/storage-utils';\n\n@Component({\n selector: 'lib-storage-config-list',\n imports: [\n FButtonDirective,\n UiIconComponent,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TableComponent,\n TagComponent,\n TooltipDirective,\n DatePipe,\n FormsModule,\n HasPermissionDirective,\n TranslatePipe,\n ],\n template: `\n <div class=\"card\">\n <div\n class=\"flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 mb-4\"\n >\n <div>\n <h3 class=\"text-lg sm:text-xl font-semibold\">\n {{ 'storage.config.title' | translate }}\n </h3>\n @if (showCompanyInfo()) {\n <p class=\"text-sm text-muted-color mt-1\">\n {{ 'shared.company' | translate }}: {{ currentCompanyName() }}\n </p>\n }\n </div>\n <div\n class=\"flex flex-col sm:flex-row items-stretch sm:items-center gap-2 w-full sm:w-auto\"\n >\n <f-iconfield class=\"w-full sm:w-64\">\n <f-inputicon icon=\"search\" />\n <input\n fInputText\n type=\"text\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onSearchChange($event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [placeholder]=\"'shared.search' | translate\"\n class=\"w-full\"\n />\n </f-iconfield>\n <button\n fButton\n *hasPermission=\"STORAGE_CONFIG_PERMISSIONS.CREATE\"\n (click)=\"onCreate()\"\n class=\"w-full sm:w-auto\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{ 'storage.button.new.configuration' | translate }}</span>\n </button>\n </div>\n </div>\n\n <div class=\"overflow-x-auto\">\n <f-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 >\n <ng-template #header>\n <tr>\n <th>{{ 'shared.name' | translate }}</th>\n <th>{{ 'storage.table.provider' | translate }}</th>\n <th class=\"hidden sm:table-cell\">\n {{ 'storage.table.created' | translate }}\n </th>\n <th class=\"w-[120px]\">\n {{ 'shared.actions' | translate }}\n </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 <ui-icon [name]=\"getProviderIcon(config.storage)\"></ui-icon>\n <span class=\"truncate max-w-32 sm:max-w-none\">{{\n config.name\n }}</span>\n </div>\n </td>\n <td>\n <f-tag\n [value]=\"getProviderLabelKey(config.storage) | translate\"\n [severity]=\"getProviderSeverity(config.storage)\"\n />\n </td>\n <td class=\"hidden sm:table-cell\">\n {{ config.createdAt | date: 'short' }}\n </td>\n <td>\n <div class=\"flex gap-1\">\n <button\n fButton\n *hasPermission=\"STORAGE_CONFIG_PERMISSIONS.UPDATE\"\n [text]=\"true\"\n severity=\"secondary\"\n size=\"small\"\n (click)=\"onEdit(config.id)\"\n [fTooltip]=\"'shared.edit' | translate\"\n tooltipPosition=\"top\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n <button\n fButton\n *hasPermission=\"STORAGE_CONFIG_PERMISSIONS.DELETE\"\n [text]=\"true\"\n severity=\"danger\"\n size=\"small\"\n [disabled]=\"config.isDefault\"\n (click)=\"onDeleteConfig(config)\"\n [fTooltip]=\"\n (config.isDefault\n ? 'storage.config.default.delete.forbidden'\n : 'shared.delete'\n ) | translate\n \"\n tooltipPosition=\"top\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\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 {{\n (showCompanyInfo()\n ? 'storage.empty.configs.in.company'\n : 'storage.empty.configs'\n ) | translate\n }}\n </td>\n </tr>\n </ng-template>\n </f-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 private readonly translateService = inject(TranslateService);\n\n readonly getProviderIcon = getProviderIcon;\n readonly getProviderLabelKey = getProviderLabelKey;\n readonly getProviderSeverity = getProviderSeverity;\n\n private readonly _searchTerm = signal('');\n readonly searchTerm = this._searchTerm.asReadonly();\n\n getResourceRoute(): string {\n return '/storage/configs';\n }\n\n override getDeleteConfirmMessage(config: IStorageConfig): string {\n return this.translateService.translate('shared.confirm.delete.item', {\n name: config.name,\n });\n }\n\n async loadData(): Promise<void> {\n const token = this.beginLoad();\n this.isLoading.set(true);\n try {\n const response = await this.configService.getAll(\n {\n pagination: this.getPaginationParams(),\n },\n this.searchTerm(),\n );\n if (!this.isLatestLoad(token)) return;\n if (response.success) {\n this.items.set(response.data ?? []);\n this.total.set(response.meta?.total ?? 0);\n }\n } catch {\n if (this.isLatestLoad(token)) {\n this.showError(\n this.translateService.translate('storage.config.load.failed'),\n );\n }\n } finally {\n if (this.isLatestLoad(token)) this.isLoading.set(false);\n }\n }\n\n onSearchChange(term: string): void {\n this._searchTerm.set(term);\n this.first.set(0);\n this.loadData();\n }\n\n onDeleteConfig(config: IStorageConfig): void {\n this.onDeleteAsync(\n config,\n (c) => c.id,\n (id) => this.configService.delete({ id, type: 'delete' }),\n {\n header: this.translateService.translate('storage.config.delete.title'),\n },\n );\n }\n}\n"],"mappings":"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"}
@@ -224,7 +224,7 @@ function formatFileSizeWithKey(bytes) {
224
224
  unitKey: "storage.size.bytes"
225
225
  };
226
226
  const k = 1024;
227
- const i = Math.min(Math.floor(Math.log(bytes) / Math.log(k)), FILE_SIZE_UNIT_KEYS.length - 1);
227
+ const i = Math.min(Math.max(0, Math.floor(Math.log(bytes) / Math.log(k))), FILE_SIZE_UNIT_KEYS.length - 1);
228
228
  return {
229
229
  value: (Math.round(bytes / Math.pow(k, i) * 100) / 100).toString(),
230
230
  unitKey: FILE_SIZE_UNIT_KEYS[i]
@@ -325,6 +325,7 @@ var BaseStorageListPage = class BaseStorageListPage {
325
325
  showCompanyInfo = computed(() => this.appConfig.enableCompanyFeature, ...ngDevMode ? [{ debugName: "showCompanyInfo" }] : /* istanbul ignore next */ []);
326
326
  totalRecords = this.total;
327
327
  currentCompanyName = computed(() => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME, ...ngDevMode ? [{ debugName: "currentCompanyName" }] : /* istanbul ignore next */ []);
328
+ loadToken = 0;
328
329
  getDeleteConfirmMessage(item) {
329
330
  const name = item.name ?? this.translateAdapter.translate("storage.delete.this.item");
330
331
  return this.translateAdapter.translate("shared.confirm.delete.item", { name });
@@ -340,6 +341,12 @@ var BaseStorageListPage = class BaseStorageListPage {
340
341
  this.pageSize.set(event.rows ?? 10);
341
342
  this.loadData();
342
343
  }
344
+ beginLoad() {
345
+ return ++this.loadToken;
346
+ }
347
+ isLatestLoad(token) {
348
+ return token === this.loadToken;
349
+ }
343
350
  getPaginationParams() {
344
351
  return {
345
352
  currentPage: this.currentPage(),
@@ -576,7 +583,7 @@ const STORAGE_ROUTES = [{
576
583
  children: [
577
584
  {
578
585
  path: "",
579
- loadComponent: () => import("./flusys-ng-storage-file-manager-list.component-4_LdJOtH.mjs").then((m) => m.FileManagerListComponent)
586
+ loadComponent: () => import("./flusys-ng-storage-file-manager-list.component-BjlsjxSH.mjs").then((m) => m.FileManagerListComponent)
580
587
  },
581
588
  {
582
589
  path: "new",
@@ -596,17 +603,17 @@ const STORAGE_ROUTES = [{
596
603
  children: [
597
604
  {
598
605
  path: "",
599
- loadComponent: () => import("./flusys-ng-storage-folder-list.component-BdSBM_DB.mjs").then((m) => m.FolderListComponent)
606
+ loadComponent: () => import("./flusys-ng-storage-folder-list.component-B0kQQRFm.mjs").then((m) => m.FolderListComponent)
600
607
  },
601
608
  {
602
609
  path: "new",
603
610
  canActivate: [permissionGuard(FOLDER_PERMISSIONS.CREATE)],
604
- loadComponent: () => import("./flusys-ng-storage-folder-form.component-7C2oWijb.mjs").then((m) => m.FolderFormComponent)
611
+ loadComponent: () => import("./flusys-ng-storage-folder-form.component-D9qZ47dk.mjs").then((m) => m.FolderFormComponent)
605
612
  },
606
613
  {
607
614
  path: ":id",
608
615
  canActivate: [permissionGuard(FOLDER_PERMISSIONS.UPDATE)],
609
- loadComponent: () => import("./flusys-ng-storage-folder-form.component-7C2oWijb.mjs").then((m) => m.FolderFormComponent)
616
+ loadComponent: () => import("./flusys-ng-storage-folder-form.component-D9qZ47dk.mjs").then((m) => m.FolderFormComponent)
610
617
  }
611
618
  ]
612
619
  },
@@ -616,7 +623,7 @@ const STORAGE_ROUTES = [{
616
623
  children: [
617
624
  {
618
625
  path: "",
619
- loadComponent: () => import("./flusys-ng-storage-storage-config-list.component-Dh9JkuZP.mjs").then((m) => m.StorageConfigListComponent)
626
+ loadComponent: () => import("./flusys-ng-storage-storage-config-list.component-B6uawDtd.mjs").then((m) => m.StorageConfigListComponent)
620
627
  },
621
628
  {
622
629
  path: "new",
@@ -1 +1 @@
1
- {"version":3,"file":"flusys-ng-storage.mjs","names":[],"sources":["../../../projects/ng-storage/constants/messages.ts","../../../projects/ng-storage/enums/file-location.enum.ts","../../../projects/ng-storage/utils/storage-utils.ts","../../../projects/ng-storage/utils/base-storage-page.ts","../../../projects/ng-storage/adapters/file-provider.adapter.ts","../../../projects/ng-storage/providers/storage-providers.ts","../../../projects/ng-storage/routes/storage.routes.ts"],"sourcesContent":["export const STORAGE_MESSAGES: Record<string, string> = {\n // File entity CRUD (API keys)\n 'file.create.success': 'File created successfully',\n 'file.create.many.success': '{{count}} files created successfully',\n 'file.get.success': 'File retrieved successfully',\n 'file.get.by.ids.success': 'Files retrieved successfully by Ids',\n 'file.get.by.filter.success': 'Files retrieved successfully by filter',\n 'file.get.all.success': 'Files retrieved successfully',\n 'file.update.success': 'File updated successfully',\n 'file.update.many.success': '{{count}} files updated successfully',\n 'file.delete.success': 'File deleted successfully',\n 'file.restore.success': 'File restored successfully',\n 'file.not.found': 'File not found',\n\n // Folder entity CRUD (API keys)\n 'folder.create.success': 'Folder created successfully',\n 'folder.create.many.success': '{{count}} folders created successfully',\n 'folder.get.success': 'Folder retrieved successfully',\n 'folder.get.by.ids.success': 'Folders retrieved successfully by Ids',\n 'folder.get.by.filter.success': 'Folders retrieved successfully by filter',\n 'folder.get.all.success': 'Folders retrieved successfully',\n 'folder.update.success': 'Folder updated successfully',\n 'folder.update.many.success': '{{count}} folders updated successfully',\n 'folder.delete.success': 'Folder deleted successfully',\n 'folder.restore.success': 'Folder restored successfully',\n 'folder.not.found': 'Folder not found',\n\n // Storage config CRUD (API keys)\n 'storage.config.create.success': 'Storage configuration created successfully',\n 'storage.config.create.many.success':\n '{{count}} storage configurations created successfully',\n 'storage.config.get.success': 'Storage configuration retrieved successfully',\n 'storage.config.get.by.ids.success':\n 'Storage configurations retrieved successfully by Ids',\n 'storage.config.get.by.filter.success':\n 'Storage configurations retrieved successfully by filter',\n 'storage.config.get.all.success':\n 'Storage configurations retrieved successfully',\n 'storage.config.update.success': 'Storage configuration updated successfully',\n 'storage.config.update.many.success':\n '{{count}} storage configurations updated successfully',\n 'storage.config.delete.success': 'Storage configuration deleted successfully',\n 'storage.config.restore.success':\n 'Storage configuration restored successfully',\n\n // Upload (API keys)\n 'upload.success': 'File uploaded successfully',\n 'upload.many.success': 'Files uploaded successfully',\n 'upload.file.too.large':\n 'File size ({{fileSize}}MB) exceeds maximum {{maxSize}}MB',\n 'upload.invalid.type':\n 'File type \"{{mimeType}}\" not allowed. Allowed: {{allowedTypes}}',\n 'upload.no.files.provided': 'No files provided',\n 'upload.no.file.path': 'File path is required',\n 'upload.invalid.file.path': 'Invalid file path',\n 'upload.config.not.found': 'Upload configuration not found',\n\n // pages/storage-container/storage-container.component.ts\n 'storage.title': 'Storage',\n 'storage.subtitle': 'Manage files, folders, and storage configurations',\n 'storage.file.title': 'Files',\n 'storage.folder.title': 'Folder Setup',\n 'storage.config.title': 'Storage Configurations',\n\n // pages/storage-config/storage-config-list.component.ts\n 'storage.button.new.configuration': 'New Configuration',\n 'storage.table.provider': 'Provider',\n 'storage.table.created': 'Created',\n 'storage.empty.configs.in.company':\n 'No storage configurations found in current company',\n 'storage.empty.configs': 'No storage configurations found',\n 'storage.config.load.failed': 'Failed to load storage configurations',\n 'storage.config.delete.title': 'Delete Configuration',\n 'storage.config.default.delete.forbidden':\n 'Cannot delete the default configuration. Set another as default first.',\n\n // pages/storage-config/storage-config-form.component.ts\n 'storage.config.edit.config': 'Edit Storage Configuration',\n 'storage.config.new.config': 'New Configuration',\n 'storage.config.config.name.required': 'Configuration Name *',\n 'storage.config.config.name.placeholder': 'e.g., Production AWS S3',\n 'storage.config.provider.required': 'Storage Provider *',\n 'storage.set.as.default': 'Set as Default',\n 'storage.aws.title': 'AWS S3 Configuration',\n 'storage.config.region.required': 'AWS Region *',\n 'storage.aws.region.placeholder': 'us-east-1',\n 'storage.config.bucket.required': 'Bucket Name *',\n 'storage.aws.bucket.placeholder': 'my-bucket',\n 'storage.config.access.key.required': 'Access Key ID *',\n 'storage.config.secret.key.required': 'Secret Access Key *',\n 'storage.config.endpoint.optional': 'Custom Endpoint (Optional)',\n 'storage.config.endpoint.placeholder': 'https://s3.custom-endpoint.com',\n 'storage.azure.title': 'Azure Blob Configuration',\n 'storage.azure.account.name.required': 'Account Name *',\n 'storage.azure.container.name.required': 'Container Name *',\n 'storage.azure.account.key.required': 'Account Key *',\n 'storage.sftp.title': 'SFTP Configuration',\n 'storage.sftp.host.required': 'Host *',\n 'storage.sftp.host.placeholder': 'sftp.example.com',\n 'storage.sftp.port.required': 'Port *',\n 'storage.sftp.port.placeholder': '22',\n 'storage.sftp.username.required': 'Username *',\n 'storage.sftp.password.required': 'Password *',\n 'storage.sftp.base.path.required': 'Base Path *',\n 'storage.sftp.base.path.placeholder': '/uploads',\n 'storage.local.title': 'Local Storage Configuration',\n 'storage.local.base.path.required': 'Base Path *',\n 'storage.local.base.path.placeholder': '/var/www/uploads',\n 'storage.config.endpoint': 'Endpoint URL',\n 'storage.validation.config.name.required': 'Configuration name is required',\n\n // pages/file-manager/file-manager-list.component.ts\n 'storage.file.manager.title': 'File Manager',\n 'storage.button.upload.file': 'Upload File',\n 'storage.table.size': 'Size',\n 'storage.table.location': 'Location',\n 'storage.table.config': 'Config',\n 'storage.table.private': 'Private',\n 'storage.private': 'Private',\n 'storage.public': 'Public',\n 'storage.tooltip.trash': 'Trash',\n 'storage.empty.files.in.company': 'No files found in current company',\n 'storage.empty.files': 'No files found',\n 'storage.file.url.not.available': 'File URL is not available',\n 'storage.delete.move.to.trash.confirm':\n 'Move \"{{name}}\" to trash? You can recover it later.',\n 'storage.delete.move.to.trash': 'Move to Trash',\n 'storage.delete.permanent.delete.confirm':\n 'Permanently delete \"{{name}}\"? This action CANNOT be undone and will delete the file from storage.',\n 'storage.delete.permanent.delete': 'Permanent Delete',\n 'storage.delete.permanent.delete.button': 'Delete Permanently',\n\n // pages/file-manager/file-manager-form.component.ts\n 'storage.file.manager.edit.file': 'Edit File',\n 'storage.file.manager.upload.file': 'Upload File',\n 'storage.config.select.config': 'Select storage configuration...',\n 'storage.config.no.configs':\n 'No storage configurations found. Please create one first.',\n 'storage.folder.optional': 'Folder (Optional)',\n 'storage.folder.no.folder': 'No folder (root level)',\n 'storage.folder.no.folders.available':\n 'No folders available. File will be uploaded to root level.',\n 'storage.folder.no.folders.edit': 'No folders available.',\n 'storage.file.select.required': 'Select File *',\n 'storage.button.choose.file': 'Choose File',\n 'storage.upload.drag.drop': 'Drag and drop file here or click to browse',\n 'storage.upload.max.size': 'Maximum file size: {{size}}',\n 'storage.upload.please.select': 'Please select a file to upload',\n 'storage.file.name.required': 'File Name *',\n 'storage.file.placeholder.edit': 'Enter file name',\n 'storage.file.placeholder': 'Will be auto-filled from selected file',\n 'storage.file.private': 'Private File',\n 'storage.file.private.hint': 'Only users with permission can access',\n 'storage.file.public.hint': 'File is publicly accessible',\n 'storage.validation.file.name.required': 'File name is required',\n 'storage.error.no.file': 'Please select a file',\n 'storage.error.no.config': 'Please select a storage configuration',\n 'storage.upload.failed': 'Failed to upload file',\n\n // pages/folder/folder-list.component.ts\n 'storage.button.new.folder': 'New Folder',\n 'storage.table.slug': 'Slug',\n 'storage.empty.folders.in.company': 'No folders found in current company',\n 'storage.empty.folders': 'No folders found',\n 'storage.folder.delete.title': 'Delete Folder',\n\n // pages/folder/folder-form.component.ts\n 'storage.folder.edit.folder': 'Edit Folder',\n 'storage.folder.new.folder': 'New Folder',\n 'storage.folder.name.required': 'Folder Name *',\n 'storage.folder.name.placeholder': 'Enter folder name',\n 'storage.validation.folder.name.required': 'Folder name is required',\n\n // utils/base-storage-page.ts\n 'storage.delete.this.item': 'this item',\n\n // utils/storage-utils.ts\n 'storage.size.bytes': 'Bytes',\n 'storage.size.gb': 'GB',\n};\n","/**\n * File Location Enum\n * Storage provider types (matches backend FileLocationEnum)\n */\nexport enum FileLocationEnum {\n LOCAL = 'local',\n AWS = 'aws',\n AZURE = 'azure',\n SFTP = 'sftp',\n}\n\n/**\n * Image Format Enum\n * Supported image output formats for compression\n */\nexport enum ImageFormat {\n ORIGINAL = 'original',\n JPEG = 'jpeg',\n PNG = 'png',\n WEBP = 'webp',\n}\n","import { FileLocationEnum } from '../enums/file-location.enum';\n\n/**\n * Storage Provider Configuration\n * Maps provider enum to display properties\n */\ninterface IProviderConfig {\n labelKey: string;\n icon: string;\n severity: 'success' | 'info' | 'warn' | 'danger' | 'secondary' | 'contrast';\n}\n\n/**\n * Provider label translation keys\n */\nexport const PROVIDER_LABEL_KEYS: Record<FileLocationEnum, string> = {\n [FileLocationEnum.LOCAL]: 'storage.local.title',\n [FileLocationEnum.AWS]: 'storage.aws.title',\n [FileLocationEnum.AZURE]: 'storage.azure.title',\n [FileLocationEnum.SFTP]: 'storage.sftp.title',\n};\n\n/**\n * Provider configurations for all storage types\n */\nconst PROVIDER_CONFIGS: Record<FileLocationEnum, IProviderConfig> = {\n [FileLocationEnum.LOCAL]: {\n labelKey: 'storage.local.title',\n icon: 'folder',\n severity: 'secondary',\n },\n [FileLocationEnum.AWS]: {\n labelKey: 'storage.aws.title',\n icon: 'cloud',\n severity: 'warn',\n },\n [FileLocationEnum.AZURE]: {\n labelKey: 'storage.azure.title',\n icon: 'cloud',\n severity: 'info',\n },\n [FileLocationEnum.SFTP]: {\n labelKey: 'storage.sftp.title',\n icon: 'server',\n severity: 'contrast',\n },\n};\n\n/**\n * Get provider label translation key\n */\nexport function getProviderLabelKey(\n storage: FileLocationEnum | string,\n): string {\n const enumValue = storage as FileLocationEnum;\n return PROVIDER_CONFIGS[enumValue]?.labelKey ?? storage;\n}\n\n/**\n * Get provider icon class\n */\nexport function getProviderIcon(storage: FileLocationEnum | string): string {\n const enumValue = storage as FileLocationEnum;\n return PROVIDER_CONFIGS[enumValue]?.icon ?? 'database';\n}\n\n/**\n * Get provider severity for f-tag\n */\nexport function getProviderSeverity(\n storage: FileLocationEnum | string,\n): 'success' | 'info' | 'warn' | 'danger' | 'secondary' | 'contrast' {\n const enumValue = storage as FileLocationEnum;\n return PROVIDER_CONFIGS[enumValue]?.severity ?? 'secondary';\n}\n\n/**\n * Get file icon based on content type\n */\nexport function getFileIcon(contentType: string): string {\n if (contentType.startsWith('image/')) return 'image';\n if (contentType.startsWith('video/')) return 'video';\n if (contentType.startsWith('audio/')) return 'volume-up';\n if (contentType.includes('pdf')) return 'file-pdf';\n if (contentType.includes('excel') || contentType.includes('spreadsheet'))\n return 'file-excel';\n if (contentType.includes('word') || contentType.includes('document'))\n return 'file-word';\n return 'file';\n}\n\n/** File size unit keys for translation */\nexport const FILE_SIZE_UNIT_KEYS = [\n 'storage.size.bytes',\n 'shared.size.kb',\n 'shared.size.mb',\n 'storage.size.gb',\n] as const;\n\n/**\n * Format file size from bytes to human readable format\n * Returns an object with value and unitKey for translation\n */\nexport function formatFileSizeWithKey(bytes: number): {\n value: string;\n unitKey: string;\n} {\n if (bytes <= 0) return { value: '0', unitKey: 'storage.size.bytes' };\n const k = 1024;\n const i = Math.min(\n Math.floor(Math.log(bytes) / Math.log(k)),\n FILE_SIZE_UNIT_KEYS.length - 1,\n );\n const value = (Math.round((bytes / Math.pow(k, i)) * 100) / 100).toString();\n return { value, unitKey: FILE_SIZE_UNIT_KEYS[i] };\n}\n\n/**\n * Format file size from bytes to human readable string\n * @deprecated Use formatFileSizeWithKey for localization support\n */\nexport function formatFileSize(bytes: number): string {\n const { value, unitKey } = formatFileSizeWithKey(bytes);\n // Fallback to non-translated units for backward compatibility\n const unitMap: Record<string, string> = {\n 'storage.size.bytes': 'Bytes',\n 'shared.size.kb': 'KB',\n 'shared.size.mb': 'MB',\n 'storage.size.gb': 'GB',\n };\n return `${value} ${unitMap[unitKey]}`;\n}\n\n/**\n * Storage provider options for dropdown selects\n * Labels are translation keys - components should translate them\n */\nexport const STORAGE_PROVIDER_OPTIONS = [\n { labelKey: 'storage.aws.title', value: FileLocationEnum.AWS },\n { labelKey: 'storage.azure.title', value: FileLocationEnum.AZURE },\n { labelKey: 'storage.sftp.title', value: FileLocationEnum.SFTP },\n { labelKey: 'storage.local.title', value: FileLocationEnum.LOCAL },\n] as const;\n\nexport type StorageProviderOption = (typeof STORAGE_PROVIDER_OPTIONS)[number];\n","import { computed, DestroyRef, Directive, inject, signal } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Router } from '@angular/router';\nimport { APP_CONFIG, DEFAULT_APP_NAME } from '@flusys/ng-core';\nimport { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';\nimport { TranslateService } from '@flusys/ng-shared';\nimport { ConfirmationService, MessageService } from '@flusys/ng-ui';\nimport { from, Observable } from 'rxjs';\n\n@Directive()\nexport abstract class BaseStoragePage {\n protected readonly router = inject(Router);\n protected readonly messageService = inject(MessageService);\n protected readonly appConfig = inject(APP_CONFIG);\n protected readonly companyContext = inject(LAYOUT_AUTH_STATE);\n protected readonly translateAdapter = inject(TranslateService);\n\n readonly isLoading = signal(false);\n readonly showCompanyInfo = computed(() => this.appConfig.enableCompanyFeature);\n readonly currentCompanyName = computed(\n () => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME,\n );\n\n protected showSuccess(detail: string, summaryKey = 'shared.success'): void {\n const summary = this.translateAdapter.translate(summaryKey);\n this.messageService.add({ severity: 'success', summary, detail });\n }\n\n protected showError(detail: string, summaryKey = 'shared.error'): void {\n const summary = this.translateAdapter.translate(summaryKey);\n this.messageService.add({ severity: 'error', summary, detail });\n }\n\n protected navigateTo(path: string[]): void {\n this.router.navigate(path);\n }\n}\n\n@Directive()\nexport abstract class BaseStorageListPage<T> {\n protected readonly router = inject(Router);\n protected readonly messageService = inject(MessageService);\n protected readonly appConfig = inject(APP_CONFIG);\n protected readonly confirmationService = inject(ConfirmationService);\n protected readonly destroyRef = inject(DestroyRef);\n protected readonly translateAdapter = inject(TranslateService);\n protected readonly companyContext = inject(LAYOUT_AUTH_STATE);\n\n readonly items = signal<T[]>([]);\n readonly isLoading = signal(false);\n readonly total = signal(0);\n readonly pageSize = signal(50);\n readonly first = signal(0);\n readonly currentPage = computed(() => Math.floor(this.first() / this.pageSize()));\n readonly showCompanyInfo = computed(() => this.appConfig.enableCompanyFeature);\n readonly totalRecords = this.total;\n readonly currentCompanyName = computed(\n () => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME,\n );\n\n abstract loadData(): Promise<void>;\n abstract getResourceRoute(): string;\n\n getDeleteConfirmMessage(item: T): string {\n const itemName = (item as { name?: string }).name;\n const name = itemName ?? this.translateAdapter.translate('storage.delete.this.item');\n return this.translateAdapter.translate('shared.confirm.delete.item', { name });\n }\n\n onCreate(): void {\n this.router.navigate([this.getResourceRoute(), 'new']);\n }\n\n onEdit(id: string): void {\n this.router.navigate([this.getResourceRoute(), id]);\n }\n\n onPageChange(event: { first?: number | null; rows?: number | null }): void {\n this.first.set(event.first ?? 0);\n this.pageSize.set(event.rows ?? 10);\n this.loadData();\n }\n\n protected getPaginationParams(): { currentPage: number; pageSize: number } {\n return { currentPage: this.currentPage(), pageSize: this.pageSize() };\n }\n\n protected showSuccess(detail: string, summary?: string): void {\n this.messageService.add({\n severity: 'success',\n summary: summary ?? this.t('shared.success'),\n detail,\n });\n }\n\n protected showError(detail: string, summary?: string): void {\n this.messageService.add({\n severity: 'error',\n summary: summary ?? this.t('shared.error'),\n detail,\n });\n }\n\n protected showInfo(detail: string, summary?: string): void {\n this.messageService.add({\n severity: 'info',\n summary: summary ?? this.t('shared.info'),\n detail,\n });\n }\n\n protected showWarn(detail: string, summary?: string): void {\n this.messageService.add({\n severity: 'warn',\n summary: summary ?? this.t('shared.warning'),\n detail,\n });\n }\n\n onDelete(\n item: T,\n idGetter: (item: T) => string,\n deleteApiCall: (id: string) => Observable<unknown> | Promise<unknown>,\n options?: { header?: string },\n ): void {\n this.confirmationService.confirm({\n message: this.getDeleteConfirmMessage(item),\n header: options?.header ?? this.t('shared.confirm.delete.header'),\n icon: 'exclamation-triangle',\n acceptButtonStyleClass: 'p-button-danger',\n accept: () => {\n from(deleteApiCall(idGetter(item)))\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({\n next: (res) => {\n const r = res as {\n messageKey?: string;\n messageVariables?: Record<string, string | number>;\n message?: string;\n };\n this.showSuccess(\n r?.messageKey ? this.t(r.messageKey, r.messageVariables) : (r?.message ?? ''),\n );\n this.loadData();\n },\n });\n },\n });\n }\n\n async onDeleteAsync(\n item: T,\n idGetter: (item: T) => string,\n deleteApiCall: (id: string) => Promise<unknown>,\n options?: { header?: string },\n ): Promise<void> {\n this.confirmationService.confirm({\n message: this.getDeleteConfirmMessage(item),\n header: options?.header ?? this.t('shared.confirm.delete.header'),\n icon: 'exclamation-triangle',\n acceptButtonStyleClass: 'p-button-danger',\n accept: async () => {\n const res = await deleteApiCall(idGetter(item));\n const r = res as {\n messageKey?: string;\n messageVariables?: Record<string, string | number>;\n message?: string;\n };\n this.showSuccess(\n r?.messageKey ? this.t(r.messageKey, r.messageVariables) : (r?.message ?? ''),\n );\n await this.loadData();\n },\n });\n }\n\n protected navigateTo(path: string[]): void {\n this.router.navigate(path);\n }\n\n protected t(key: string, variables?: Record<string, string | number>): string {\n return this.translateAdapter?.translate(key, variables) ?? key;\n }\n}\n","import { inject, Service } from '@angular/core';\nimport { from, map, Observable } from 'rxjs';\nimport {\n IFileBasicInfo,\n IFileProvider,\n IFileSelectFilter,\n IFileUploadOptions,\n IFolderBasicInfo,\n IListResponse,\n ISelectFilter,\n ISingleResponse,\n IStorageConfigBasicInfo,\n IUploadedFile,\n} from '@flusys/ng-shared';\nimport { FileManagerApiService } from '../services/file-manager-api.service';\nimport { FolderApiService } from '../services/folder-api.service';\nimport { StorageConfigApiService } from '../services/storage-config-api.service';\nimport { UploadService } from '../services/upload.service';\nimport { IFileManager } from '../interfaces/file-manager.interface';\n\n@Service({ autoProvided: false })\nexport class FileProviderAdapter implements IFileProvider {\n private readonly fileManagerApi = inject(FileManagerApiService);\n private readonly uploadService = inject(UploadService);\n private readonly folderApi = inject(FolderApiService);\n private readonly storageConfigApi = inject(StorageConfigApiService);\n\n loadFiles(filter: IFileSelectFilter): Observable<IListResponse<IFileBasicInfo>> {\n const filterObj = this.buildFileFilter(filter);\n\n return from(this.fileManagerApi\n .getAll(\n { pagination: { currentPage: filter.page, pageSize: filter.pageSize }, filter: Object.keys(filterObj).length > 0 ? filterObj : undefined },\n filter.search || '',\n ))\n .pipe(map((res) => ({ ...res, data: res.data?.map(this.mapToFileBasicInfo) })));\n }\n\n uploadFile(file: File, options?: IFileUploadOptions): Observable<ISingleResponse<IUploadedFile>> {\n return this.uploadService\n .uploadAndRegister(file, options)\n .pipe(map((res) => ({ ...res, data: res.data ? this.mapToUploadedFile(res.data) : undefined })));\n }\n\n uploadMultipleFiles(files: File[], options?: IFileUploadOptions): Observable<ISingleResponse<IUploadedFile[]>> {\n return this.uploadService\n .uploadAndRegisterMultiple(files, options)\n .pipe(map((res) => ({ ...res, data: res.data?.map(this.mapToUploadedFile) })));\n }\n\n getFileUrls(fileIds: string[]): Observable<ISingleResponse<IFileBasicInfo[]>> {\n return this.fileManagerApi.getFiles(fileIds).pipe(\n map((res) => ({\n ...res,\n data: res.data?.map((f) => ({ id: f.id, name: f.name, contentType: f.contentType, size: '0', url: f.url })),\n }))\n );\n }\n\n loadFolders(filter: ISelectFilter): Observable<IListResponse<IFolderBasicInfo>> {\n return from(this.folderApi\n .getAll(\n { pagination: { currentPage: filter.page, pageSize: filter.pageSize } },\n filter.search || '',\n ))\n .pipe(map((res) => ({ ...res, data: res.data?.map((f) => ({ id: f.id, name: f.name, slug: f.slug })) })));\n }\n\n loadStorageConfigs(filter: ISelectFilter): Observable<IListResponse<IStorageConfigBasicInfo>> {\n return from(this.storageConfigApi\n .getAll(\n { pagination: { currentPage: filter.page, pageSize: filter.pageSize } },\n filter.search || '',\n ))\n .pipe(map((res) => ({ ...res, data: res.data?.map((c) => ({ id: c.id, name: c.name, isDefault: c.isDefault })) })));\n }\n\n // ─── Private Helpers ────────────────────────────────────────────────────────\n\n private buildFileFilter(filter: IFileSelectFilter): Record<string, string> {\n const filterObj: Record<string, string> = {};\n if (filter.folderId) filterObj['folderId'] = filter.folderId;\n if (filter.storageConfigId) filterObj['storageConfigId'] = filter.storageConfigId;\n if (filter.contentTypes?.length) filterObj['contentType'] = filter.contentTypes.join(',');\n return filterObj;\n }\n\n private mapToFileBasicInfo = (f: IFileManager): IFileBasicInfo => ({\n id: f.id,\n name: f.name,\n contentType: f.contentType,\n size: f.size,\n url: f.url,\n });\n\n private mapToUploadedFile = (f: IFileManager): IUploadedFile => ({\n id: f.id,\n name: f.name,\n key: f.key,\n size: parseFloat(f.size) * 1024,\n contentType: f.contentType,\n });\n}\n","import { Provider } from '@angular/core';\nimport { FILE_PROVIDER } from '@flusys/ng-shared';\nimport { FileProviderAdapter } from '../adapters/file-provider.adapter';\n\n/**\n * Provide Storage Providers\n *\n * Registers storage-related provider implementations.\n * Call this in app.config.ts to enable storage features in other packages.\n *\n * @example\n * // In app.config.ts\n * export const appConfig: ApplicationConfig = {\n * providers: [\n * ...provideStorageProviders(),\n * ],\n * };\n *\n * @returns Array of providers for storage functionality\n */\nexport function provideStorageProviders(): Provider[] {\n return [\n {\n provide: FILE_PROVIDER,\n useClass: FileProviderAdapter,\n },\n ];\n}\n","import { inject } from '@angular/core';\nimport { Routes } from '@angular/router';\nimport {\n FILE_PERMISSIONS,\n FOLDER_PERMISSIONS,\n PermissionValidatorService,\n permissionGuard,\n STORAGE_CONFIG_PERMISSIONS,\n SHARED_MESSAGES,\n resolveTranslationModule,\n} from '@flusys/ng-shared';\nimport { STORAGE_MESSAGES } from '../constants/messages';\n\n/**\n * Resolves which storage tab the current user should land on when navigating\n * to the bare `/storage` route. Mirrors the tab visibility order in\n * StorageContainerComponent.visibleTabs so the redirect never points at a\n * tab the user can't actually see.\n */\nfunction resolveStorageDefaultTab(): string {\n const permissionValidator = inject(PermissionValidatorService);\n\n if (permissionValidator.hasPermission(FILE_PERMISSIONS.READ)) {\n return 'files';\n }\n\n if (permissionValidator.hasPermission(FOLDER_PERMISSIONS.READ)) {\n return 'folders';\n }\n\n if (permissionValidator.hasPermission(STORAGE_CONFIG_PERMISSIONS.READ)) {\n return 'configs';\n }\n\n return 'files';\n}\n\n/**\n * Storage Module Routes\n * All routes protected by permission guards\n */\nexport const STORAGE_ROUTES: Routes = [\n {\n path: '',\n resolve: { translations: resolveTranslationModule({ modules: ['storage'], fallbackMessages: { ...STORAGE_MESSAGES, ...SHARED_MESSAGES } }) },\n loadComponent: () =>\n import('../pages/storage-container/storage-container.component').then(\n (m) => m.StorageContainerComponent,\n ),\n children: [\n // File Manager Routes\n {\n path: 'files',\n canActivate: [permissionGuard(FILE_PERMISSIONS.READ)],\n children: [\n {\n path: '',\n loadComponent: () =>\n import('../pages/file-manager/file-manager-list.component').then(\n (m) => m.FileManagerListComponent,\n ),\n },\n {\n path: 'new',\n canActivate: [permissionGuard(FILE_PERMISSIONS.CREATE)],\n loadComponent: () =>\n import('../pages/file-manager/file-manager-form.component').then(\n (m) => m.FileManagerFormComponent,\n ),\n },\n {\n path: ':id',\n canActivate: [permissionGuard(FILE_PERMISSIONS.UPDATE)],\n loadComponent: () =>\n import('../pages/file-manager/file-manager-form.component').then(\n (m) => m.FileManagerFormComponent,\n ),\n },\n ],\n },\n\n // Folder Routes\n {\n path: 'folders',\n canActivate: [permissionGuard(FOLDER_PERMISSIONS.READ)],\n children: [\n {\n path: '',\n loadComponent: () =>\n import('../pages/folder/folder-list.component').then(\n (m) => m.FolderListComponent,\n ),\n },\n {\n path: 'new',\n canActivate: [permissionGuard(FOLDER_PERMISSIONS.CREATE)],\n loadComponent: () =>\n import('../pages/folder/folder-form.component').then(\n (m) => m.FolderFormComponent,\n ),\n },\n {\n path: ':id',\n canActivate: [permissionGuard(FOLDER_PERMISSIONS.UPDATE)],\n loadComponent: () =>\n import('../pages/folder/folder-form.component').then(\n (m) => m.FolderFormComponent,\n ),\n },\n ],\n },\n\n // Storage Config Routes\n {\n path: 'configs',\n canActivate: [permissionGuard(STORAGE_CONFIG_PERMISSIONS.READ)],\n children: [\n {\n path: '',\n loadComponent: () =>\n import('../pages/storage-config/storage-config-list.component').then(\n (m) => m.StorageConfigListComponent,\n ),\n },\n {\n path: 'new',\n canActivate: [permissionGuard(STORAGE_CONFIG_PERMISSIONS.CREATE)],\n loadComponent: () =>\n import('../pages/storage-config/storage-config-form.component').then(\n (m) => m.StorageConfigFormComponent,\n ),\n },\n {\n path: ':id',\n canActivate: [permissionGuard(STORAGE_CONFIG_PERMISSIONS.UPDATE)],\n loadComponent: () =>\n import('../pages/storage-config/storage-config-form.component').then(\n (m) => m.StorageConfigFormComponent,\n ),\n },\n ],\n },\n\n // Default redirect to the first tab the user has permission to see\n { path: '', redirectTo: () => resolveStorageDefaultTab(), pathMatch: 'full' },\n ],\n },\n];\n"],"mappings":"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"}
1
+ {"version":3,"file":"flusys-ng-storage.mjs","names":[],"sources":["../../../projects/ng-storage/constants/messages.ts","../../../projects/ng-storage/enums/file-location.enum.ts","../../../projects/ng-storage/utils/storage-utils.ts","../../../projects/ng-storage/utils/base-storage-page.ts","../../../projects/ng-storage/adapters/file-provider.adapter.ts","../../../projects/ng-storage/providers/storage-providers.ts","../../../projects/ng-storage/routes/storage.routes.ts"],"sourcesContent":["export const STORAGE_MESSAGES: Record<string, string> = {\n // File entity CRUD (API keys)\n 'file.create.success': 'File created successfully',\n 'file.create.many.success': '{{count}} files created successfully',\n 'file.get.success': 'File retrieved successfully',\n 'file.get.by.ids.success': 'Files retrieved successfully by Ids',\n 'file.get.by.filter.success': 'Files retrieved successfully by filter',\n 'file.get.all.success': 'Files retrieved successfully',\n 'file.update.success': 'File updated successfully',\n 'file.update.many.success': '{{count}} files updated successfully',\n 'file.delete.success': 'File deleted successfully',\n 'file.restore.success': 'File restored successfully',\n 'file.not.found': 'File not found',\n\n // Folder entity CRUD (API keys)\n 'folder.create.success': 'Folder created successfully',\n 'folder.create.many.success': '{{count}} folders created successfully',\n 'folder.get.success': 'Folder retrieved successfully',\n 'folder.get.by.ids.success': 'Folders retrieved successfully by Ids',\n 'folder.get.by.filter.success': 'Folders retrieved successfully by filter',\n 'folder.get.all.success': 'Folders retrieved successfully',\n 'folder.update.success': 'Folder updated successfully',\n 'folder.update.many.success': '{{count}} folders updated successfully',\n 'folder.delete.success': 'Folder deleted successfully',\n 'folder.restore.success': 'Folder restored successfully',\n 'folder.not.found': 'Folder not found',\n\n // Storage config CRUD (API keys)\n 'storage.config.create.success': 'Storage configuration created successfully',\n 'storage.config.create.many.success':\n '{{count}} storage configurations created successfully',\n 'storage.config.get.success': 'Storage configuration retrieved successfully',\n 'storage.config.get.by.ids.success':\n 'Storage configurations retrieved successfully by Ids',\n 'storage.config.get.by.filter.success':\n 'Storage configurations retrieved successfully by filter',\n 'storage.config.get.all.success':\n 'Storage configurations retrieved successfully',\n 'storage.config.update.success': 'Storage configuration updated successfully',\n 'storage.config.update.many.success':\n '{{count}} storage configurations updated successfully',\n 'storage.config.delete.success': 'Storage configuration deleted successfully',\n 'storage.config.restore.success':\n 'Storage configuration restored successfully',\n\n // Upload (API keys)\n 'upload.success': 'File uploaded successfully',\n 'upload.many.success': 'Files uploaded successfully',\n 'upload.file.too.large':\n 'File size ({{fileSize}}MB) exceeds maximum {{maxSize}}MB',\n 'upload.invalid.type':\n 'File type \"{{mimeType}}\" not allowed. Allowed: {{allowedTypes}}',\n 'upload.no.files.provided': 'No files provided',\n 'upload.no.file.path': 'File path is required',\n 'upload.invalid.file.path': 'Invalid file path',\n 'upload.config.not.found': 'Upload configuration not found',\n\n // pages/storage-container/storage-container.component.ts\n 'storage.title': 'Storage',\n 'storage.subtitle': 'Manage files, folders, and storage configurations',\n 'storage.file.title': 'Files',\n 'storage.folder.title': 'Folder Setup',\n 'storage.config.title': 'Storage Configurations',\n\n // pages/storage-config/storage-config-list.component.ts\n 'storage.button.new.configuration': 'New Configuration',\n 'storage.table.provider': 'Provider',\n 'storage.table.created': 'Created',\n 'storage.empty.configs.in.company':\n 'No storage configurations found in current company',\n 'storage.empty.configs': 'No storage configurations found',\n 'storage.config.load.failed': 'Failed to load storage configurations',\n 'storage.config.delete.title': 'Delete Configuration',\n 'storage.config.default.delete.forbidden':\n 'Cannot delete the default configuration. Set another as default first.',\n\n // pages/storage-config/storage-config-form.component.ts\n 'storage.config.edit.config': 'Edit Storage Configuration',\n 'storage.config.new.config': 'New Configuration',\n 'storage.config.config.name.required': 'Configuration Name *',\n 'storage.config.config.name.placeholder': 'e.g., Production AWS S3',\n 'storage.config.provider.required': 'Storage Provider *',\n 'storage.set.as.default': 'Set as Default',\n 'storage.aws.title': 'AWS S3 Configuration',\n 'storage.config.region.required': 'AWS Region *',\n 'storage.aws.region.placeholder': 'us-east-1',\n 'storage.config.bucket.required': 'Bucket Name *',\n 'storage.aws.bucket.placeholder': 'my-bucket',\n 'storage.config.access.key.required': 'Access Key ID *',\n 'storage.config.secret.key.required': 'Secret Access Key *',\n 'storage.config.endpoint.optional': 'Custom Endpoint (Optional)',\n 'storage.config.endpoint.placeholder': 'https://s3.custom-endpoint.com',\n 'storage.azure.title': 'Azure Blob Configuration',\n 'storage.azure.account.name.required': 'Account Name *',\n 'storage.azure.container.name.required': 'Container Name *',\n 'storage.azure.account.key.required': 'Account Key *',\n 'storage.sftp.title': 'SFTP Configuration',\n 'storage.sftp.host.required': 'Host *',\n 'storage.sftp.host.placeholder': 'sftp.example.com',\n 'storage.sftp.port.required': 'Port *',\n 'storage.sftp.port.placeholder': '22',\n 'storage.sftp.username.required': 'Username *',\n 'storage.sftp.password.required': 'Password *',\n 'storage.sftp.base.path.required': 'Base Path *',\n 'storage.sftp.base.path.placeholder': '/uploads',\n 'storage.local.title': 'Local Storage Configuration',\n 'storage.local.base.path.required': 'Base Path *',\n 'storage.local.base.path.placeholder': '/var/www/uploads',\n 'storage.config.endpoint': 'Endpoint URL',\n 'storage.validation.config.name.required': 'Configuration name is required',\n\n // pages/file-manager/file-manager-list.component.ts\n 'storage.file.manager.title': 'File Manager',\n 'storage.button.upload.file': 'Upload File',\n 'storage.table.size': 'Size',\n 'storage.table.location': 'Location',\n 'storage.table.config': 'Config',\n 'storage.table.private': 'Private',\n 'storage.private': 'Private',\n 'storage.public': 'Public',\n 'storage.tooltip.trash': 'Trash',\n 'storage.empty.files.in.company': 'No files found in current company',\n 'storage.empty.files': 'No files found',\n 'storage.file.url.not.available': 'File URL is not available',\n 'storage.delete.move.to.trash.confirm':\n 'Move \"{{name}}\" to trash? You can recover it later.',\n 'storage.delete.move.to.trash': 'Move to Trash',\n 'storage.delete.permanent.delete.confirm':\n 'Permanently delete \"{{name}}\"? This action CANNOT be undone and will delete the file from storage.',\n 'storage.delete.permanent.delete': 'Permanent Delete',\n 'storage.delete.permanent.delete.button': 'Delete Permanently',\n\n // pages/file-manager/file-manager-form.component.ts\n 'storage.file.manager.edit.file': 'Edit File',\n 'storage.file.manager.upload.file': 'Upload File',\n 'storage.config.select.config': 'Select storage configuration...',\n 'storage.config.no.configs':\n 'No storage configurations found. Please create one first.',\n 'storage.folder.optional': 'Folder (Optional)',\n 'storage.folder.no.folder': 'No folder (root level)',\n 'storage.folder.no.folders.available':\n 'No folders available. File will be uploaded to root level.',\n 'storage.folder.no.folders.edit': 'No folders available.',\n 'storage.file.select.required': 'Select File *',\n 'storage.button.choose.file': 'Choose File',\n 'storage.upload.drag.drop': 'Drag and drop file here or click to browse',\n 'storage.upload.max.size': 'Maximum file size: {{size}}',\n 'storage.upload.please.select': 'Please select a file to upload',\n 'storage.file.name.required': 'File Name *',\n 'storage.file.placeholder.edit': 'Enter file name',\n 'storage.file.placeholder': 'Will be auto-filled from selected file',\n 'storage.file.private': 'Private File',\n 'storage.file.private.hint': 'Only users with permission can access',\n 'storage.file.public.hint': 'File is publicly accessible',\n 'storage.validation.file.name.required': 'File name is required',\n 'storage.error.no.file': 'Please select a file',\n 'storage.error.no.config': 'Please select a storage configuration',\n 'storage.upload.failed': 'Failed to upload file',\n\n // pages/folder/folder-list.component.ts\n 'storage.button.new.folder': 'New Folder',\n 'storage.table.slug': 'Slug',\n 'storage.empty.folders.in.company': 'No folders found in current company',\n 'storage.empty.folders': 'No folders found',\n 'storage.folder.delete.title': 'Delete Folder',\n\n // pages/folder/folder-form.component.ts\n 'storage.folder.edit.folder': 'Edit Folder',\n 'storage.folder.new.folder': 'New Folder',\n 'storage.folder.name.required': 'Folder Name *',\n 'storage.folder.name.placeholder': 'Enter folder name',\n 'storage.validation.folder.name.required': 'Folder name is required',\n\n // utils/base-storage-page.ts\n 'storage.delete.this.item': 'this item',\n\n // utils/storage-utils.ts\n 'storage.size.bytes': 'Bytes',\n 'storage.size.gb': 'GB',\n};\n","/**\n * File Location Enum\n * Storage provider types (matches backend FileLocationEnum)\n */\nexport enum FileLocationEnum {\n LOCAL = 'local',\n AWS = 'aws',\n AZURE = 'azure',\n SFTP = 'sftp',\n}\n\n/**\n * Image Format Enum\n * Supported image output formats for compression\n */\nexport enum ImageFormat {\n ORIGINAL = 'original',\n JPEG = 'jpeg',\n PNG = 'png',\n WEBP = 'webp',\n}\n","import { FileLocationEnum } from '../enums/file-location.enum';\n\n/**\n * Storage Provider Configuration\n * Maps provider enum to display properties\n */\ninterface IProviderConfig {\n labelKey: string;\n icon: string;\n severity: 'success' | 'info' | 'warn' | 'danger' | 'secondary' | 'contrast';\n}\n\n/**\n * Provider label translation keys\n */\nexport const PROVIDER_LABEL_KEYS: Record<FileLocationEnum, string> = {\n [FileLocationEnum.LOCAL]: 'storage.local.title',\n [FileLocationEnum.AWS]: 'storage.aws.title',\n [FileLocationEnum.AZURE]: 'storage.azure.title',\n [FileLocationEnum.SFTP]: 'storage.sftp.title',\n};\n\n/**\n * Provider configurations for all storage types\n */\nconst PROVIDER_CONFIGS: Record<FileLocationEnum, IProviderConfig> = {\n [FileLocationEnum.LOCAL]: {\n labelKey: 'storage.local.title',\n icon: 'folder',\n severity: 'secondary',\n },\n [FileLocationEnum.AWS]: {\n labelKey: 'storage.aws.title',\n icon: 'cloud',\n severity: 'warn',\n },\n [FileLocationEnum.AZURE]: {\n labelKey: 'storage.azure.title',\n icon: 'cloud',\n severity: 'info',\n },\n [FileLocationEnum.SFTP]: {\n labelKey: 'storage.sftp.title',\n icon: 'server',\n severity: 'contrast',\n },\n};\n\n/**\n * Get provider label translation key\n */\nexport function getProviderLabelKey(\n storage: FileLocationEnum | string,\n): string {\n const enumValue = storage as FileLocationEnum;\n return PROVIDER_CONFIGS[enumValue]?.labelKey ?? storage;\n}\n\n/**\n * Get provider icon class\n */\nexport function getProviderIcon(storage: FileLocationEnum | string): string {\n const enumValue = storage as FileLocationEnum;\n return PROVIDER_CONFIGS[enumValue]?.icon ?? 'database';\n}\n\n/**\n * Get provider severity for f-tag\n */\nexport function getProviderSeverity(\n storage: FileLocationEnum | string,\n): 'success' | 'info' | 'warn' | 'danger' | 'secondary' | 'contrast' {\n const enumValue = storage as FileLocationEnum;\n return PROVIDER_CONFIGS[enumValue]?.severity ?? 'secondary';\n}\n\n/**\n * Get file icon based on content type\n */\nexport function getFileIcon(contentType: string): string {\n if (contentType.startsWith('image/')) return 'image';\n if (contentType.startsWith('video/')) return 'video';\n if (contentType.startsWith('audio/')) return 'volume-up';\n if (contentType.includes('pdf')) return 'file-pdf';\n if (contentType.includes('excel') || contentType.includes('spreadsheet'))\n return 'file-excel';\n if (contentType.includes('word') || contentType.includes('document'))\n return 'file-word';\n return 'file';\n}\n\n/** File size unit keys for translation */\nexport const FILE_SIZE_UNIT_KEYS = [\n 'storage.size.bytes',\n 'shared.size.kb',\n 'shared.size.mb',\n 'storage.size.gb',\n] as const;\n\n/**\n * Format file size from bytes to human readable format\n * Returns an object with value and unitKey for translation\n */\nexport function formatFileSizeWithKey(bytes: number): {\n value: string;\n unitKey: string;\n} {\n if (bytes <= 0) return { value: '0', unitKey: 'storage.size.bytes' };\n const k = 1024;\n const i = Math.min(\n Math.max(0, Math.floor(Math.log(bytes) / Math.log(k))),\n FILE_SIZE_UNIT_KEYS.length - 1,\n );\n const value = (Math.round((bytes / Math.pow(k, i)) * 100) / 100).toString();\n return { value, unitKey: FILE_SIZE_UNIT_KEYS[i] };\n}\n\n/**\n * Format file size from bytes to human readable string\n * @deprecated Use formatFileSizeWithKey for localization support\n */\nexport function formatFileSize(bytes: number): string {\n const { value, unitKey } = formatFileSizeWithKey(bytes);\n // Fallback to non-translated units for backward compatibility\n const unitMap: Record<string, string> = {\n 'storage.size.bytes': 'Bytes',\n 'shared.size.kb': 'KB',\n 'shared.size.mb': 'MB',\n 'storage.size.gb': 'GB',\n };\n return `${value} ${unitMap[unitKey]}`;\n}\n\n/**\n * Storage provider options for dropdown selects\n * Labels are translation keys - components should translate them\n */\nexport const STORAGE_PROVIDER_OPTIONS = [\n { labelKey: 'storage.aws.title', value: FileLocationEnum.AWS },\n { labelKey: 'storage.azure.title', value: FileLocationEnum.AZURE },\n { labelKey: 'storage.sftp.title', value: FileLocationEnum.SFTP },\n { labelKey: 'storage.local.title', value: FileLocationEnum.LOCAL },\n] as const;\n\nexport type StorageProviderOption = (typeof STORAGE_PROVIDER_OPTIONS)[number];\n","import { computed, DestroyRef, Directive, inject, signal } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Router } from '@angular/router';\nimport { APP_CONFIG, DEFAULT_APP_NAME } from '@flusys/ng-core';\nimport { LAYOUT_AUTH_STATE } from '@flusys/ng-layout';\nimport { TranslateService } from '@flusys/ng-shared';\nimport { ConfirmationService, MessageService } from '@flusys/ng-ui';\nimport { from, Observable } from 'rxjs';\n\n@Directive()\nexport abstract class BaseStoragePage {\n protected readonly router = inject(Router);\n protected readonly messageService = inject(MessageService);\n protected readonly appConfig = inject(APP_CONFIG);\n protected readonly companyContext = inject(LAYOUT_AUTH_STATE);\n protected readonly translateAdapter = inject(TranslateService);\n\n readonly isLoading = signal(false);\n readonly showCompanyInfo = computed(() => this.appConfig.enableCompanyFeature);\n readonly currentCompanyName = computed(\n () => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME,\n );\n\n protected showSuccess(detail: string, summaryKey = 'shared.success'): void {\n const summary = this.translateAdapter.translate(summaryKey);\n this.messageService.add({ severity: 'success', summary, detail });\n }\n\n protected showError(detail: string, summaryKey = 'shared.error'): void {\n const summary = this.translateAdapter.translate(summaryKey);\n this.messageService.add({ severity: 'error', summary, detail });\n }\n\n protected navigateTo(path: string[]): void {\n this.router.navigate(path);\n }\n}\n\n@Directive()\nexport abstract class BaseStorageListPage<T> {\n protected readonly router = inject(Router);\n protected readonly messageService = inject(MessageService);\n protected readonly appConfig = inject(APP_CONFIG);\n protected readonly confirmationService = inject(ConfirmationService);\n protected readonly destroyRef = inject(DestroyRef);\n protected readonly translateAdapter = inject(TranslateService);\n protected readonly companyContext = inject(LAYOUT_AUTH_STATE);\n\n readonly items = signal<T[]>([]);\n readonly isLoading = signal(false);\n readonly total = signal(0);\n readonly pageSize = signal(50);\n readonly first = signal(0);\n readonly currentPage = computed(() => Math.floor(this.first() / this.pageSize()));\n readonly showCompanyInfo = computed(() => this.appConfig.enableCompanyFeature);\n readonly totalRecords = this.total;\n readonly currentCompanyName = computed(\n () => this.companyContext.currentCompanyInfo()?.name ?? DEFAULT_APP_NAME,\n );\n\n private loadToken = 0;\n\n abstract loadData(): Promise<void>;\n abstract getResourceRoute(): string;\n\n getDeleteConfirmMessage(item: T): string {\n const itemName = (item as { name?: string }).name;\n const name = itemName ?? this.translateAdapter.translate('storage.delete.this.item');\n return this.translateAdapter.translate('shared.confirm.delete.item', { name });\n }\n\n onCreate(): void {\n this.router.navigate([this.getResourceRoute(), 'new']);\n }\n\n onEdit(id: string): void {\n this.router.navigate([this.getResourceRoute(), id]);\n }\n\n onPageChange(event: { first?: number | null; rows?: number | null }): void {\n this.first.set(event.first ?? 0);\n this.pageSize.set(event.rows ?? 10);\n this.loadData();\n }\n\n protected beginLoad(): number {\n return ++this.loadToken;\n }\n\n protected isLatestLoad(token: number): boolean {\n return token === this.loadToken;\n }\n\n protected getPaginationParams(): { currentPage: number; pageSize: number } {\n return { currentPage: this.currentPage(), pageSize: this.pageSize() };\n }\n\n protected showSuccess(detail: string, summary?: string): void {\n this.messageService.add({\n severity: 'success',\n summary: summary ?? this.t('shared.success'),\n detail,\n });\n }\n\n protected showError(detail: string, summary?: string): void {\n this.messageService.add({\n severity: 'error',\n summary: summary ?? this.t('shared.error'),\n detail,\n });\n }\n\n protected showInfo(detail: string, summary?: string): void {\n this.messageService.add({\n severity: 'info',\n summary: summary ?? this.t('shared.info'),\n detail,\n });\n }\n\n protected showWarn(detail: string, summary?: string): void {\n this.messageService.add({\n severity: 'warn',\n summary: summary ?? this.t('shared.warning'),\n detail,\n });\n }\n\n onDelete(\n item: T,\n idGetter: (item: T) => string,\n deleteApiCall: (id: string) => Observable<unknown> | Promise<unknown>,\n options?: { header?: string },\n ): void {\n this.confirmationService.confirm({\n message: this.getDeleteConfirmMessage(item),\n header: options?.header ?? this.t('shared.confirm.delete.header'),\n icon: 'exclamation-triangle',\n acceptButtonStyleClass: 'p-button-danger',\n accept: () => {\n from(deleteApiCall(idGetter(item)))\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({\n next: (res) => {\n const r = res as {\n messageKey?: string;\n messageVariables?: Record<string, string | number>;\n message?: string;\n };\n this.showSuccess(\n r?.messageKey ? this.t(r.messageKey, r.messageVariables) : (r?.message ?? ''),\n );\n this.loadData();\n },\n });\n },\n });\n }\n\n async onDeleteAsync(\n item: T,\n idGetter: (item: T) => string,\n deleteApiCall: (id: string) => Promise<unknown>,\n options?: { header?: string },\n ): Promise<void> {\n this.confirmationService.confirm({\n message: this.getDeleteConfirmMessage(item),\n header: options?.header ?? this.t('shared.confirm.delete.header'),\n icon: 'exclamation-triangle',\n acceptButtonStyleClass: 'p-button-danger',\n accept: async () => {\n const res = await deleteApiCall(idGetter(item));\n const r = res as {\n messageKey?: string;\n messageVariables?: Record<string, string | number>;\n message?: string;\n };\n this.showSuccess(\n r?.messageKey ? this.t(r.messageKey, r.messageVariables) : (r?.message ?? ''),\n );\n await this.loadData();\n },\n });\n }\n\n protected navigateTo(path: string[]): void {\n this.router.navigate(path);\n }\n\n protected t(key: string, variables?: Record<string, string | number>): string {\n return this.translateAdapter?.translate(key, variables) ?? key;\n }\n}\n","import { inject, Service } from '@angular/core';\nimport { from, map, Observable } from 'rxjs';\nimport {\n IFileBasicInfo,\n IFileProvider,\n IFileSelectFilter,\n IFileUploadOptions,\n IFolderBasicInfo,\n IListResponse,\n ISelectFilter,\n ISingleResponse,\n IStorageConfigBasicInfo,\n IUploadedFile,\n} from '@flusys/ng-shared';\nimport { FileManagerApiService } from '../services/file-manager-api.service';\nimport { FolderApiService } from '../services/folder-api.service';\nimport { StorageConfigApiService } from '../services/storage-config-api.service';\nimport { UploadService } from '../services/upload.service';\nimport { IFileManager } from '../interfaces/file-manager.interface';\n\n@Service({ autoProvided: false })\nexport class FileProviderAdapter implements IFileProvider {\n private readonly fileManagerApi = inject(FileManagerApiService);\n private readonly uploadService = inject(UploadService);\n private readonly folderApi = inject(FolderApiService);\n private readonly storageConfigApi = inject(StorageConfigApiService);\n\n loadFiles(filter: IFileSelectFilter): Observable<IListResponse<IFileBasicInfo>> {\n const filterObj = this.buildFileFilter(filter);\n\n return from(this.fileManagerApi\n .getAll(\n { pagination: { currentPage: filter.page, pageSize: filter.pageSize }, filter: Object.keys(filterObj).length > 0 ? filterObj : undefined },\n filter.search || '',\n ))\n .pipe(map((res) => ({ ...res, data: res.data?.map(this.mapToFileBasicInfo) })));\n }\n\n uploadFile(file: File, options?: IFileUploadOptions): Observable<ISingleResponse<IUploadedFile>> {\n return this.uploadService\n .uploadAndRegister(file, options)\n .pipe(map((res) => ({ ...res, data: res.data ? this.mapToUploadedFile(res.data) : undefined })));\n }\n\n uploadMultipleFiles(files: File[], options?: IFileUploadOptions): Observable<ISingleResponse<IUploadedFile[]>> {\n return this.uploadService\n .uploadAndRegisterMultiple(files, options)\n .pipe(map((res) => ({ ...res, data: res.data?.map(this.mapToUploadedFile) })));\n }\n\n getFileUrls(fileIds: string[]): Observable<ISingleResponse<IFileBasicInfo[]>> {\n return this.fileManagerApi.getFiles(fileIds).pipe(\n map((res) => ({\n ...res,\n data: res.data?.map((f) => ({ id: f.id, name: f.name, contentType: f.contentType, size: '0', url: f.url })),\n }))\n );\n }\n\n loadFolders(filter: ISelectFilter): Observable<IListResponse<IFolderBasicInfo>> {\n return from(this.folderApi\n .getAll(\n { pagination: { currentPage: filter.page, pageSize: filter.pageSize } },\n filter.search || '',\n ))\n .pipe(map((res) => ({ ...res, data: res.data?.map((f) => ({ id: f.id, name: f.name, slug: f.slug })) })));\n }\n\n loadStorageConfigs(filter: ISelectFilter): Observable<IListResponse<IStorageConfigBasicInfo>> {\n return from(this.storageConfigApi\n .getAll(\n { pagination: { currentPage: filter.page, pageSize: filter.pageSize } },\n filter.search || '',\n ))\n .pipe(map((res) => ({ ...res, data: res.data?.map((c) => ({ id: c.id, name: c.name, isDefault: c.isDefault })) })));\n }\n\n // ─── Private Helpers ────────────────────────────────────────────────────────\n\n private buildFileFilter(filter: IFileSelectFilter): Record<string, string> {\n const filterObj: Record<string, string> = {};\n if (filter.folderId) filterObj['folderId'] = filter.folderId;\n if (filter.storageConfigId) filterObj['storageConfigId'] = filter.storageConfigId;\n if (filter.contentTypes?.length) filterObj['contentType'] = filter.contentTypes.join(',');\n return filterObj;\n }\n\n private mapToFileBasicInfo = (f: IFileManager): IFileBasicInfo => ({\n id: f.id,\n name: f.name,\n contentType: f.contentType,\n size: f.size,\n url: f.url,\n });\n\n private mapToUploadedFile = (f: IFileManager): IUploadedFile => ({\n id: f.id,\n name: f.name,\n key: f.key,\n size: parseFloat(f.size) * 1024,\n contentType: f.contentType,\n });\n}\n","import { Provider } from '@angular/core';\nimport { FILE_PROVIDER } from '@flusys/ng-shared';\nimport { FileProviderAdapter } from '../adapters/file-provider.adapter';\n\n/**\n * Provide Storage Providers\n *\n * Registers storage-related provider implementations.\n * Call this in app.config.ts to enable storage features in other packages.\n *\n * @example\n * // In app.config.ts\n * export const appConfig: ApplicationConfig = {\n * providers: [\n * ...provideStorageProviders(),\n * ],\n * };\n *\n * @returns Array of providers for storage functionality\n */\nexport function provideStorageProviders(): Provider[] {\n return [\n {\n provide: FILE_PROVIDER,\n useClass: FileProviderAdapter,\n },\n ];\n}\n","import { inject } from '@angular/core';\nimport { Routes } from '@angular/router';\nimport {\n FILE_PERMISSIONS,\n FOLDER_PERMISSIONS,\n PermissionValidatorService,\n permissionGuard,\n STORAGE_CONFIG_PERMISSIONS,\n SHARED_MESSAGES,\n resolveTranslationModule,\n} from '@flusys/ng-shared';\nimport { STORAGE_MESSAGES } from '../constants/messages';\n\n/**\n * Resolves which storage tab the current user should land on when navigating\n * to the bare `/storage` route. Mirrors the tab visibility order in\n * StorageContainerComponent.visibleTabs so the redirect never points at a\n * tab the user can't actually see.\n */\nfunction resolveStorageDefaultTab(): string {\n const permissionValidator = inject(PermissionValidatorService);\n\n if (permissionValidator.hasPermission(FILE_PERMISSIONS.READ)) {\n return 'files';\n }\n\n if (permissionValidator.hasPermission(FOLDER_PERMISSIONS.READ)) {\n return 'folders';\n }\n\n if (permissionValidator.hasPermission(STORAGE_CONFIG_PERMISSIONS.READ)) {\n return 'configs';\n }\n\n return 'files';\n}\n\n/**\n * Storage Module Routes\n * All routes protected by permission guards\n */\nexport const STORAGE_ROUTES: Routes = [\n {\n path: '',\n resolve: { translations: resolveTranslationModule({ modules: ['storage'], fallbackMessages: { ...STORAGE_MESSAGES, ...SHARED_MESSAGES } }) },\n loadComponent: () =>\n import('../pages/storage-container/storage-container.component').then(\n (m) => m.StorageContainerComponent,\n ),\n children: [\n // File Manager Routes\n {\n path: 'files',\n canActivate: [permissionGuard(FILE_PERMISSIONS.READ)],\n children: [\n {\n path: '',\n loadComponent: () =>\n import('../pages/file-manager/file-manager-list.component').then(\n (m) => m.FileManagerListComponent,\n ),\n },\n {\n path: 'new',\n canActivate: [permissionGuard(FILE_PERMISSIONS.CREATE)],\n loadComponent: () =>\n import('../pages/file-manager/file-manager-form.component').then(\n (m) => m.FileManagerFormComponent,\n ),\n },\n {\n path: ':id',\n canActivate: [permissionGuard(FILE_PERMISSIONS.UPDATE)],\n loadComponent: () =>\n import('../pages/file-manager/file-manager-form.component').then(\n (m) => m.FileManagerFormComponent,\n ),\n },\n ],\n },\n\n // Folder Routes\n {\n path: 'folders',\n canActivate: [permissionGuard(FOLDER_PERMISSIONS.READ)],\n children: [\n {\n path: '',\n loadComponent: () =>\n import('../pages/folder/folder-list.component').then(\n (m) => m.FolderListComponent,\n ),\n },\n {\n path: 'new',\n canActivate: [permissionGuard(FOLDER_PERMISSIONS.CREATE)],\n loadComponent: () =>\n import('../pages/folder/folder-form.component').then(\n (m) => m.FolderFormComponent,\n ),\n },\n {\n path: ':id',\n canActivate: [permissionGuard(FOLDER_PERMISSIONS.UPDATE)],\n loadComponent: () =>\n import('../pages/folder/folder-form.component').then(\n (m) => m.FolderFormComponent,\n ),\n },\n ],\n },\n\n // Storage Config Routes\n {\n path: 'configs',\n canActivate: [permissionGuard(STORAGE_CONFIG_PERMISSIONS.READ)],\n children: [\n {\n path: '',\n loadComponent: () =>\n import('../pages/storage-config/storage-config-list.component').then(\n (m) => m.StorageConfigListComponent,\n ),\n },\n {\n path: 'new',\n canActivate: [permissionGuard(STORAGE_CONFIG_PERMISSIONS.CREATE)],\n loadComponent: () =>\n import('../pages/storage-config/storage-config-form.component').then(\n (m) => m.StorageConfigFormComponent,\n ),\n },\n {\n path: ':id',\n canActivate: [permissionGuard(STORAGE_CONFIG_PERMISSIONS.UPDATE)],\n loadComponent: () =>\n import('../pages/storage-config/storage-config-form.component').then(\n (m) => m.StorageConfigFormComponent,\n ),\n },\n ],\n },\n\n // Default redirect to the first tab the user has permission to see\n { path: '', redirectTo: () => resolveStorageDefaultTab(), pathMatch: 'full' },\n ],\n },\n];\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flusys/ng-storage",
3
- "version": "9.1.2",
3
+ "version": "9.2.0",
4
4
  "description": "File storage module for FLUSYS Angular applications",
5
5
  "license": "MIT",
6
6
  "peerDependencies": {
@@ -8,10 +8,10 @@
8
8
  "@angular/core": ">=22.0.0",
9
9
  "@angular/forms": ">=22.0.0",
10
10
  "@angular/router": ">=22.0.0",
11
- "@flusys/ng-core": ">=9.1.2",
12
- "@flusys/ng-layout": ">=9.1.2",
13
- "@flusys/ng-shared": ">=9.1.2",
14
- "@flusys/ng-ui": ">=9.1.2",
11
+ "@flusys/ng-core": ">=9.2.0",
12
+ "@flusys/ng-layout": ">=9.2.0",
13
+ "@flusys/ng-shared": ">=9.2.0",
14
+ "@flusys/ng-ui": ">=9.2.0",
15
15
  "rxjs": "^7.8.0"
16
16
  },
17
17
  "dependencies": {
@@ -242,6 +242,7 @@ export declare abstract class BaseStorageListPage<T> {
242
242
  readonly showCompanyInfo: import("@angular/core").Signal<boolean>;
243
243
  readonly totalRecords: import("@angular/core").WritableSignal<number>;
244
244
  readonly currentCompanyName: import("@angular/core").Signal<string>;
245
+ private loadToken;
245
246
  abstract loadData(): Promise<void>;
246
247
  abstract getResourceRoute(): string;
247
248
  getDeleteConfirmMessage(item: T): string;
@@ -251,6 +252,8 @@ export declare abstract class BaseStorageListPage<T> {
251
252
  first?: number | null;
252
253
  rows?: number | null;
253
254
  }): void;
255
+ protected beginLoad(): number;
256
+ protected isLatestLoad(token: number): boolean;
254
257
  protected getPaginationParams(): {
255
258
  currentPage: number;
256
259
  pageSize: number;