@memberjunction/ng-file-storage 6.2.0-edge.0 → 6.2.0-edge.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/lib/admin/storage-admin-dialog.component.d.ts +1 -1
  2. package/dist/lib/admin/storage-admin-dialog.component.js +2 -2
  3. package/dist/lib/admin/storage-admin-dialog.component.js.map +1 -1
  4. package/dist/lib/category-tree/category-tree.d.ts +83 -9
  5. package/dist/lib/category-tree/category-tree.d.ts.map +1 -1
  6. package/dist/lib/category-tree/category-tree.js +192 -50
  7. package/dist/lib/category-tree/category-tree.js.map +1 -1
  8. package/dist/lib/file-browser/file-browser.component.d.ts +30 -4
  9. package/dist/lib/file-browser/file-browser.component.d.ts.map +1 -1
  10. package/dist/lib/file-browser/file-browser.component.js +68 -16
  11. package/dist/lib/file-browser/file-browser.component.js.map +1 -1
  12. package/dist/lib/file-browser/file-grid.component.d.ts +404 -58
  13. package/dist/lib/file-browser/file-grid.component.d.ts.map +1 -1
  14. package/dist/lib/file-browser/file-grid.component.js +1040 -396
  15. package/dist/lib/file-browser/file-grid.component.js.map +1 -1
  16. package/dist/lib/file-browser/folder-tree.component.d.ts +65 -9
  17. package/dist/lib/file-browser/folder-tree.component.d.ts.map +1 -1
  18. package/dist/lib/file-browser/folder-tree.component.js +166 -58
  19. package/dist/lib/file-browser/folder-tree.component.js.map +1 -1
  20. package/dist/lib/file-browser/storage-providers-list.component.d.ts +55 -7
  21. package/dist/lib/file-browser/storage-providers-list.component.d.ts.map +1 -1
  22. package/dist/lib/file-browser/storage-providers-list.component.js +124 -34
  23. package/dist/lib/file-browser/storage-providers-list.component.js.map +1 -1
  24. package/dist/lib/file-upload/file-upload.d.ts +22 -2
  25. package/dist/lib/file-upload/file-upload.d.ts.map +1 -1
  26. package/dist/lib/file-upload/file-upload.js +40 -10
  27. package/dist/lib/file-upload/file-upload.js.map +1 -1
  28. package/dist/lib/files-grid/files-grid.d.ts +28 -4
  29. package/dist/lib/files-grid/files-grid.d.ts.map +1 -1
  30. package/dist/lib/files-grid/files-grid.js +71 -23
  31. package/dist/lib/files-grid/files-grid.js.map +1 -1
  32. package/dist/lib/record-attachments/record-attachments.component.d.ts +15 -7
  33. package/dist/lib/record-attachments/record-attachments.component.d.ts.map +1 -1
  34. package/dist/lib/record-attachments/record-attachments.component.js +34 -18
  35. package/dist/lib/record-attachments/record-attachments.component.js.map +1 -1
  36. package/package.json +13 -13
@@ -1 +1 @@
1
- {"version":3,"file":"folder-tree.component.js","sourceRoot":"","sources":["../../../src/lib/file-browser/folder-tree.component.ts","../../../src/lib/file-browser/folder-tree.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, Input, Output, ChangeDetectorRef, inject } from '@angular/core';\nimport { GraphQLDataProvider, GraphQLFileStorageClient } from '@memberjunction/graphql-dataprovider';\nimport { StorageAccountWithProvider } from '@memberjunction/core-entities';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n/**\n * Represents a breadcrumb item in the path\n */\nexport interface BreadcrumbItem {\n label: string;\n path: string;\n}\n\n/**\n * Represents a folder in the tree\n */\nexport interface FolderItem {\n name: string;\n fullPath: string;\n}\n\n/**\n * Folder tree navigation component with breadcrumbs and history navigation.\n * Provides Mac Finder-style navigation with back/forward buttons and breadcrumb path.\n * Loads actual folder structure from storage accounts via GraphQL.\n */\n@Component({\n standalone: false,\n selector: 'mj-folder-tree',\n templateUrl: './folder-tree.component.html',\n styleUrls: ['./folder-tree.component.css']\n})\nexport class FolderTreeComponent {\n /**\n * GraphQL client for file storage operations\n */\n private storageClient: GraphQLFileStorageClient;\n\n /**\n * Currently selected storage account with provider details\n */\n private _account: StorageAccountWithProvider | null = null;\n\n constructor() {\n this.storageClient = new GraphQLFileStorageClient(GraphQLDataProvider.Instance);\n }\n\n @Input()\n set account(value: StorageAccountWithProvider | null) {\n const previousAccount = this._account;\n this._account = value;\n\n if (value && !UUIDsEqual(value.account.ID, previousAccount?.account.ID)) {\n this.resetNavigation();\n this.loadFolders();\n }\n }\n get account(): StorageAccountWithProvider | null {\n return this._account;\n }\n\n /**\n * Emits when a folder is selected in the tree\n */\n @Output() folderSelected = new EventEmitter<string>();\n\n /**\n * Current folder path\n */\n public currentPath: string = '/';\n\n /**\n * Navigation history (for back button)\n */\n public history: string[] = [];\n\n /**\n * Current position in history\n */\n public historyIndex: number = -1;\n\n /**\n * Breadcrumb items for current path\n */\n public breadcrumbs: BreadcrumbItem[] = [];\n\n /**\n * Folders in current path\n */\n public folders: FolderItem[] = [];\n\n private cdr = inject(ChangeDetectorRef);\n\n /**\n * Loading state\n */\n public isLoading: boolean = false;\n\n /**\n * Error message\n */\n public errorMessage: string | null = null;\n\n /**\n * Resets navigation when provider changes\n */\n private resetNavigation(): void {\n this.currentPath = '/';\n this.history = ['/'];\n this.historyIndex = 0;\n this.updateBreadcrumbs();\n }\n\n /**\n * Navigates to a specific folder path\n */\n public navigateToPath(path: string): void {\n // Don't navigate if already at this path\n if (path === this.currentPath) {\n return;\n }\n\n // Add to history if navigating from user action (not back/forward)\n if (this.historyIndex === this.history.length - 1) {\n this.history.push(path);\n this.historyIndex = this.history.length - 1;\n } else {\n // Navigating from middle of history - truncate forward history\n this.history = this.history.slice(0, this.historyIndex + 1);\n this.history.push(path);\n this.historyIndex = this.history.length - 1;\n }\n\n this.currentPath = path;\n this.updateBreadcrumbs();\n this.loadFolders();\n this.folderSelected.emit(path);\n }\n\n /**\n * Refreshes the current folder view without changing navigation\n * Used when folder structure changes (e.g., folder deleted) but we're staying in the same location\n */\n public refresh(): void {\n this.loadFolders();\n }\n\n /**\n * Navigates back in history\n */\n public navigateBack(): void {\n if (!this.canGoBack()) {\n return;\n }\n\n this.historyIndex--;\n this.currentPath = this.history[this.historyIndex];\n this.updateBreadcrumbs();\n this.folderSelected.emit(this.currentPath);\n this.loadFolders();\n }\n\n /**\n * Navigates forward in history\n */\n public navigateForward(): void {\n if (!this.canGoForward()) {\n return;\n }\n\n this.historyIndex++;\n this.currentPath = this.history[this.historyIndex];\n this.updateBreadcrumbs();\n this.folderSelected.emit(this.currentPath);\n this.loadFolders();\n }\n\n /**\n * Checks if can navigate back\n */\n public canGoBack(): boolean {\n return this.historyIndex > 0;\n }\n\n /**\n * Checks if can navigate forward\n */\n public canGoForward(): boolean {\n return this.historyIndex < this.history.length - 1;\n }\n\n /**\n * Updates breadcrumbs based on current path\n */\n private updateBreadcrumbs(): void {\n if (!this.account) {\n this.breadcrumbs = [];\n return;\n }\n\n // Start with account root (show account name)\n const items: BreadcrumbItem[] = [\n {\n label: this.account.account.Name,\n path: '/'\n }\n ];\n\n // Add path segments if not at root\n if (this.currentPath !== '/') {\n const segments = this.currentPath.split('/').filter(s => s.length > 0);\n let builtPath = '';\n\n for (const segment of segments) {\n builtPath += '/' + segment;\n items.push({\n label: segment,\n path: builtPath\n });\n }\n }\n\n this.breadcrumbs = items;\n }\n\n /**\n * Handles breadcrumb click\n */\n public onBreadcrumbClick(item: BreadcrumbItem): void {\n this.navigateToPath(item.path);\n this.loadFolders();\n }\n\n /**\n * Loads folders from the storage account for the current path\n */\n private async loadFolders(): Promise<void> {\n if (!this.account) {\n this.folders = [];\n return;\n }\n\n this.isLoading = true;\n this.errorMessage = null;\n this.cdr.detectChanges();\n\n try {\n // Blob keys (Azure/S3) have NO leading slash and use a trailing slash to denote a\n // directory prefix. currentPath is stored with a leading slash (e.g. \"/test\"), which\n // never matches real keys — so nested-folder listings came back empty (empty folder\n // names). Normalize to a slash-free, trailing-slash prefix before listing.\n const rawPath = this.currentPath && this.currentPath !== '/' ? this.currentPath : '';\n const listPrefix = rawPath ? rawPath.replace(/^\\/+/, '').replace(/\\/+$/, '') + '/' : '';\n const listResult = await this.storageClient.ListObjects(\n this.account.account.ID,\n listPrefix,\n '/'\n );\n\n // Convert prefixes to FolderItems\n const prefixes = listResult.prefixes || [];\n this.folders = prefixes.map((prefix: string) => {\n // Remove trailing slash and get just the folder name\n const cleanPath = prefix.endsWith('/') ? prefix.slice(0, -1) : prefix;\n const name = cleanPath.split('/').pop() || cleanPath;\n\n return {\n name,\n fullPath: prefix\n };\n });\n } catch (error) {\n console.error('Error loading folders:', error);\n this.errorMessage = error instanceof Error ? error.message : 'Failed to load folders';\n this.folders = [];\n } finally {\n this.isLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Handles folder click for navigation\n */\n public onFolderClick(folder: FolderItem): void {\n this.navigateToPath(folder.fullPath);\n this.loadFolders();\n }\n}\n","<div class=\"folder-tree\">\n <!-- Navigation bar with back/forward buttons and breadcrumbs -->\n @if (account) {\n <div class=\"navigation-bar\">\n <!-- Back/Forward buttons -->\n <div class=\"nav-buttons\">\n <button\n type=\"button\"\n [disabled]=\"!canGoBack()\"\n (click)=\"navigateBack()\"\n title=\"Go back\"\n class=\"nav-button\">\n <i class=\"fa-solid fa-chevron-left\"></i>\n </button>\n <button\n type=\"button\"\n [disabled]=\"!canGoForward()\"\n (click)=\"navigateForward()\"\n title=\"Go forward\"\n class=\"nav-button\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </button>\n </div>\n <!-- Breadcrumb path -->\n <div class=\"breadcrumbs\">\n @for (item of breadcrumbs; track item.path; let last = $last) {\n <button\n type=\"button\"\n (click)=\"onBreadcrumbClick(item)\"\n [class.current]=\"last\"\n class=\"breadcrumb-item\">\n {{ item.label }}\n </button>\n @if (!last) {\n <i class=\"fa-solid fa-chevron-right breadcrumb-separator\"></i>\n }\n }\n </div>\n </div>\n }\n\n <!-- Folder tree content -->\n <div class=\"tree-content\">\n <!-- Loading state -->\n @if (isLoading) {\n <div class=\"tree-loading\">\n <mj-loading text=\"Loading folders...\"></mj-loading>\n </div>\n }\n\n <!-- Error state -->\n @if (errorMessage && !isLoading) {\n <div class=\"tree-error\">\n <i class=\"fa-solid fa-triangle-exclamation error-icon\"></i>\n <p class=\"error-text\">{{ errorMessage }}</p>\n </div>\n }\n\n <!-- Folder list -->\n @if (!isLoading && !errorMessage) {\n <div class=\"folder-list\">\n @for (folder of folders; track folder.name) {\n <div\n class=\"folder-item\"\n (click)=\"onFolderClick(folder)\"\n [title]=\"folder.name\">\n <i class=\"fa-solid fa-folder folder-icon\"></i>\n <span class=\"folder-name\">{{ folder.name }}</span>\n </div>\n }\n <!-- Empty state -->\n @if (folders.length === 0) {\n <div class=\"tree-placeholder\">\n <i class=\"fa-solid fa-folder-open placeholder-icon\"></i>\n <p class=\"placeholder-text\">No folders in this location</p>\n @if (account) {\n <p class=\"placeholder-hint\">Account: {{ account.account.Name }}</p>\n }\n <p class=\"placeholder-hint\">Path: {{ currentPath }}</p>\n </div>\n }\n </div>\n }\n </div>\n</div>\n"]}
1
+ {"version":3,"file":"folder-tree.component.js","sourceRoot":"","sources":["../../../src/lib/file-browser/folder-tree.component.ts","../../../src/lib/file-browser/folder-tree.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAClG,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAErG,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;;;;;;IC+BxC,wBAA8D;;;;IARhE,kCAI0B;IAFxB,wNAAS,iCAAuB,KAAC;IAGjC,YACF;IAAA,iBAAS;IACT,wGAAa;;;;;IAJX,8DAAsB;IAEtB,cACF;IADE,8CACF;IACA,cAEC;IAFD,iEAEC;;;;IA7BH,AADF,AAFF,8BAA4B,aAED,gBAMF;IAFnB,uLAAS,qBAAc,KAAC;IAGxB,uBAAwC;IAC1C,iBAAS;IACT,iCAKqB;IAFnB,uLAAS,wBAAiB,KAAC;IAG3B,wBAAyC;IAE7C,AADE,iBAAS,EACL;IAEN,+BAAyB;IACvB,sGAWC;IAEL,AADE,iBAAM,EACF;;;IA9BA,eAAyB;IAAzB,8CAAyB;IAQzB,eAA4B;IAA5B,iDAA4B;IAS9B,eAWC;IAXD,iCAWC;;;IASH,8BAA0B;IACxB,iCAAmD;IACrD,iBAAM;;;IAKN,8BAAwB;IACtB,wBAA2D;IAC3D,6BAAsB;IAAA,YAAkB;IAC1C,AAD0C,iBAAI,EACxC;;;IADkB,eAAkB;IAAlB,yCAAkB;;;;IAQtC,+BAGwB;IADtB,uNAAS,+BAAqB,KAAC;IAE/B,wBAA8C;IAC9C,gCAA0B;IAAA,YAAiB;IAC7C,AAD6C,iBAAO,EAC9C;;;IAHJ,sCAAqB;IAEK,eAAiB;IAAjB,oCAAiB;;;IASzC,6BAA4B;IAAA,YAAmC;IAAA,iBAAI;;;IAAvC,cAAmC;IAAnC,+DAAmC;;;IAJnE,+BAA8B;IAC5B,wBAAwD;IACxD,6BAA4B;IAAA,2CAA2B;IAAA,iBAAI;IAC3D,gHAAe;IAGf,6BAA4B;IAAA,YAAuB;IACrD,AADqD,iBAAI,EACnD;;;IAJJ,eAEC;IAFD,yCAEC;IAC2B,eAAuB;IAAvB,mDAAuB;;;IAlBzD,8BAAyB;IACvB,qGAQC;IAED,oGAA4B;IAU9B,iBAAM;;;IApBJ,cAQC;IARD,6BAQC;IAED,eASC;IATD,sDASC;;AD3DT;;;;GAIG;AAOH,MAAM,OAAO,mBAAmB;IAC9B;;OAEG;IACK,aAAa,CAA2B;IAEhD;;OAEG;IACK,QAAQ,GAAsC,IAAI,CAAC;IAE3D;QACE,IAAI,CAAC,aAAa,GAAG,IAAI,wBAAwB,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAClF,CAAC;IAED,IACI,OAAO,CAAC,KAAwC;QAClD,MAAM,eAAe,GAAG,IAAI,CAAC,QAAQ,CAAC;QACtC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QAEtB,IAAI,KAAK,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;YACxE,IAAI,CAAC,eAAe,EAAE,CAAC;YACvB,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;IACD,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,uCAAuC;IACvC,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IACD,uCAAuC;IACvC,IAAa,OAAO,CAAC,KAAwC;QAC3D,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,CAAC;IAED;;OAEG;IACO,cAAc,GAAG,IAAI,YAAY,EAAU,CAAC;IAEtD;;;;;;OAMG;IACO,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC;IAE/C;;OAEG;IACI,WAAW,GAAW,GAAG,CAAC;IAEjC,2CAA2C;IAC3C,IAAW,WAAW;QACpB,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IACD,2CAA2C;IAC3C,IAAW,WAAW,CAAC,KAAa;QAClC,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;IAC3B,CAAC;IAED;;OAEG;IACI,OAAO,GAAa,EAAE,CAAC;IAE9B,uCAAuC;IACvC,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IACD,uCAAuC;IACvC,IAAW,OAAO,CAAC,KAAe;QAChC,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,CAAC;IAED;;OAEG;IACI,YAAY,GAAW,CAAC,CAAC,CAAC;IAEjC,4CAA4C;IAC5C,IAAW,YAAY;QACrB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IACD,4CAA4C;IAC5C,IAAW,YAAY,CAAC,KAAa;QACnC,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;IAC5B,CAAC;IAED;;OAEG;IACI,WAAW,GAAqB,EAAE,CAAC;IAE1C,2CAA2C;IAC3C,IAAW,WAAW;QACpB,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IACD,2CAA2C;IAC3C,IAAW,WAAW,CAAC,KAAuB;QAC5C,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;IAC3B,CAAC;IAED;;OAEG;IACI,OAAO,GAAiB,EAAE,CAAC;IAElC,uCAAuC;IACvC,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IACD,uCAAuC;IACvC,IAAW,OAAO,CAAC,KAAmB;QACpC,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,CAAC;IAEO,GAAG,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAExC;;OAEG;IACI,SAAS,GAAY,KAAK,CAAC;IAElC,yCAAyC;IACzC,IAAW,SAAS;QAClB,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IACD,yCAAyC;IACzC,IAAW,SAAS,CAAC,KAAc;QACjC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAED;;OAEG;IACI,YAAY,GAAkB,IAAI,CAAC;IAE1C,4CAA4C;IAC5C,IAAW,YAAY;QACrB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IACD,4CAA4C;IAC5C,IAAW,YAAY,CAAC,KAAoB;QAC1C,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;IAC5B,CAAC;IAED;;OAEG;IACK,eAAe;QACrB,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC3B,CAAC;IAED;;OAEG;IACI,cAAc,CAAC,IAAY;QAChC,yCAAyC;QACzC,IAAI,IAAI,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;YAC9B,OAAO;QACT,CAAC;QAED,mEAAmE;QACnE,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QAC9C,CAAC;aAAM,CAAC;YACN,+DAA+D;YAC/D,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;YAC5D,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QAC9C,CAAC;QAED,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAED,8CAA8C;IACvC,cAAc,CAAC,IAAY;QAChC,OAAO,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED;;;OAGG;IACI,OAAO;QACZ,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED,uCAAuC;IAChC,OAAO;QACZ,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;IAED;;OAEG;IACI,YAAY;QACjB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;YACtB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACnD,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC3C,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED,4CAA4C;IACrC,YAAY;QACjB,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC;IAC7B,CAAC;IAED;;OAEG;IACI,eAAe;QACpB,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACzB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACnD,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC3C,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED,+CAA+C;IACxC,eAAe;QACpB,OAAO,IAAI,CAAC,eAAe,EAAE,CAAC;IAChC,CAAC;IAED;;OAEG;IACI,SAAS;QACd,OAAO,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;IAC/B,CAAC;IAED,yCAAyC;IAClC,SAAS;QACd,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC;IAC1B,CAAC;IAED;;OAEG;IACI,YAAY;QACjB,OAAO,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IACrD,CAAC;IAED,4CAA4C;IACrC,YAAY;QACjB,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC;IAC7B,CAAC;IAED;;OAEG;IACK,iBAAiB;QACvB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;YACtB,OAAO;QACT,CAAC;QAED,8CAA8C;QAC9C,MAAM,KAAK,GAAqB;YAC9B;gBACE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI;gBAChC,IAAI,EAAE,GAAG;aACV;SACF,CAAC;QAEF,mCAAmC;QACnC,IAAI,IAAI,CAAC,WAAW,KAAK,GAAG,EAAE,CAAC;YAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACvE,IAAI,SAAS,GAAG,EAAE,CAAC;YAEnB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,SAAS,IAAI,GAAG,GAAG,OAAO,CAAC;gBAC3B,KAAK,CAAC,IAAI,CAAC;oBACT,KAAK,EAAE,OAAO;oBACd,IAAI,EAAE,SAAS;iBAChB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;IAC3B,CAAC;IAED;;OAEG;IACI,iBAAiB,CAAC,IAAoB;QAC3C,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED,iDAAiD;IAC1C,iBAAiB,CAAC,IAAoB;QAC3C,OAAO,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,WAAW;QACvB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;YAClB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QAEzB,IAAI,CAAC;YACH,kFAAkF;YAClF,qFAAqF;YACrF,oFAAoF;YACpF,2EAA2E;YAC3E,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;YACrF,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACxF,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,WAAW,CACrD,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EACvB,UAAU,EACV,GAAG,CACJ,CAAC;YAEF,kCAAkC;YAClC,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,IAAI,EAAE,CAAC;YAC3C,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAc,EAAE,EAAE;gBAC7C,qDAAqD;gBACrD,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;gBACtE,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,SAAS,CAAC;gBAErD,OAAO;oBACL,IAAI;oBACJ,QAAQ,EAAE,MAAM;iBACjB,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;YAC/C,IAAI,CAAC,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC;YACtF,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QACpB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACvB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;IAED;;OAEG;IACI,aAAa,CAAC,MAAkB;QACrC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IAED,6CAA6C;IACtC,aAAa,CAAC,MAAkB;QACrC,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;6GAxXU,mBAAmB;6DAAnB,mBAAmB;YChChC,8BAAyB;YAEvB,qFAAe;YAwCf,8BAA0B;YAExB,qFAAiB;YAOjB,qFAAkC;YAQlC,qFAAmC;YAyBvC,AADE,iBAAM,EACF;;YAlFJ,cAqCC;YArCD,sCAqCC;YAKC,eAIC;YAJD,wCAIC;YAGD,cAKC;YALD,6DAKC;YAGD,cAuBC;YAvBD,8DAuBC;;;iFDlDQ,mBAAmB;cAN/B,SAAS;6BACI,KAAK,YACP,gBAAgB;;kBAmBzB,KAAK;;kBAmBL,KAAK;;kBAOL,MAAM;;kBASN,MAAM;;kFAlDI,mBAAmB","sourcesContent":["import { Component, EventEmitter, Input, Output, ChangeDetectorRef, inject } from '@angular/core';\nimport { GraphQLDataProvider, GraphQLFileStorageClient } from '@memberjunction/graphql-dataprovider';\nimport { StorageAccountWithProvider } from '@memberjunction/core-entities';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n/**\n * Represents a breadcrumb item in the path\n */\nexport interface BreadcrumbItem {\n label: string; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n path: string; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n}\n\n/**\n * Represents a folder in the tree\n */\nexport interface FolderItem {\n name: string; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n fullPath: string; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n}\n\n/**\n * Folder tree navigation component with breadcrumbs and history navigation.\n * Provides Mac Finder-style navigation with back/forward buttons and breadcrumb path.\n * Loads actual folder structure from storage accounts via GraphQL.\n */\n@Component({\n standalone: false,\n selector: 'mj-folder-tree',\n templateUrl: './folder-tree.component.html',\n styleUrls: ['./folder-tree.component.css']\n})\nexport class FolderTreeComponent {\n /**\n * GraphQL client for file storage operations\n */\n private storageClient: GraphQLFileStorageClient;\n\n /**\n * Currently selected storage account with provider details\n */\n private _account: StorageAccountWithProvider | null = null;\n\n constructor() {\n this.storageClient = new GraphQLFileStorageClient(GraphQLDataProvider.Instance);\n }\n\n @Input()\n set Account(value: StorageAccountWithProvider | null) {\n const previousAccount = this._account;\n this._account = value;\n\n if (value && !UUIDsEqual(value.account.ID, previousAccount?.account.ID)) {\n this.resetNavigation();\n this.loadFolders();\n }\n }\n get Account(): StorageAccountWithProvider | null {\n return this._account;\n }\n\n /** @deprecated Use {@link Account}. */\n get account(): StorageAccountWithProvider | null {\n return this.Account;\n }\n /** @deprecated Use {@link Account}. */\n @Input() set account(value: StorageAccountWithProvider | null) {\n this.Account = value;\n }\n\n /**\n * Emits when a folder is selected in the tree\n */\n @Output() FolderSelected = new EventEmitter<string>();\n\n /**\n * @deprecated Use {@link FolderSelected}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (folderSelected) keeps working. Must stay AFTER FolderSelected: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() folderSelected = this.FolderSelected;\n\n /**\n * Current folder path\n */\n public CurrentPath: string = '/';\n\n /** @deprecated Use {@link CurrentPath}. */\n public get currentPath(): string {\n return this.CurrentPath;\n }\n /** @deprecated Use {@link CurrentPath}. */\n public set currentPath(value: string) {\n this.CurrentPath = value;\n }\n\n /**\n * Navigation history (for back button)\n */\n public History: string[] = [];\n\n /** @deprecated Use {@link History}. */\n public get history(): string[] {\n return this.History;\n }\n /** @deprecated Use {@link History}. */\n public set history(value: string[]) {\n this.History = value;\n }\n\n /**\n * Current position in history\n */\n public HistoryIndex: number = -1;\n\n /** @deprecated Use {@link HistoryIndex}. */\n public get historyIndex(): number {\n return this.HistoryIndex;\n }\n /** @deprecated Use {@link HistoryIndex}. */\n public set historyIndex(value: number) {\n this.HistoryIndex = value;\n }\n\n /**\n * Breadcrumb items for current path\n */\n public Breadcrumbs: BreadcrumbItem[] = [];\n\n /** @deprecated Use {@link Breadcrumbs}. */\n public get breadcrumbs(): BreadcrumbItem[] {\n return this.Breadcrumbs;\n }\n /** @deprecated Use {@link Breadcrumbs}. */\n public set breadcrumbs(value: BreadcrumbItem[]) {\n this.Breadcrumbs = value;\n }\n\n /**\n * Folders in current path\n */\n public Folders: FolderItem[] = [];\n\n /** @deprecated Use {@link Folders}. */\n public get folders(): FolderItem[] {\n return this.Folders;\n }\n /** @deprecated Use {@link Folders}. */\n public set folders(value: FolderItem[]) {\n this.Folders = value;\n }\n\n private cdr = inject(ChangeDetectorRef);\n\n /**\n * Loading state\n */\n public IsLoading: boolean = false;\n\n /** @deprecated Use {@link IsLoading}. */\n public get isLoading(): boolean {\n return this.IsLoading;\n }\n /** @deprecated Use {@link IsLoading}. */\n public set isLoading(value: boolean) {\n this.IsLoading = value;\n }\n\n /**\n * Error message\n */\n public ErrorMessage: string | null = null;\n\n /** @deprecated Use {@link ErrorMessage}. */\n public get errorMessage(): string | null {\n return this.ErrorMessage;\n }\n /** @deprecated Use {@link ErrorMessage}. */\n public set errorMessage(value: string | null) {\n this.ErrorMessage = value;\n }\n\n /**\n * Resets navigation when provider changes\n */\n private resetNavigation(): void {\n this.CurrentPath = '/';\n this.History = ['/'];\n this.HistoryIndex = 0;\n this.updateBreadcrumbs();\n }\n\n /**\n * Navigates to a specific folder path\n */\n public NavigateToPath(path: string): void {\n // Don't navigate if already at this path\n if (path === this.CurrentPath) {\n return;\n }\n\n // Add to history if navigating from user action (not back/forward)\n if (this.HistoryIndex === this.History.length - 1) {\n this.History.push(path);\n this.HistoryIndex = this.History.length - 1;\n } else {\n // Navigating from middle of history - truncate forward history\n this.History = this.History.slice(0, this.HistoryIndex + 1);\n this.History.push(path);\n this.HistoryIndex = this.History.length - 1;\n }\n\n this.CurrentPath = path;\n this.updateBreadcrumbs();\n this.loadFolders();\n this.FolderSelected.emit(path);\n }\n\n /** @deprecated Use {@link NavigateToPath}. */\n public navigateToPath(path: string): void {\n return this.NavigateToPath(path);\n }\n\n /**\n * Refreshes the current folder view without changing navigation\n * Used when folder structure changes (e.g., folder deleted) but we're staying in the same location\n */\n public Refresh(): void {\n this.loadFolders();\n }\n\n /** @deprecated Use {@link Refresh}. */\n public refresh(): void {\n return this.Refresh();\n }\n\n /**\n * Navigates back in history\n */\n public NavigateBack(): void {\n if (!this.CanGoBack()) {\n return;\n }\n\n this.HistoryIndex--;\n this.CurrentPath = this.History[this.HistoryIndex];\n this.updateBreadcrumbs();\n this.FolderSelected.emit(this.CurrentPath);\n this.loadFolders();\n }\n\n /** @deprecated Use {@link NavigateBack}. */\n public navigateBack(): void {\n return this.NavigateBack();\n }\n\n /**\n * Navigates forward in history\n */\n public NavigateForward(): void {\n if (!this.CanGoForward()) {\n return;\n }\n\n this.HistoryIndex++;\n this.CurrentPath = this.History[this.HistoryIndex];\n this.updateBreadcrumbs();\n this.FolderSelected.emit(this.CurrentPath);\n this.loadFolders();\n }\n\n /** @deprecated Use {@link NavigateForward}. */\n public navigateForward(): void {\n return this.NavigateForward();\n }\n\n /**\n * Checks if can navigate back\n */\n public CanGoBack(): boolean {\n return this.HistoryIndex > 0;\n }\n\n /** @deprecated Use {@link CanGoBack}. */\n public canGoBack(): boolean {\n return this.CanGoBack();\n }\n\n /**\n * Checks if can navigate forward\n */\n public CanGoForward(): boolean {\n return this.HistoryIndex < this.History.length - 1;\n }\n\n /** @deprecated Use {@link CanGoForward}. */\n public canGoForward(): boolean {\n return this.CanGoForward();\n }\n\n /**\n * Updates breadcrumbs based on current path\n */\n private updateBreadcrumbs(): void {\n if (!this.Account) {\n this.Breadcrumbs = [];\n return;\n }\n\n // Start with account root (show account name)\n const items: BreadcrumbItem[] = [\n {\n label: this.Account.account.Name,\n path: '/'\n }\n ];\n\n // Add path segments if not at root\n if (this.CurrentPath !== '/') {\n const segments = this.CurrentPath.split('/').filter(s => s.length > 0);\n let builtPath = '';\n\n for (const segment of segments) {\n builtPath += '/' + segment;\n items.push({\n label: segment,\n path: builtPath\n });\n }\n }\n\n this.Breadcrumbs = items;\n }\n\n /**\n * Handles breadcrumb click\n */\n public OnBreadcrumbClick(item: BreadcrumbItem): void {\n this.NavigateToPath(item.path);\n this.loadFolders();\n }\n\n /** @deprecated Use {@link OnBreadcrumbClick}. */\n public onBreadcrumbClick(item: BreadcrumbItem): void {\n return this.OnBreadcrumbClick(item);\n }\n\n /**\n * Loads folders from the storage account for the current path\n */\n private async loadFolders(): Promise<void> {\n if (!this.Account) {\n this.Folders = [];\n return;\n }\n\n this.IsLoading = true;\n this.ErrorMessage = null;\n this.cdr.detectChanges();\n\n try {\n // Blob keys (Azure/S3) have NO leading slash and use a trailing slash to denote a\n // directory prefix. currentPath is stored with a leading slash (e.g. \"/test\"), which\n // never matches real keys — so nested-folder listings came back empty (empty folder\n // names). Normalize to a slash-free, trailing-slash prefix before listing.\n const rawPath = this.CurrentPath && this.CurrentPath !== '/' ? this.CurrentPath : '';\n const listPrefix = rawPath ? rawPath.replace(/^\\/+/, '').replace(/\\/+$/, '') + '/' : '';\n const listResult = await this.storageClient.ListObjects(\n this.Account.account.ID,\n listPrefix,\n '/'\n );\n\n // Convert prefixes to FolderItems\n const prefixes = listResult.prefixes || [];\n this.Folders = prefixes.map((prefix: string) => {\n // Remove trailing slash and get just the folder name\n const cleanPath = prefix.endsWith('/') ? prefix.slice(0, -1) : prefix;\n const name = cleanPath.split('/').pop() || cleanPath;\n\n return {\n name,\n fullPath: prefix\n };\n });\n } catch (error) {\n console.error('Error loading folders:', error);\n this.ErrorMessage = error instanceof Error ? error.message : 'Failed to load folders';\n this.Folders = [];\n } finally {\n this.IsLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Handles folder click for navigation\n */\n public OnFolderClick(folder: FolderItem): void {\n this.NavigateToPath(folder.fullPath);\n this.loadFolders();\n }\n\n /** @deprecated Use {@link OnFolderClick}. */\n public onFolderClick(folder: FolderItem): void {\n return this.OnFolderClick(folder);\n }\n}\n","<div class=\"folder-tree\">\n <!-- Navigation bar with back/forward buttons and breadcrumbs -->\n @if (account) {\n <div class=\"navigation-bar\">\n <!-- Back/Forward buttons -->\n <div class=\"nav-buttons\">\n <button\n type=\"button\"\n [disabled]=\"!canGoBack()\"\n (click)=\"navigateBack()\"\n title=\"Go back\"\n class=\"nav-button\">\n <i class=\"fa-solid fa-chevron-left\"></i>\n </button>\n <button\n type=\"button\"\n [disabled]=\"!canGoForward()\"\n (click)=\"navigateForward()\"\n title=\"Go forward\"\n class=\"nav-button\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </button>\n </div>\n <!-- Breadcrumb path -->\n <div class=\"breadcrumbs\">\n @for (item of breadcrumbs; track item.path; let last = $last) {\n <button\n type=\"button\"\n (click)=\"onBreadcrumbClick(item)\"\n [class.current]=\"last\"\n class=\"breadcrumb-item\">\n {{ item.label }}\n </button>\n @if (!last) {\n <i class=\"fa-solid fa-chevron-right breadcrumb-separator\"></i>\n }\n }\n </div>\n </div>\n }\n\n <!-- Folder tree content -->\n <div class=\"tree-content\">\n <!-- Loading state -->\n @if (isLoading) {\n <div class=\"tree-loading\">\n <mj-loading text=\"Loading folders...\"></mj-loading>\n </div>\n }\n\n <!-- Error state -->\n @if (errorMessage && !isLoading) {\n <div class=\"tree-error\">\n <i class=\"fa-solid fa-triangle-exclamation error-icon\"></i>\n <p class=\"error-text\">{{ errorMessage }}</p>\n </div>\n }\n\n <!-- Folder list -->\n @if (!isLoading && !errorMessage) {\n <div class=\"folder-list\">\n @for (folder of folders; track folder.name) {\n <div\n class=\"folder-item\"\n (click)=\"onFolderClick(folder)\"\n [title]=\"folder.name\">\n <i class=\"fa-solid fa-folder folder-icon\"></i>\n <span class=\"folder-name\">{{ folder.name }}</span>\n </div>\n }\n <!-- Empty state -->\n @if (folders.length === 0) {\n <div class=\"tree-placeholder\">\n <i class=\"fa-solid fa-folder-open placeholder-icon\"></i>\n <p class=\"placeholder-text\">No folders in this location</p>\n @if (account) {\n <p class=\"placeholder-hint\">Account: {{ account.account.Name }}</p>\n }\n <p class=\"placeholder-hint\">Path: {{ currentPath }}</p>\n </div>\n }\n </div>\n }\n </div>\n</div>\n"]}
@@ -15,15 +15,31 @@ export declare class StorageProvidersListComponent implements OnInit {
15
15
  * Emits when an account is selected by the user, or null when no accounts are available.
16
16
  * Emits the full account-with-provider object for downstream components to use.
17
17
  */
18
+ AccountSelected: EventEmitter<StorageAccountWithProvider | null>;
19
+ /**
20
+ * @deprecated Use {@link AccountSelected}.
21
+ *
22
+ * The same emitter under the old binding name, so a template still binding
23
+ * (accountSelected) keeps working. Must stay AFTER AccountSelected: class fields
24
+ * initialise in order, and the other way round this captures undefined.
25
+ */
18
26
  accountSelected: EventEmitter<StorageAccountWithProvider | null>;
19
27
  /**
20
28
  * All available storage accounts with their provider details.
21
29
  */
22
- accounts: StorageAccountWithProvider[];
30
+ Accounts: StorageAccountWithProvider[];
31
+ /** @deprecated Use {@link Accounts}. */
32
+ get accounts(): StorageAccountWithProvider[];
33
+ /** @deprecated Use {@link Accounts}. */
34
+ set accounts(value: StorageAccountWithProvider[]);
23
35
  /**
24
36
  * Currently selected account.
25
37
  */
26
- selectedAccount: StorageAccountWithProvider | null;
38
+ SelectedAccount: StorageAccountWithProvider | null;
39
+ /** @deprecated Use {@link SelectedAccount}. */
40
+ get selectedAccount(): StorageAccountWithProvider | null;
41
+ /** @deprecated Use {@link SelectedAccount}. */
42
+ set selectedAccount(value: StorageAccountWithProvider | null);
27
43
  /**
28
44
  * Loading state indicator.
29
45
  */
@@ -35,13 +51,29 @@ export declare class StorageProvidersListComponent implements OnInit {
35
51
  /**
36
52
  * Whether current user has admin rights to configure storage accounts or providers.
37
53
  */
38
- userCanManage: boolean;
54
+ UserCanManage: boolean;
55
+ /** @deprecated Use {@link UserCanManage}. */
56
+ get userCanManage(): boolean;
57
+ /** @deprecated Use {@link UserCanManage}. */
58
+ set userCanManage(value: boolean);
39
59
  /**
40
60
  * Admin dialog state
41
61
  */
42
- isManageDialogOpen: boolean;
43
- adminDialogTab: StorageAdminTab;
44
- accountToEdit: MJFileStorageAccountEntity | null;
62
+ IsManageDialogOpen: boolean;
63
+ /** @deprecated Use {@link IsManageDialogOpen}. */
64
+ get isManageDialogOpen(): boolean;
65
+ /** @deprecated Use {@link IsManageDialogOpen}. */
66
+ set isManageDialogOpen(value: boolean);
67
+ AdminDialogTab: StorageAdminTab;
68
+ /** @deprecated Use {@link AdminDialogTab}. */
69
+ get adminDialogTab(): StorageAdminTab;
70
+ /** @deprecated Use {@link AdminDialogTab}. */
71
+ set adminDialogTab(value: StorageAdminTab);
72
+ AccountToEdit: MJFileStorageAccountEntity | null;
73
+ /** @deprecated Use {@link AccountToEdit}. */
74
+ get accountToEdit(): MJFileStorageAccountEntity | null;
75
+ /** @deprecated Use {@link AccountToEdit}. */
76
+ set accountToEdit(value: MJFileStorageAccountEntity | null);
45
77
  Provider: IMetadataProvider | null;
46
78
  get ProviderToUse(): IMetadataProvider;
47
79
  constructor();
@@ -58,36 +90,52 @@ export declare class StorageProvidersListComponent implements OnInit {
58
90
  /**
59
91
  * Handles account selection by the user.
60
92
  */
93
+ SelectAccount(accountWithProvider: StorageAccountWithProvider): void;
94
+ /** @deprecated Use {@link SelectAccount}. */
61
95
  selectAccount(accountWithProvider: StorageAccountWithProvider): void;
62
96
  /**
63
97
  * Checks if an account is currently selected.
64
98
  */
99
+ IsSelected(accountWithProvider: StorageAccountWithProvider): boolean;
100
+ /** @deprecated Use {@link IsSelected}. */
65
101
  isSelected(accountWithProvider: StorageAccountWithProvider): boolean;
66
102
  /**
67
103
  * Gets the icon class for a provider based on its name.
68
104
  */
105
+ GetProviderIcon(providerName: string): string;
106
+ /** @deprecated Use {@link GetProviderIcon}. */
69
107
  getProviderIcon(providerName: string): string;
70
108
  /**
71
109
  * Refreshes the accounts list by forcing a reload from the database.
72
110
  */
111
+ Refresh(): void;
112
+ /** @deprecated Use {@link Refresh}. */
73
113
  refresh(): void;
74
114
  /**
75
115
  * Opens the storage administration dialog
76
116
  */
117
+ OpenAdminDialog(tab?: StorageAdminTab, account?: MJFileStorageAccountEntity | null): void;
118
+ /** @deprecated Use {@link OpenAdminDialog}. */
77
119
  openAdminDialog(tab?: StorageAdminTab, account?: MJFileStorageAccountEntity | null): void;
78
120
  /**
79
121
  * Closes the storage administration dialog
80
122
  */
123
+ CloseAdminDialog(): void;
124
+ /** @deprecated Use {@link CloseAdminDialog}. */
81
125
  closeAdminDialog(): void;
82
126
  /**
83
127
  * Handles storage configuration changes from the admin dialog
84
128
  */
129
+ OnAdminAccountsChanged(): void;
130
+ /** @deprecated Use {@link OnAdminAccountsChanged}. */
85
131
  onAdminAccountsChanged(): void;
86
132
  /**
87
133
  * Handles inline edit click on an account item
88
134
  */
135
+ OnEditAccountClick(item: StorageAccountWithProvider, event: MouseEvent): void;
136
+ /** @deprecated Use {@link OnEditAccountClick}. */
89
137
  onEditAccountClick(item: StorageAccountWithProvider, event: MouseEvent): void;
90
138
  static ɵfac: i0.ɵɵFactoryDeclaration<StorageProvidersListComponent, never>;
91
- static ɵcmp: i0.ɵɵComponentDeclaration<StorageProvidersListComponent, "mj-storage-providers-list", never, {}, { "accountSelected": "accountSelected"; }, never, never, false, never>;
139
+ static ɵcmp: i0.ɵɵComponentDeclaration<StorageProvidersListComponent, "mj-storage-providers-list", never, {}, { "AccountSelected": "AccountSelected"; "accountSelected": "accountSelected"; }, never, never, false, never>;
92
140
  }
93
141
  //# sourceMappingURL=storage-providers-list.component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage-providers-list.component.d.ts","sourceRoot":"","sources":["../../../src/lib/file-browser/storage-providers-list.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAE,MAAM,EAAqC,MAAM,eAAe,CAAC;AACnG,OAAO,EAAyB,0BAA0B,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC9H,OAAO,EAAY,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAExE,OAAO,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;;AAE1E;;;;;GAKG;AACH,qBAMa,6BAA8B,YAAW,MAAM;IAC1D,OAAO,CAAC,GAAG,CAA6B;IAExC;;;OAGG;IACO,eAAe,kDAAyD;IAElF;;OAEG;IACI,QAAQ,EAAE,0BAA0B,EAAE,CAAM;IAEnD;;OAEG;IACI,eAAe,EAAE,0BAA0B,GAAG,IAAI,CAAQ;IAEjE;;OAEG;IACI,SAAS,EAAE,OAAO,CAAS;IAElC;;OAEG;IACI,YAAY,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE1C;;OAEG;IACI,aAAa,EAAE,OAAO,CAAS;IAEtC;;OAEG;IACI,kBAAkB,EAAE,OAAO,CAAS;IACpC,cAAc,EAAE,eAAe,CAAc;IAC7C,aAAa,EAAE,0BAA0B,GAAG,IAAI,CAAQ;IAExD,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAQ;IAEjD,IAAW,aAAa,IAAI,iBAAiB,CAE5C;;IAID,QAAQ,IAAI,IAAI;IAOhB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAoBxB;;;OAGG;YACW,YAAY;IAsC1B;;OAEG;IACI,aAAa,CAAC,mBAAmB,EAAE,0BAA0B,GAAG,IAAI;IAK3E;;OAEG;IACI,UAAU,CAAC,mBAAmB,EAAE,0BAA0B,GAAG,OAAO;IAI3E;;OAEG;IACI,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAsBpD;;OAEG;IACI,OAAO,IAAI,IAAI;IAItB;;OAEG;IACI,eAAe,CAAC,GAAG,GAAE,eAA4B,EAAE,OAAO,CAAC,EAAE,0BAA0B,GAAG,IAAI,GAAG,IAAI;IAO5G;;OAEG;IACI,gBAAgB,IAAI,IAAI;IAM/B;;OAEG;IACI,sBAAsB,IAAI,IAAI;IAIrC;;OAEG;IACI,kBAAkB,CAAC,IAAI,EAAE,0BAA0B,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;yCArMzE,6BAA6B;2CAA7B,6BAA6B;CAyMzC"}
1
+ {"version":3,"file":"storage-providers-list.component.d.ts","sourceRoot":"","sources":["../../../src/lib/file-browser/storage-providers-list.component.ts"],"names":[],"mappings":"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"}
@@ -141,15 +141,39 @@ export class StorageProvidersListComponent {
141
141
  * Emits when an account is selected by the user, or null when no accounts are available.
142
142
  * Emits the full account-with-provider object for downstream components to use.
143
143
  */
144
- accountSelected = new EventEmitter();
144
+ AccountSelected = new EventEmitter();
145
+ /**
146
+ * @deprecated Use {@link AccountSelected}.
147
+ *
148
+ * The same emitter under the old binding name, so a template still binding
149
+ * (accountSelected) keeps working. Must stay AFTER AccountSelected: class fields
150
+ * initialise in order, and the other way round this captures undefined.
151
+ */
152
+ accountSelected = this.AccountSelected;
145
153
  /**
146
154
  * All available storage accounts with their provider details.
147
155
  */
148
- accounts = [];
156
+ Accounts = [];
157
+ /** @deprecated Use {@link Accounts}. */
158
+ get accounts() {
159
+ return this.Accounts;
160
+ }
161
+ /** @deprecated Use {@link Accounts}. */
162
+ set accounts(value) {
163
+ this.Accounts = value;
164
+ }
149
165
  /**
150
166
  * Currently selected account.
151
167
  */
152
- selectedAccount = null;
168
+ SelectedAccount = null;
169
+ /** @deprecated Use {@link SelectedAccount}. */
170
+ get selectedAccount() {
171
+ return this.SelectedAccount;
172
+ }
173
+ /** @deprecated Use {@link SelectedAccount}. */
174
+ set selectedAccount(value) {
175
+ this.SelectedAccount = value;
176
+ }
153
177
  /**
154
178
  * Loading state indicator.
155
179
  */
@@ -161,20 +185,52 @@ export class StorageProvidersListComponent {
161
185
  /**
162
186
  * Whether current user has admin rights to configure storage accounts or providers.
163
187
  */
164
- userCanManage = false;
188
+ UserCanManage = false;
189
+ /** @deprecated Use {@link UserCanManage}. */
190
+ get userCanManage() {
191
+ return this.UserCanManage;
192
+ }
193
+ /** @deprecated Use {@link UserCanManage}. */
194
+ set userCanManage(value) {
195
+ this.UserCanManage = value;
196
+ }
165
197
  /**
166
198
  * Admin dialog state
167
199
  */
168
- isManageDialogOpen = false;
169
- adminDialogTab = 'accounts';
170
- accountToEdit = null;
200
+ IsManageDialogOpen = false;
201
+ /** @deprecated Use {@link IsManageDialogOpen}. */
202
+ get isManageDialogOpen() {
203
+ return this.IsManageDialogOpen;
204
+ }
205
+ /** @deprecated Use {@link IsManageDialogOpen}. */
206
+ set isManageDialogOpen(value) {
207
+ this.IsManageDialogOpen = value;
208
+ }
209
+ AdminDialogTab = 'accounts';
210
+ /** @deprecated Use {@link AdminDialogTab}. */
211
+ get adminDialogTab() {
212
+ return this.AdminDialogTab;
213
+ }
214
+ /** @deprecated Use {@link AdminDialogTab}. */
215
+ set adminDialogTab(value) {
216
+ this.AdminDialogTab = value;
217
+ }
218
+ AccountToEdit = null;
219
+ /** @deprecated Use {@link AccountToEdit}. */
220
+ get accountToEdit() {
221
+ return this.AccountToEdit;
222
+ }
223
+ /** @deprecated Use {@link AccountToEdit}. */
224
+ set accountToEdit(value) {
225
+ this.AccountToEdit = value;
226
+ }
171
227
  Provider = null;
172
228
  get ProviderToUse() {
173
229
  return this.Provider ?? Metadata.Provider;
174
230
  }
175
231
  constructor() { }
176
232
  ngOnInit() {
177
- if (!this.userCanManage) {
233
+ if (!this.UserCanManage) {
178
234
  this.checkPermissions();
179
235
  }
180
236
  this.loadAccounts();
@@ -193,10 +249,10 @@ export class StorageProvidersListComponent {
193
249
  const acctEntity = md.Entities.find(e => e.Name === 'MJ: File Storage Accounts');
194
250
  const provCanManage = provEntity ? provEntity.GetUserPermisions(user).CanCreate || provEntity.GetUserPermisions(user).CanUpdate : false;
195
251
  const acctCanManage = acctEntity ? acctEntity.GetUserPermisions(user).CanCreate || acctEntity.GetUserPermisions(user).CanUpdate : false;
196
- this.userCanManage = !!(provCanManage || acctCanManage);
252
+ this.UserCanManage = !!(provCanManage || acctCanManage);
197
253
  }
198
254
  catch {
199
- this.userCanManage = false;
255
+ this.UserCanManage = false;
200
256
  }
201
257
  }
202
258
  /**
@@ -210,22 +266,22 @@ export class StorageProvidersListComponent {
210
266
  const engine = FileStorageEngineBase.Instance;
211
267
  await engine.Config(forceRefresh);
212
268
  // Only show accounts whose provider is active
213
- this.accounts = engine.AccountsWithProviders.filter(a => a.provider.IsActive !== false);
214
- if (this.accounts.length === 0 && !forceRefresh) {
269
+ this.Accounts = engine.AccountsWithProviders.filter(a => a.provider.IsActive !== false);
270
+ if (this.Accounts.length === 0 && !forceRefresh) {
215
271
  await engine.Config(true);
216
- this.accounts = engine.AccountsWithProviders.filter(a => a.provider.IsActive !== false);
272
+ this.Accounts = engine.AccountsWithProviders.filter(a => a.provider.IsActive !== false);
217
273
  }
218
- console.log('[StorageAccountsList] Loaded accounts:', this.accounts.map(a => ({
274
+ console.log('[StorageAccountsList] Loaded accounts:', this.Accounts.map(a => ({
219
275
  name: a.account.Name,
220
276
  provider: a.provider.Name,
221
277
  hasCredential: !!a.account.CredentialID
222
278
  })));
223
279
  // Auto-select first account if available
224
- if (this.accounts.length > 0) {
225
- this.selectAccount(this.accounts[0]);
280
+ if (this.Accounts.length > 0) {
281
+ this.SelectAccount(this.Accounts[0]);
226
282
  }
227
283
  else {
228
- this.accountSelected.emit(null);
284
+ this.AccountSelected.emit(null);
229
285
  }
230
286
  }
231
287
  catch (error) {
@@ -240,20 +296,28 @@ export class StorageProvidersListComponent {
240
296
  /**
241
297
  * Handles account selection by the user.
242
298
  */
299
+ SelectAccount(accountWithProvider) {
300
+ this.SelectedAccount = accountWithProvider;
301
+ this.AccountSelected.emit(accountWithProvider);
302
+ }
303
+ /** @deprecated Use {@link SelectAccount}. */
243
304
  selectAccount(accountWithProvider) {
244
- this.selectedAccount = accountWithProvider;
245
- this.accountSelected.emit(accountWithProvider);
305
+ return this.SelectAccount(accountWithProvider);
246
306
  }
247
307
  /**
248
308
  * Checks if an account is currently selected.
249
309
  */
310
+ IsSelected(accountWithProvider) {
311
+ return UUIDsEqual(this.SelectedAccount?.account.ID, accountWithProvider.account.ID);
312
+ }
313
+ /** @deprecated Use {@link IsSelected}. */
250
314
  isSelected(accountWithProvider) {
251
- return UUIDsEqual(this.selectedAccount?.account.ID, accountWithProvider.account.ID);
315
+ return this.IsSelected(accountWithProvider);
252
316
  }
253
317
  /**
254
318
  * Gets the icon class for a provider based on its name.
255
319
  */
256
- getProviderIcon(providerName) {
320
+ GetProviderIcon(providerName) {
257
321
  const name = providerName.toLowerCase();
258
322
  if (name.includes('aws') || name.includes('s3')) {
259
323
  return 'fa-brands fa-aws';
@@ -280,44 +344,68 @@ export class StorageProvidersListComponent {
280
344
  return 'fa-solid fa-cloud';
281
345
  }
282
346
  }
347
+ /** @deprecated Use {@link GetProviderIcon}. */
348
+ getProviderIcon(providerName) {
349
+ return this.GetProviderIcon(providerName);
350
+ }
283
351
  /**
284
352
  * Refreshes the accounts list by forcing a reload from the database.
285
353
  */
286
- refresh() {
354
+ Refresh() {
287
355
  void this.loadAccounts(true);
288
356
  }
357
+ /** @deprecated Use {@link Refresh}. */
358
+ refresh() {
359
+ return this.Refresh();
360
+ }
289
361
  /**
290
362
  * Opens the storage administration dialog
291
363
  */
292
- openAdminDialog(tab = 'accounts', account) {
293
- this.adminDialogTab = tab;
294
- this.accountToEdit = account ?? null;
295
- this.isManageDialogOpen = true;
364
+ OpenAdminDialog(tab = 'accounts', account) {
365
+ this.AdminDialogTab = tab;
366
+ this.AccountToEdit = account ?? null;
367
+ this.IsManageDialogOpen = true;
296
368
  this.cdr.markForCheck();
297
369
  }
370
+ /** @deprecated Use {@link OpenAdminDialog}. */
371
+ openAdminDialog(tab = 'accounts', account) {
372
+ return this.OpenAdminDialog(tab, account);
373
+ }
298
374
  /**
299
375
  * Closes the storage administration dialog
300
376
  */
301
- closeAdminDialog() {
302
- this.isManageDialogOpen = false;
303
- this.accountToEdit = null;
377
+ CloseAdminDialog() {
378
+ this.IsManageDialogOpen = false;
379
+ this.AccountToEdit = null;
304
380
  this.cdr.markForCheck();
305
381
  }
382
+ /** @deprecated Use {@link CloseAdminDialog}. */
383
+ closeAdminDialog() {
384
+ return this.CloseAdminDialog();
385
+ }
306
386
  /**
307
387
  * Handles storage configuration changes from the admin dialog
308
388
  */
389
+ OnAdminAccountsChanged() {
390
+ this.Refresh();
391
+ }
392
+ /** @deprecated Use {@link OnAdminAccountsChanged}. */
309
393
  onAdminAccountsChanged() {
310
- this.refresh();
394
+ return this.OnAdminAccountsChanged();
311
395
  }
312
396
  /**
313
397
  * Handles inline edit click on an account item
314
398
  */
315
- onEditAccountClick(item, event) {
399
+ OnEditAccountClick(item, event) {
316
400
  event.stopPropagation();
317
- this.openAdminDialog('accounts', item.account);
401
+ this.OpenAdminDialog('accounts', item.account);
402
+ }
403
+ /** @deprecated Use {@link OnEditAccountClick}. */
404
+ onEditAccountClick(item, event) {
405
+ return this.OnEditAccountClick(item, event);
318
406
  }
319
407
  static ɵfac = function StorageProvidersListComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || StorageProvidersListComponent)(); };
320
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: StorageProvidersListComponent, selectors: [["mj-storage-providers-list"]], outputs: { accountSelected: "accountSelected" }, standalone: false, decls: 10, vars: 6, consts: [[1, "providers-list"], [1, "providers-header"], [1, "header-title"], [1, "admin-header-actions"], [1, "loading-state"], ["Variant", "error", "Icon", "fa-solid fa-triangle-exclamation", "Size", "compact", 1, "storage-providers-empty-fill", 3, "Title"], ["Icon", "fa-solid fa-folder-plus", "Size", "compact", 1, "storage-providers-empty-fill", 3, "Title", "Message"], [1, "providers-container"], [3, "Visible", "ActiveTab"], ["type", "button", "title", "Add Storage Account", 1, "admin-action-btn", 3, "click"], [1, "fa-solid", "fa-plus"], ["type", "button", "title", "Manage Storage Providers & Accounts", 1, "admin-action-btn", 3, "click"], [1, "fa-solid", "fa-gear"], ["text", "Loading accounts..."], ["type", "button", 1, "mj-empty-action-btn"], ["type", "button", 1, "mj-empty-action-btn", 3, "click"], [1, "provider-item", 3, "selected", "title"], [1, "provider-item", 3, "click", "title"], [1, "provider-icon"], [1, "provider-info"], [1, "provider-name"], [1, "provider-meta"], [1, "provider-type-badge", 3, "title"], ["title", "Supports search", 1, "search-badge"], ["title", "Credentials configured", 1, "credential-badge"], ["title", "No credentials configured", 1, "unconfigured-badge"], ["type", "button", "title", "Edit Storage Account", 1, "provider-edit-btn"], [1, "fa-solid", "fa-magnifying-glass"], [1, "fa-solid", "fa-key"], [1, "fa-solid", "fa-exclamation-triangle"], ["type", "button", "title", "Edit Storage Account", 1, "provider-edit-btn", 3, "click"], [1, "fa-solid", "fa-pen-to-square"], [3, "Close", "AccountsChanged", "Visible", "ActiveTab"]], template: function StorageProvidersListComponent_Template(rf, ctx) { if (rf & 1) {
408
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: StorageProvidersListComponent, selectors: [["mj-storage-providers-list"]], outputs: { AccountSelected: "AccountSelected", accountSelected: "accountSelected" }, standalone: false, decls: 10, vars: 6, consts: [[1, "providers-list"], [1, "providers-header"], [1, "header-title"], [1, "admin-header-actions"], [1, "loading-state"], ["Variant", "error", "Icon", "fa-solid fa-triangle-exclamation", "Size", "compact", 1, "storage-providers-empty-fill", 3, "Title"], ["Icon", "fa-solid fa-folder-plus", "Size", "compact", 1, "storage-providers-empty-fill", 3, "Title", "Message"], [1, "providers-container"], [3, "Visible", "ActiveTab"], ["type", "button", "title", "Add Storage Account", 1, "admin-action-btn", 3, "click"], [1, "fa-solid", "fa-plus"], ["type", "button", "title", "Manage Storage Providers & Accounts", 1, "admin-action-btn", 3, "click"], [1, "fa-solid", "fa-gear"], ["text", "Loading accounts..."], ["type", "button", 1, "mj-empty-action-btn"], ["type", "button", 1, "mj-empty-action-btn", 3, "click"], [1, "provider-item", 3, "selected", "title"], [1, "provider-item", 3, "click", "title"], [1, "provider-icon"], [1, "provider-info"], [1, "provider-name"], [1, "provider-meta"], [1, "provider-type-badge", 3, "title"], ["title", "Supports search", 1, "search-badge"], ["title", "Credentials configured", 1, "credential-badge"], ["title", "No credentials configured", 1, "unconfigured-badge"], ["type", "button", "title", "Edit Storage Account", 1, "provider-edit-btn"], [1, "fa-solid", "fa-magnifying-glass"], [1, "fa-solid", "fa-key"], [1, "fa-solid", "fa-exclamation-triangle"], ["type", "button", "title", "Edit Storage Account", 1, "provider-edit-btn", 3, "click"], [1, "fa-solid", "fa-pen-to-square"], [3, "Close", "AccountsChanged", "Visible", "ActiveTab"]], template: function StorageProvidersListComponent_Template(rf, ctx) { if (rf & 1) {
321
409
  i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "span", 2);
322
410
  i0.ɵɵtext(3, "Storage Accounts");
323
411
  i0.ɵɵelementEnd();
@@ -347,7 +435,9 @@ export class StorageProvidersListComponent {
347
435
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(StorageProvidersListComponent, [{
348
436
  type: Component,
349
437
  args: [{ standalone: false, selector: 'mj-storage-providers-list', template: "<div class=\"providers-list\">\n <!-- Header -->\n <div class=\"providers-header\">\n <span class=\"header-title\">Storage Accounts</span>\n @if (userCanManage) {\n <div class=\"admin-header-actions\">\n <button\n type=\"button\"\n class=\"admin-action-btn\"\n title=\"Add Storage Account\"\n (click)=\"openAdminDialog('accounts')\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n <button\n type=\"button\"\n class=\"admin-action-btn\"\n title=\"Manage Storage Providers & Accounts\"\n (click)=\"openAdminDialog('accounts')\">\n <i class=\"fa-solid fa-gear\"></i>\n </button>\n </div>\n }\n </div>\n\n <!-- Loading State -->\n @if (isLoading) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading accounts...\"></mj-loading>\n </div>\n }\n\n <!-- Error State -->\n @if (errorMessage && !isLoading) {\n <mj-empty-state\n class=\"storage-providers-empty-fill\"\n Variant=\"error\"\n Icon=\"fa-solid fa-triangle-exclamation\"\n [Title]=\"errorMessage\"\n Size=\"compact\" />\n }\n\n <!-- Empty State -->\n @if (!isLoading && !errorMessage && accounts.length === 0) {\n <mj-empty-state\n class=\"storage-providers-empty-fill\"\n Icon=\"fa-solid fa-folder-plus\"\n [Title]=\"userCanManage ? 'No storage accounts configured' : 'No storage accounts available'\"\n [Message]=\"userCanManage ? 'Configure storage accounts to connect MemberJunction to cloud storage providers.' : 'Contact your administrator to set up file storage accounts.'\"\n Size=\"compact\">\n @if (userCanManage) {\n <button\n type=\"button\"\n class=\"mj-empty-action-btn\"\n (click)=\"openAdminDialog('accounts')\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>Configure Account</span>\n </button>\n }\n </mj-empty-state>\n }\n\n <!-- Account List -->\n @if (!isLoading && !errorMessage && accounts.length > 0) {\n <div class=\"providers-container\">\n @for (item of accounts; track item.account.ID) {\n <div\n class=\"provider-item\"\n [class.selected]=\"isSelected(item)\"\n (click)=\"selectAccount(item)\"\n [title]=\"item.account.Description || item.account.Name\">\n <div class=\"provider-icon\">\n <i [class]=\"getProviderIcon(item.provider.Name)\"></i>\n </div>\n <div class=\"provider-info\">\n <div class=\"provider-name\">{{ item.account.Name }}</div>\n <div class=\"provider-meta\">\n <!-- Provider type badge -->\n <span class=\"provider-type-badge\" [title]=\"item.provider.Name\">\n {{ item.provider.Name }}\n </span>\n <!-- Search support badge -->\n @if (item.provider.SupportsSearch) {\n <span class=\"search-badge\" title=\"Supports search\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n </span>\n }\n <!-- Credential configured badge -->\n @if (item.account.CredentialID) {\n <span class=\"credential-badge\" title=\"Credentials configured\">\n <i class=\"fa-solid fa-key\"></i>\n </span>\n }\n <!-- No credential warning -->\n @if (!item.account.CredentialID) {\n <span class=\"unconfigured-badge\" title=\"No credentials configured\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n </span>\n }\n </div>\n </div>\n @if (userCanManage) {\n <button\n type=\"button\"\n class=\"provider-edit-btn\"\n title=\"Edit Storage Account\"\n (click)=\"onEditAccountClick(item, $event)\">\n <i class=\"fa-solid fa-pen-to-square\"></i>\n </button>\n }\n </div>\n }\n </div>\n }\n</div>\n\n<!-- Storage Administration Dialog -->\n@if (isManageDialogOpen) {\n <mj-storage-admin-dialog\n [Visible]=\"isManageDialogOpen\"\n [ActiveTab]=\"adminDialogTab\"\n (Close)=\"closeAdminDialog()\"\n (AccountsChanged)=\"onAdminAccountsChanged()\">\n </mj-storage-admin-dialog>\n}\n", styles: ["/* ===========================\n Storage Providers List\n =========================== */\n\n.providers-list {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n\n/* Header with Add Button */\n.providers-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n background-color: var(--mj-bg-surface-card);\n}\n\n.header-title {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.admin-header-actions {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.admin-action-btn {\n width: 26px;\n height: 26px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm, 6px);\n background-color: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.15s ease;\n font-size: 11px;\n}\n\n.admin-action-btn:hover {\n background-color: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.provider-edit-btn {\n width: 24px;\n height: 24px;\n border: none;\n border-radius: var(--mj-radius-sm, 4px);\n background-color: transparent;\n color: var(--mj-text-muted);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.15s ease;\n font-size: 11px;\n opacity: 0;\n margin-left: 6px;\n flex-shrink: 0;\n}\n\n.provider-item:hover .provider-edit-btn {\n opacity: 1;\n}\n\n.provider-edit-btn:hover {\n background-color: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.mj-empty-action-btn {\n margin-top: 12px;\n padding: 6px 12px;\n border-radius: var(--mj-radius-sm, 6px);\n border: 1px solid transparent;\n background-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse, #ffffff);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n transition: background-color 0.12s;\n}\n\n.mj-empty-action-btn:hover {\n background-color: var(--mj-brand-primary-hover);\n}\n\n.add-provider-btn {\n width: 28px;\n height: 28px;\n border: none;\n border-radius: 50%;\n background-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease;\n font-size: 14px;\n}\n\n.add-provider-btn:hover:not(:disabled) {\n background-color: var(--mj-brand-primary-hover);\n transform: scale(1.05);\n}\n\n.add-provider-btn:disabled {\n background-color: var(--mj-border-strong);\n cursor: not-allowed;\n}\n\n/* Loading State */\n.loading-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 24px;\n text-align: center;\n color: var(--mj-text-muted);\n flex: 1;\n}\n\n/* Empty/error states fill the panel vertically (flex-parent gotcha) */\n.storage-providers-empty-fill {\n flex: 1;\n}\n\n/* Provider List Container */\n.providers-container {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\n/* Individual Provider Item */\n.provider-item {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n cursor: pointer;\n transition: all 0.2s ease;\n border-bottom: 1px solid var(--mj-bg-surface-sunken);\n position: relative;\n}\n\n.provider-item:hover {\n background-color: var(--mj-bg-surface-card);\n}\n\n.provider-item.selected {\n background-color: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n.provider-item.selected::before {\n content: '';\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 3px;\n background-color: var(--mj-brand-primary);\n}\n\n/* Provider Icon */\n.provider-icon {\n flex-shrink: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 20px;\n color: var(--mj-text-secondary);\n margin-right: 12px;\n}\n\n.provider-item.selected .provider-icon {\n color: var(--mj-brand-primary);\n}\n\n/* Provider Info */\n.provider-info {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.provider-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.provider-item.selected .provider-name {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.provider-meta {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n/* Default Badge */\n.default-badge {\n display: inline-flex;\n align-items: center;\n color: var(--mj-status-warning);\n}\n\n.default-badge i {\n font-size: 10px;\n}\n\n/* Provider Type Badge */\n.provider-type-badge {\n display: inline-flex;\n align-items: center;\n padding: 2px 6px;\n background-color: var(--mj-bg-surface-sunken);\n border-radius: 10px;\n font-size: 10px;\n color: var(--mj-text-secondary);\n max-width: 100px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.provider-item.selected .provider-type-badge {\n background-color: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n color: var(--mj-brand-primary);\n}\n\n/* Search Badge */\n.search-badge {\n display: inline-flex;\n align-items: center;\n padding: 2px 6px;\n background-color: var(--mj-bg-surface-sunken);\n border-radius: 10px;\n font-size: 10px;\n color: var(--mj-text-secondary);\n}\n\n.provider-item.selected .search-badge {\n background-color: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.search-badge i {\n font-size: 9px;\n}\n\n/* Credential Badge */\n.credential-badge {\n display: inline-flex;\n align-items: center;\n padding: 2px 6px;\n background-color: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n border-radius: 10px;\n font-size: 10px;\n color: var(--mj-status-success);\n}\n\n.provider-item.selected .credential-badge {\n background-color: color-mix(in srgb, var(--mj-status-success) 15%, transparent);\n color: var(--mj-status-success);\n}\n\n.credential-badge i {\n font-size: 9px;\n}\n\n/* Unconfigured Badge */\n.unconfigured-badge {\n display: inline-flex;\n align-items: center;\n color: var(--mj-status-warning);\n}\n\n.unconfigured-badge i {\n font-size: 10px;\n}\n\n/* OAuth Status Badges */\n.oauth-connected-badge {\n display: inline-flex;\n align-items: center;\n padding: 2px 6px;\n background-color: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n border-radius: 10px;\n font-size: 10px;\n color: var(--mj-status-success);\n}\n\n.oauth-connected-badge i {\n font-size: 9px;\n}\n\n.oauth-disconnected-badge {\n display: inline-flex;\n align-items: center;\n padding: 2px 6px;\n background-color: color-mix(in srgb, var(--mj-status-warning) 8%, var(--mj-bg-surface));\n border-radius: 10px;\n font-size: 10px;\n color: var(--mj-status-warning);\n}\n\n.oauth-disconnected-badge i {\n font-size: 9px;\n}\n\n/* Provider Actions (OAuth connect/disconnect buttons) */\n.provider-actions {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-left: 8px;\n}\n\n.connect-btn,\n.disconnect-btn {\n width: 26px;\n height: 26px;\n border: none;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease;\n font-size: 12px;\n}\n\n.connect-btn {\n background-color: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.connect-btn:hover:not(:disabled) {\n background-color: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n transform: scale(1.05);\n}\n\n.connect-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.disconnect-btn {\n background-color: transparent;\n color: var(--mj-text-muted);\n}\n\n.disconnect-btn:hover {\n background-color: color-mix(in srgb, var(--mj-status-error) 8%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n/* Remove Provider Button */\n.remove-provider-btn {\n width: 24px;\n height: 24px;\n border: none;\n border-radius: 50%;\n background-color: transparent;\n color: var(--mj-text-disabled);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease;\n font-size: 12px;\n opacity: 0;\n margin-left: 8px;\n}\n\n.provider-item:hover .remove-provider-btn {\n opacity: 1;\n}\n\n.remove-provider-btn:hover:not(:disabled) {\n background-color: color-mix(in srgb, var(--mj-status-error) 8%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.remove-provider-btn:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Scrollbar Styling */\n.providers-container::-webkit-scrollbar {\n width: 6px;\n}\n\n.providers-container::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.providers-container::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 3px;\n}\n\n.providers-container::-webkit-scrollbar-thumb:hover {\n background: var(--mj-text-disabled);\n}\n\n/* ===========================\n Add Provider Dialog\n =========================== */\n\n.add-provider-dialog {\n min-height: 150px;\n}\n\n.dialog-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n}\n\n.dialog-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 30px 20px;\n text-align: center;\n}\n\n.dialog-empty-icon {\n font-size: 40px;\n color: var(--mj-status-success);\n margin-bottom: 12px;\n}\n\n.dialog-empty-message {\n font-size: 16px;\n font-weight: 500;\n color: var(--mj-text-primary);\n margin: 0 0 4px 0;\n}\n\n.dialog-empty-hint {\n font-size: 13px;\n color: var(--mj-text-muted);\n margin: 0;\n}\n\n.dialog-instruction {\n font-size: 13px;\n color: var(--mj-text-secondary);\n margin: 0 0 12px 0;\n padding: 0 4px;\n}\n\n.available-providers {\n max-height: 350px;\n overflow-y: auto;\n}\n\n.available-provider-item {\n display: flex;\n align-items: center;\n padding: 12px;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n margin-bottom: 8px;\n border: 1px solid var(--mj-border-default);\n}\n\n.available-provider-item:hover:not(.disabled) {\n background-color: var(--mj-bg-surface-card);\n border-color: var(--mj-brand-primary);\n}\n\n.available-provider-item.disabled {\n opacity: 0.6;\n cursor: not-allowed;\n background-color: var(--mj-bg-surface-card);\n}\n\n.available-provider-item .provider-icon {\n margin-right: 12px;\n}\n\n.available-provider-item .provider-info {\n flex: 1;\n}\n\n.available-provider-item .provider-name {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.available-provider-item .provider-description {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n line-height: 1.3;\n}\n\n.available-provider-item .provider-warning {\n font-size: 11px;\n color: var(--mj-status-warning);\n margin-top: 4px;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.available-provider-item .provider-warning i {\n font-size: 10px;\n}\n\n/* OAuth hint in add provider dialog */\n.available-provider-item .oauth-hint {\n font-size: 11px;\n color: var(--mj-brand-primary);\n margin-top: 4px;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.available-provider-item .oauth-hint i {\n font-size: 10px;\n}\n\n.available-provider-item.oauth-provider {\n border-color: var(--mj-brand-primary);\n border-style: dashed;\n}\n\n.available-provider-item.oauth-provider:hover:not(.disabled) {\n background-color: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-style: solid;\n}\n\n.add-indicator {\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n/* Responsive Adjustments */\n@media screen and (max-width: 768px) {\n .providers-header {\n padding: 10px 12px;\n }\n\n .header-title {\n font-size: 12px;\n }\n\n .add-provider-btn {\n width: 26px;\n height: 26px;\n font-size: 12px;\n }\n\n .provider-item {\n padding: 10px 12px;\n }\n\n .provider-icon {\n width: 28px;\n height: 28px;\n font-size: 18px;\n margin-right: 10px;\n }\n\n .provider-name {\n font-size: 12px;\n }\n\n .provider-status {\n font-size: 10px;\n }\n\n .remove-provider-btn {\n width: 22px;\n height: 22px;\n font-size: 11px;\n opacity: 1;\n }\n}\n"] }]
350
- }], () => [], { accountSelected: [{
438
+ }], () => [], { AccountSelected: [{
439
+ type: Output
440
+ }], accountSelected: [{
351
441
  type: Output
352
442
  }] }); })();
353
443
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(StorageProvidersListComponent, { className: "StorageProvidersListComponent", filePath: "src/lib/file-browser/storage-providers-list.component.ts", lineNumber: 19 }); })();