@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.
- package/dist/lib/admin/storage-admin-dialog.component.d.ts +1 -1
- package/dist/lib/admin/storage-admin-dialog.component.js +2 -2
- package/dist/lib/admin/storage-admin-dialog.component.js.map +1 -1
- package/dist/lib/category-tree/category-tree.d.ts +83 -9
- package/dist/lib/category-tree/category-tree.d.ts.map +1 -1
- package/dist/lib/category-tree/category-tree.js +192 -50
- package/dist/lib/category-tree/category-tree.js.map +1 -1
- package/dist/lib/file-browser/file-browser.component.d.ts +30 -4
- package/dist/lib/file-browser/file-browser.component.d.ts.map +1 -1
- package/dist/lib/file-browser/file-browser.component.js +68 -16
- package/dist/lib/file-browser/file-browser.component.js.map +1 -1
- package/dist/lib/file-browser/file-grid.component.d.ts +404 -58
- package/dist/lib/file-browser/file-grid.component.d.ts.map +1 -1
- package/dist/lib/file-browser/file-grid.component.js +1040 -396
- package/dist/lib/file-browser/file-grid.component.js.map +1 -1
- package/dist/lib/file-browser/folder-tree.component.d.ts +65 -9
- package/dist/lib/file-browser/folder-tree.component.d.ts.map +1 -1
- package/dist/lib/file-browser/folder-tree.component.js +166 -58
- package/dist/lib/file-browser/folder-tree.component.js.map +1 -1
- package/dist/lib/file-browser/storage-providers-list.component.d.ts +55 -7
- package/dist/lib/file-browser/storage-providers-list.component.d.ts.map +1 -1
- package/dist/lib/file-browser/storage-providers-list.component.js +124 -34
- package/dist/lib/file-browser/storage-providers-list.component.js.map +1 -1
- package/dist/lib/file-upload/file-upload.d.ts +22 -2
- package/dist/lib/file-upload/file-upload.d.ts.map +1 -1
- package/dist/lib/file-upload/file-upload.js +40 -10
- package/dist/lib/file-upload/file-upload.js.map +1 -1
- package/dist/lib/files-grid/files-grid.d.ts +28 -4
- package/dist/lib/files-grid/files-grid.d.ts.map +1 -1
- package/dist/lib/files-grid/files-grid.js +71 -23
- package/dist/lib/files-grid/files-grid.js.map +1 -1
- package/dist/lib/record-attachments/record-attachments.component.d.ts +15 -7
- package/dist/lib/record-attachments/record-attachments.component.d.ts.map +1 -1
- package/dist/lib/record-attachments/record-attachments.component.js +34 -18
- package/dist/lib/record-attachments/record-attachments.component.js.map +1 -1
- package/package.json +13 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-providers-list.component.js","sourceRoot":"","sources":["../../../src/lib/file-browser/storage-providers-list.component.ts","../../../src/lib/file-browser/storage-providers-list.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, OnInit, Output, ChangeDetectorRef, inject } from '@angular/core';\nimport { FileStorageEngineBase, StorageAccountWithProvider, MJFileStorageAccountEntity } from '@memberjunction/core-entities';\nimport { Metadata, type IMetadataProvider } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { StorageAdminTab } from '../admin/storage-admin-dialog.component';\n\n/**\n * Displays a list of organizational file storage accounts.\n * In the enterprise model, accounts are configured by administrators\n * and available to users based on permissions. Users no longer manage\n * their own OAuth connections - credentials are handled at the org level.\n */\n@Component({\n standalone: false,\n selector: 'mj-storage-providers-list',\n templateUrl: './storage-providers-list.component.html',\n styleUrls: ['./storage-providers-list.component.css']\n})\nexport class StorageProvidersListComponent implements OnInit {\n private cdr = inject(ChangeDetectorRef);\n\n /**\n * Emits when an account is selected by the user, or null when no accounts are available.\n * Emits the full account-with-provider object for downstream components to use.\n */\n @Output() accountSelected = new EventEmitter<StorageAccountWithProvider | null>();\n\n /**\n * All available storage accounts with their provider details.\n */\n public accounts: StorageAccountWithProvider[] = [];\n\n /**\n * Currently selected account.\n */\n public selectedAccount: StorageAccountWithProvider | null = null;\n\n /**\n * Loading state indicator.\n */\n public isLoading: boolean = false;\n\n /**\n * Error message if loading fails.\n */\n public errorMessage: string | null = null;\n\n /**\n * Whether current user has admin rights to configure storage accounts or providers.\n */\n public userCanManage: boolean = false;\n\n /**\n * Admin dialog state\n */\n public isManageDialogOpen: boolean = false;\n public adminDialogTab: StorageAdminTab = 'accounts';\n public accountToEdit: MJFileStorageAccountEntity | null = null;\n\n public Provider: IMetadataProvider | null = null;\n\n public get ProviderToUse(): IMetadataProvider {\n return this.Provider ?? Metadata.Provider;\n }\n\n constructor() {}\n\n ngOnInit(): void {\n if (!this.userCanManage) {\n this.checkPermissions();\n }\n this.loadAccounts();\n }\n\n /**\n * Checks if current user has create or update permissions on storage entities.\n */\n private checkPermissions(): void {\n try {\n const md = this.ProviderToUse;\n const user = md.CurrentUser;\n if (!user) {\n return;\n }\n\n const provEntity = md.Entities.find(e => e.Name === 'MJ: File Storage Providers');\n const acctEntity = md.Entities.find(e => e.Name === 'MJ: File Storage Accounts');\n\n const provCanManage = provEntity ? provEntity.GetUserPermisions(user).CanCreate || provEntity.GetUserPermisions(user).CanUpdate : false;\n const acctCanManage = acctEntity ? acctEntity.GetUserPermisions(user).CanCreate || acctEntity.GetUserPermisions(user).CanUpdate : false;\n\n this.userCanManage = !!(provCanManage || acctCanManage);\n } catch {\n this.userCanManage = false;\n }\n }\n\n /**\n * Loads all available file storage accounts with their provider details.\n * Uses FileStorageEngineBase for centralized, cached access.\n */\n private async loadAccounts(forceRefresh = false): Promise<void> {\n this.isLoading = true;\n this.errorMessage = null;\n\n try {\n const engine = FileStorageEngineBase.Instance;\n await engine.Config(forceRefresh);\n\n // Only show accounts whose provider is active\n this.accounts = engine.AccountsWithProviders.filter(a => a.provider.IsActive !== false);\n\n if (this.accounts.length === 0 && !forceRefresh) {\n await engine.Config(true);\n this.accounts = engine.AccountsWithProviders.filter(a => a.provider.IsActive !== false);\n }\n\n console.log('[StorageAccountsList] Loaded accounts:', this.accounts.map(a => ({\n name: a.account.Name,\n provider: a.provider.Name,\n hasCredential: !!a.account.CredentialID\n })));\n\n // Auto-select first account if available\n if (this.accounts.length > 0) {\n this.selectAccount(this.accounts[0]);\n } else {\n this.accountSelected.emit(null);\n }\n\n } catch (error) {\n this.errorMessage = error instanceof Error ? error.message : 'Failed to load storage accounts';\n console.error('[StorageProvidersList] Error loading accounts:', error);\n } finally {\n this.isLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Handles account selection by the user.\n */\n public selectAccount(accountWithProvider: StorageAccountWithProvider): void {\n this.selectedAccount = accountWithProvider;\n this.accountSelected.emit(accountWithProvider);\n }\n\n /**\n * Checks if an account is currently selected.\n */\n public isSelected(accountWithProvider: StorageAccountWithProvider): boolean {\n return UUIDsEqual(this.selectedAccount?.account.ID, accountWithProvider.account.ID);\n }\n\n /**\n * Gets the icon class for a provider based on its name.\n */\n public getProviderIcon(providerName: string): string {\n const name = providerName.toLowerCase();\n\n if (name.includes('aws') || name.includes('s3')) {\n return 'fa-brands fa-aws';\n } else if (name.includes('azure')) {\n return 'fa-brands fa-microsoft';\n } else if (name.includes('google drive')) {\n return 'fa-brands fa-google-drive';\n } else if (name.includes('google cloud')) {\n return 'fa-brands fa-google';\n } else if (name.includes('dropbox')) {\n return 'fa-brands fa-dropbox';\n } else if (name.includes('box')) {\n return 'fa-solid fa-box';\n } else if (name.includes('sharepoint') || name.includes('onedrive')) {\n return 'fa-brands fa-microsoft';\n } else {\n return 'fa-solid fa-cloud';\n }\n }\n\n /**\n * Refreshes the accounts list by forcing a reload from the database.\n */\n public refresh(): void {\n void this.loadAccounts(true);\n }\n\n /**\n * Opens the storage administration dialog\n */\n public openAdminDialog(tab: StorageAdminTab = 'accounts', account?: MJFileStorageAccountEntity | null): void {\n this.adminDialogTab = tab;\n this.accountToEdit = account ?? null;\n this.isManageDialogOpen = true;\n this.cdr.markForCheck();\n }\n\n /**\n * Closes the storage administration dialog\n */\n public closeAdminDialog(): void {\n this.isManageDialogOpen = false;\n this.accountToEdit = null;\n this.cdr.markForCheck();\n }\n\n /**\n * Handles storage configuration changes from the admin dialog\n */\n public onAdminAccountsChanged(): void {\n this.refresh();\n }\n\n /**\n * Handles inline edit click on an account item\n */\n public onEditAccountClick(item: StorageAccountWithProvider, event: MouseEvent): void {\n event.stopPropagation();\n this.openAdminDialog('accounts', item.account);\n }\n}\n","<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"]}
|
|
1
|
+
{"version":3,"file":"storage-providers-list.component.js","sourceRoot":"","sources":["../../../src/lib/file-browser/storage-providers-list.component.ts","../../../src/lib/file-browser/storage-providers-list.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, OnInit, Output, ChangeDetectorRef, inject } from '@angular/core';\nimport { FileStorageEngineBase, StorageAccountWithProvider, MJFileStorageAccountEntity } from '@memberjunction/core-entities';\nimport { Metadata, type IMetadataProvider } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { StorageAdminTab } from '../admin/storage-admin-dialog.component';\n\n/**\n * Displays a list of organizational file storage accounts.\n * In the enterprise model, accounts are configured by administrators\n * and available to users based on permissions. Users no longer manage\n * their own OAuth connections - credentials are handled at the org level.\n */\n@Component({\n standalone: false,\n selector: 'mj-storage-providers-list',\n templateUrl: './storage-providers-list.component.html',\n styleUrls: ['./storage-providers-list.component.css']\n})\nexport class StorageProvidersListComponent implements OnInit {\n private cdr = inject(ChangeDetectorRef);\n\n /**\n * Emits when an account is selected by the user, or null when no accounts are available.\n * Emits the full account-with-provider object for downstream components to use.\n */\n @Output() AccountSelected = new EventEmitter<StorageAccountWithProvider | null>();\n\n /**\n * @deprecated Use {@link AccountSelected}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (accountSelected) keeps working. Must stay AFTER AccountSelected: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() accountSelected = this.AccountSelected;\n\n /**\n * All available storage accounts with their provider details.\n */\n public Accounts: StorageAccountWithProvider[] = [];\n\n /** @deprecated Use {@link Accounts}. */\n public get accounts(): StorageAccountWithProvider[] {\n return this.Accounts;\n }\n /** @deprecated Use {@link Accounts}. */\n public set accounts(value: StorageAccountWithProvider[]) {\n this.Accounts = value;\n }\n\n /**\n * Currently selected account.\n */\n public SelectedAccount: StorageAccountWithProvider | null = null;\n\n /** @deprecated Use {@link SelectedAccount}. */\n public get selectedAccount(): StorageAccountWithProvider | null {\n return this.SelectedAccount;\n }\n /** @deprecated Use {@link SelectedAccount}. */\n public set selectedAccount(value: StorageAccountWithProvider | null) {\n this.SelectedAccount = value;\n }\n\n /**\n * Loading state indicator.\n */\n public isLoading: boolean = false;\n\n /**\n * Error message if loading fails.\n */\n public errorMessage: string | null = null;\n\n /**\n * Whether current user has admin rights to configure storage accounts or providers.\n */\n public UserCanManage: boolean = false;\n\n /** @deprecated Use {@link UserCanManage}. */\n public get userCanManage(): boolean {\n return this.UserCanManage;\n }\n /** @deprecated Use {@link UserCanManage}. */\n public set userCanManage(value: boolean) {\n this.UserCanManage = value;\n }\n\n /**\n * Admin dialog state\n */\n public IsManageDialogOpen: boolean = false;\n\n /** @deprecated Use {@link IsManageDialogOpen}. */\n public get isManageDialogOpen(): boolean {\n return this.IsManageDialogOpen;\n }\n /** @deprecated Use {@link IsManageDialogOpen}. */\n public set isManageDialogOpen(value: boolean) {\n this.IsManageDialogOpen = value;\n }\n public AdminDialogTab: StorageAdminTab = 'accounts';\n\n /** @deprecated Use {@link AdminDialogTab}. */\n public get adminDialogTab(): StorageAdminTab {\n return this.AdminDialogTab;\n }\n /** @deprecated Use {@link AdminDialogTab}. */\n public set adminDialogTab(value: StorageAdminTab) {\n this.AdminDialogTab = value;\n }\n public AccountToEdit: MJFileStorageAccountEntity | null = null;\n\n /** @deprecated Use {@link AccountToEdit}. */\n public get accountToEdit(): MJFileStorageAccountEntity | null {\n return this.AccountToEdit;\n }\n /** @deprecated Use {@link AccountToEdit}. */\n public set accountToEdit(value: MJFileStorageAccountEntity | null) {\n this.AccountToEdit = value;\n }\n\n public Provider: IMetadataProvider | null = null;\n\n public get ProviderToUse(): IMetadataProvider {\n return this.Provider ?? Metadata.Provider;\n }\n\n constructor() {}\n\n ngOnInit(): void {\n if (!this.UserCanManage) {\n this.checkPermissions();\n }\n this.loadAccounts();\n }\n\n /**\n * Checks if current user has create or update permissions on storage entities.\n */\n private checkPermissions(): void {\n try {\n const md = this.ProviderToUse;\n const user = md.CurrentUser;\n if (!user) {\n return;\n }\n\n const provEntity = md.Entities.find(e => e.Name === 'MJ: File Storage Providers');\n const acctEntity = md.Entities.find(e => e.Name === 'MJ: File Storage Accounts');\n\n const provCanManage = provEntity ? provEntity.GetUserPermisions(user).CanCreate || provEntity.GetUserPermisions(user).CanUpdate : false;\n const acctCanManage = acctEntity ? acctEntity.GetUserPermisions(user).CanCreate || acctEntity.GetUserPermisions(user).CanUpdate : false;\n\n this.UserCanManage = !!(provCanManage || acctCanManage);\n } catch {\n this.UserCanManage = false;\n }\n }\n\n /**\n * Loads all available file storage accounts with their provider details.\n * Uses FileStorageEngineBase for centralized, cached access.\n */\n private async loadAccounts(forceRefresh = false): Promise<void> {\n this.isLoading = true;\n this.errorMessage = null;\n\n try {\n const engine = FileStorageEngineBase.Instance;\n await engine.Config(forceRefresh);\n\n // Only show accounts whose provider is active\n this.Accounts = engine.AccountsWithProviders.filter(a => a.provider.IsActive !== false);\n\n if (this.Accounts.length === 0 && !forceRefresh) {\n await engine.Config(true);\n this.Accounts = engine.AccountsWithProviders.filter(a => a.provider.IsActive !== false);\n }\n\n console.log('[StorageAccountsList] Loaded accounts:', this.Accounts.map(a => ({\n name: a.account.Name,\n provider: a.provider.Name,\n hasCredential: !!a.account.CredentialID\n })));\n\n // Auto-select first account if available\n if (this.Accounts.length > 0) {\n this.SelectAccount(this.Accounts[0]);\n } else {\n this.AccountSelected.emit(null);\n }\n\n } catch (error) {\n this.errorMessage = error instanceof Error ? error.message : 'Failed to load storage accounts';\n console.error('[StorageProvidersList] Error loading accounts:', error);\n } finally {\n this.isLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Handles account selection by the user.\n */\n public SelectAccount(accountWithProvider: StorageAccountWithProvider): void {\n this.SelectedAccount = accountWithProvider;\n this.AccountSelected.emit(accountWithProvider);\n }\n\n /** @deprecated Use {@link SelectAccount}. */\n public selectAccount(accountWithProvider: StorageAccountWithProvider): void {\n return this.SelectAccount(accountWithProvider);\n }\n\n /**\n * Checks if an account is currently selected.\n */\n public IsSelected(accountWithProvider: StorageAccountWithProvider): boolean {\n return UUIDsEqual(this.SelectedAccount?.account.ID, accountWithProvider.account.ID);\n }\n\n /** @deprecated Use {@link IsSelected}. */\n public isSelected(accountWithProvider: StorageAccountWithProvider): boolean {\n return this.IsSelected(accountWithProvider);\n }\n\n /**\n * Gets the icon class for a provider based on its name.\n */\n public GetProviderIcon(providerName: string): string {\n const name = providerName.toLowerCase();\n\n if (name.includes('aws') || name.includes('s3')) {\n return 'fa-brands fa-aws';\n } else if (name.includes('azure')) {\n return 'fa-brands fa-microsoft';\n } else if (name.includes('google drive')) {\n return 'fa-brands fa-google-drive';\n } else if (name.includes('google cloud')) {\n return 'fa-brands fa-google';\n } else if (name.includes('dropbox')) {\n return 'fa-brands fa-dropbox';\n } else if (name.includes('box')) {\n return 'fa-solid fa-box';\n } else if (name.includes('sharepoint') || name.includes('onedrive')) {\n return 'fa-brands fa-microsoft';\n } else {\n return 'fa-solid fa-cloud';\n }\n }\n\n /** @deprecated Use {@link GetProviderIcon}. */\n public getProviderIcon(providerName: string): string {\n return this.GetProviderIcon(providerName);\n }\n\n /**\n * Refreshes the accounts list by forcing a reload from the database.\n */\n public Refresh(): void {\n void this.loadAccounts(true);\n }\n\n /** @deprecated Use {@link Refresh}. */\n public refresh(): void {\n return this.Refresh();\n }\n\n /**\n * Opens the storage administration dialog\n */\n public OpenAdminDialog(tab: StorageAdminTab = 'accounts', account?: MJFileStorageAccountEntity | null): void {\n this.AdminDialogTab = tab;\n this.AccountToEdit = account ?? null;\n this.IsManageDialogOpen = true;\n this.cdr.markForCheck();\n }\n\n /** @deprecated Use {@link OpenAdminDialog}. */\n public openAdminDialog(tab: StorageAdminTab = 'accounts', account?: MJFileStorageAccountEntity | null): void {\n return this.OpenAdminDialog(tab, account);\n }\n\n /**\n * Closes the storage administration dialog\n */\n public CloseAdminDialog(): void {\n this.IsManageDialogOpen = false;\n this.AccountToEdit = null;\n this.cdr.markForCheck();\n }\n\n /** @deprecated Use {@link CloseAdminDialog}. */\n public closeAdminDialog(): void {\n return this.CloseAdminDialog();\n }\n\n /**\n * Handles storage configuration changes from the admin dialog\n */\n public OnAdminAccountsChanged(): void {\n this.Refresh();\n }\n\n /** @deprecated Use {@link OnAdminAccountsChanged}. */\n public onAdminAccountsChanged(): void {\n return this.OnAdminAccountsChanged();\n }\n\n /**\n * Handles inline edit click on an account item\n */\n public OnEditAccountClick(item: StorageAccountWithProvider, event: MouseEvent): void {\n event.stopPropagation();\n this.OpenAdminDialog('accounts', item.account);\n }\n\n /** @deprecated Use {@link OnEditAccountClick}. */\n public onEditAccountClick(item: StorageAccountWithProvider, event: MouseEvent): void {\n return this.OnEditAccountClick(item, event);\n }\n}\n","<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"]}
|
|
@@ -145,9 +145,29 @@ export declare class FileUploadComponent extends BaseAngularComponent implements
|
|
|
145
145
|
private get md();
|
|
146
146
|
get IsUploading(): boolean;
|
|
147
147
|
constructor();
|
|
148
|
-
|
|
148
|
+
Disabled: boolean;
|
|
149
|
+
/** @deprecated Use {@link Disabled}. */
|
|
150
|
+
set disabled(value: FileUploadComponent['Disabled']);
|
|
151
|
+
/** @deprecated Use {@link Disabled}. */
|
|
152
|
+
get disabled(): FileUploadComponent['Disabled'];
|
|
149
153
|
CategoryID: string | undefined;
|
|
154
|
+
UploadStarted: EventEmitter<void>;
|
|
155
|
+
/**
|
|
156
|
+
* @deprecated Use {@link UploadStarted}.
|
|
157
|
+
*
|
|
158
|
+
* The same emitter under the old binding name, so a template still binding
|
|
159
|
+
* (uploadStarted) keeps working. Must stay AFTER UploadStarted: class fields
|
|
160
|
+
* initialise in order, and the other way round this captures undefined.
|
|
161
|
+
*/
|
|
150
162
|
uploadStarted: EventEmitter<void>;
|
|
163
|
+
FileUpload: EventEmitter<FileUploadEvent>;
|
|
164
|
+
/**
|
|
165
|
+
* @deprecated Use {@link FileUpload}.
|
|
166
|
+
*
|
|
167
|
+
* The same emitter under the old binding name, so a template still binding
|
|
168
|
+
* (fileUpload) keeps working. Must stay AFTER FileUpload: class fields
|
|
169
|
+
* initialise in order, and the other way round this captures undefined.
|
|
170
|
+
*/
|
|
151
171
|
fileUpload: EventEmitter<FileUploadEvent>;
|
|
152
172
|
ngOnInit(): void;
|
|
153
173
|
Refresh(): Promise<void>;
|
|
@@ -160,7 +180,7 @@ export declare class FileUploadComponent extends BaseAngularComponent implements
|
|
|
160
180
|
private _processUploadQueue;
|
|
161
181
|
private _uploadFile;
|
|
162
182
|
static ɵfac: i0.ɵɵFactoryDeclaration<FileUploadComponent, never>;
|
|
163
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<FileUploadComponent, "mj-files-file-upload", never, { "disabled": { "alias": "disabled"; "required": false; }; "CategoryID": { "alias": "CategoryID"; "required": false; }; }, { "uploadStarted": "uploadStarted"; "fileUpload": "fileUpload"; }, never, never, false, never>;
|
|
183
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<FileUploadComponent, "mj-files-file-upload", never, { "Disabled": { "alias": "Disabled"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "CategoryID": { "alias": "CategoryID"; "required": false; }; }, { "UploadStarted": "UploadStarted"; "uploadStarted": "uploadStarted"; "FileUpload": "FileUpload"; "fileUpload": "fileUpload"; }, never, never, false, never>;
|
|
164
184
|
}
|
|
165
185
|
export {};
|
|
166
186
|
//# sourceMappingURL=file-upload.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-upload.d.ts","sourceRoot":"","sources":["../../../src/lib/file-upload/file-upload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAS,MAAM,EAAU,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAoE,MAAM,+BAA+B,CAAC;AAE/H,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;;AAExB;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,IAAI,CAAC;CACf;AAED,MAAM,MAAM,eAAe,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,YAAY,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC;AAgC/G,QAAA,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAM5B,CAAC;AAEH,KAAK,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAC9E,KAAK,WAAW,GAAG,CAAC,cAAc,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAErD,qBAMa,mBAAoB,SAAQ,oBAAqB,YAAW,MAAM;IACtE,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,CAAM;IACtC,WAAW,EAAE,KAAK,CAAC,cAAc,CAAC,CAAM;IAC/C,OAAO,CAAC,iBAAiB,CAAM;IAC/B,OAAO,KAAK,EAAE,GAAiC;IAE/C,IAAI,WAAW,IAAI,OAAO,CAEzB;;IAIQ,QAAQ,UAAS;
|
|
1
|
+
{"version":3,"file":"file-upload.d.ts","sourceRoot":"","sources":["../../../src/lib/file-upload/file-upload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAS,MAAM,EAAU,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAoE,MAAM,+BAA+B,CAAC;AAE/H,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;;AAExB;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,IAAI,CAAC;CACf;AAED,MAAM,MAAM,eAAe,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,YAAY,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC;AAgC/G,QAAA,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAM5B,CAAC;AAEH,KAAK,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAC9E,KAAK,WAAW,GAAG,CAAC,cAAc,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAErD,qBAMa,mBAAoB,SAAQ,oBAAqB,YAAW,MAAM;IACtE,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,CAAM;IACtC,WAAW,EAAE,KAAK,CAAC,cAAc,CAAC,CAAM;IAC/C,OAAO,CAAC,iBAAiB,CAAM;IAC/B,OAAO,KAAK,EAAE,GAAiC;IAE/C,IAAI,WAAW,IAAI,OAAO,CAEzB;;IAIQ,QAAQ,UAAS;IAE1B,wCAAwC;IACxC,IAAa,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC,UAAU,CAAC,EAE3D;IACD,wCAAwC;IACxC,IAAI,QAAQ,IAAI,mBAAmB,CAAC,UAAU,CAAC,CAE9C;IACQ,UAAU,EAAE,MAAM,GAAG,SAAS,CAAa;IAC1C,aAAa,qBAA4B;IAEnD;;;;;;OAMG;IACO,aAAa,qBAAsB;IACnC,UAAU,gCAAuC;IAE3D;;;;;;OAMG;IACO,UAAU,gCAAmB;IAEvC,QAAQ,IAAI,IAAI;IAIV,OAAO;IAWb,OAAO;IAOD,aAAa;IAanB;;OAEG;IACH,cAAc,CAAC,KAAK,EAAE,KAAK;YAyBb,mBAAmB;YAkCnB,WAAW;yCA7Id,mBAAmB;2CAAnB,mBAAmB;CAqK/B"}
|
|
@@ -58,10 +58,34 @@ export class FileUploadComponent extends BaseAngularComponent {
|
|
|
58
58
|
return this.UploadQueue.length + this.ConfirmQueue.length > 0;
|
|
59
59
|
}
|
|
60
60
|
constructor() { super(); }
|
|
61
|
-
|
|
61
|
+
Disabled = false;
|
|
62
|
+
/** @deprecated Use {@link Disabled}. */
|
|
63
|
+
set disabled(value) {
|
|
64
|
+
this.Disabled = value;
|
|
65
|
+
}
|
|
66
|
+
/** @deprecated Use {@link Disabled}. */
|
|
67
|
+
get disabled() {
|
|
68
|
+
return this.Disabled;
|
|
69
|
+
}
|
|
62
70
|
CategoryID = undefined;
|
|
63
|
-
|
|
64
|
-
|
|
71
|
+
UploadStarted = new EventEmitter();
|
|
72
|
+
/**
|
|
73
|
+
* @deprecated Use {@link UploadStarted}.
|
|
74
|
+
*
|
|
75
|
+
* The same emitter under the old binding name, so a template still binding
|
|
76
|
+
* (uploadStarted) keeps working. Must stay AFTER UploadStarted: class fields
|
|
77
|
+
* initialise in order, and the other way round this captures undefined.
|
|
78
|
+
*/
|
|
79
|
+
uploadStarted = this.UploadStarted;
|
|
80
|
+
FileUpload = new EventEmitter();
|
|
81
|
+
/**
|
|
82
|
+
* @deprecated Use {@link FileUpload}.
|
|
83
|
+
*
|
|
84
|
+
* The same emitter under the old binding name, so a template still binding
|
|
85
|
+
* (fileUpload) keeps working. Must stay AFTER FileUpload: class fields
|
|
86
|
+
* initialise in order, and the other way round this captures undefined.
|
|
87
|
+
*/
|
|
88
|
+
fileUpload = this.FileUpload;
|
|
65
89
|
ngOnInit() {
|
|
66
90
|
this.Refresh();
|
|
67
91
|
}
|
|
@@ -88,7 +112,7 @@ export class FileUploadComponent extends BaseAngularComponent {
|
|
|
88
112
|
const fileEntity = await this.md.GetEntityObject('MJ: Files');
|
|
89
113
|
await fileEntity.LoadFromData(fileRecord);
|
|
90
114
|
await fileEntity.Delete();
|
|
91
|
-
this.
|
|
115
|
+
this.FileUpload.emit({ success: false, file });
|
|
92
116
|
}
|
|
93
117
|
}
|
|
94
118
|
/**
|
|
@@ -99,7 +123,7 @@ export class FileUploadComponent extends BaseAngularComponent {
|
|
|
99
123
|
if (!input.files || input.files.length === 0) {
|
|
100
124
|
return;
|
|
101
125
|
}
|
|
102
|
-
this.
|
|
126
|
+
this.UploadStarted.emit();
|
|
103
127
|
// Convert native File objects to our FileSelectInfo format
|
|
104
128
|
for (let i = 0; i < input.files.length; i++) {
|
|
105
129
|
const nativeFile = input.files[i];
|
|
@@ -141,7 +165,7 @@ export class FileUploadComponent extends BaseAngularComponent {
|
|
|
141
165
|
}
|
|
142
166
|
else {
|
|
143
167
|
console.error('The API returned an unexpected result', parsedResult.error.issues);
|
|
144
|
-
this.
|
|
168
|
+
this.FileUpload.emit({ success: false, file });
|
|
145
169
|
}
|
|
146
170
|
file = this.UploadQueue.shift();
|
|
147
171
|
}
|
|
@@ -160,17 +184,17 @@ export class FileUploadComponent extends BaseAngularComponent {
|
|
|
160
184
|
fileEntity.Status = 'Uploaded';
|
|
161
185
|
await fileEntity.Save();
|
|
162
186
|
// emit an event about a new file uploaded, include the file data
|
|
163
|
-
this.
|
|
187
|
+
this.FileUpload.emit({ success: true, file: fileEntity });
|
|
164
188
|
// Could also emit a progress event with each iteration
|
|
165
189
|
}
|
|
166
190
|
catch (e) {
|
|
167
191
|
console.error(e);
|
|
168
192
|
// something failed when actually uploading or when updating the API, what do to about pending file?
|
|
169
|
-
this.
|
|
193
|
+
this.FileUpload.emit({ success: false, file });
|
|
170
194
|
}
|
|
171
195
|
}
|
|
172
196
|
static ɵfac = function FileUploadComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || FileUploadComponent)(); };
|
|
173
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: FileUploadComponent, selectors: [["mj-files-file-upload"]], inputs: { disabled: "disabled", CategoryID: "CategoryID" }, outputs: { uploadStarted: "uploadStarted", fileUpload: "fileUpload" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 13, vars: 7, consts: [[1, "mj-file-select"], [1, "fa-solid", "fa-upload"], ["type", "file", 1, "mj-file-input", 3, "change", "disabled"], ["Title", "Please confirm", 3, "Close", "Visible", "Width", "MinWidth"], [1, "confirm-message"], ["mjButton", "", "variant", "primary", 3, "click"], ["mjButton", "", 3, "click"]], template: function FileUploadComponent_Template(rf, ctx) { if (rf & 1) {
|
|
197
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: FileUploadComponent, selectors: [["mj-files-file-upload"]], inputs: { Disabled: "Disabled", disabled: "disabled", CategoryID: "CategoryID" }, outputs: { UploadStarted: "UploadStarted", uploadStarted: "uploadStarted", FileUpload: "FileUpload", fileUpload: "fileUpload" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 13, vars: 7, consts: [[1, "mj-file-select"], [1, "fa-solid", "fa-upload"], ["type", "file", 1, "mj-file-input", 3, "change", "disabled"], ["Title", "Please confirm", 3, "Close", "Visible", "Width", "MinWidth"], [1, "confirm-message"], ["mjButton", "", "variant", "primary", 3, "click"], ["mjButton", "", 3, "click"]], template: function FileUploadComponent_Template(rf, ctx) { if (rf & 1) {
|
|
174
198
|
i0.ɵɵelementStart(0, "div")(1, "label", 0);
|
|
175
199
|
i0.ɵɵelement(2, "i", 1);
|
|
176
200
|
i0.ɵɵelementStart(3, "span");
|
|
@@ -204,12 +228,18 @@ export class FileUploadComponent extends BaseAngularComponent {
|
|
|
204
228
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(FileUploadComponent, [{
|
|
205
229
|
type: Component,
|
|
206
230
|
args: [{ standalone: false, selector: 'mj-files-file-upload', template: "<div>\n <label class=\"mj-file-select\" [class.disabled]=\"IsUploading || disabled\">\n <i class=\"fa-solid fa-upload\"></i>\n <span>Select file to upload</span>\n <input\n type=\"file\"\n class=\"mj-file-input\"\n [disabled]=\"IsUploading || disabled\"\n (change)=\"OnFileSelected($event)\" />\n </label>\n\n <mj-dialog\n [Visible]=\"ConfirmQueue.length > 0\"\n Title=\"Please confirm\"\n [Width]=\"450\"\n [MinWidth]=\"250\"\n (Close)=\"CancelConfirm()\">\n @if (ConfirmQueue.length > 0) {\n <p class=\"confirm-message\">\n This will overwrite an existing file named '{{ ConfirmQueue[0][0].name }}'. Are you sure you want to continue?\n </p>\n }\n <mj-dialog-actions>\n <button mjButton variant=\"primary\" (click)=\"Confirm()\">Overwrite</button>\n <button mjButton (click)=\"CancelConfirm()\">Cancel</button>\n </mj-dialog-actions>\n </mj-dialog>\n</div>\n", styles: [".mj-file-select {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n margin: 8px 0;\n border: 1px dashed var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: border-color 0.15s, background-color 0.15s;\n}\n\n.mj-file-select:hover:not(.disabled) {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.mj-file-select.disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n.mj-file-input {\n display: none;\n}\n\n.confirm-message {\n margin: 30px;\n text-align: center;\n color: var(--mj-text-primary);\n}\n"] }]
|
|
207
|
-
}], () => [], {
|
|
231
|
+
}], () => [], { Disabled: [{
|
|
232
|
+
type: Input
|
|
233
|
+
}], disabled: [{
|
|
208
234
|
type: Input
|
|
209
235
|
}], CategoryID: [{
|
|
210
236
|
type: Input
|
|
237
|
+
}], UploadStarted: [{
|
|
238
|
+
type: Output
|
|
211
239
|
}], uploadStarted: [{
|
|
212
240
|
type: Output
|
|
241
|
+
}], FileUpload: [{
|
|
242
|
+
type: Output
|
|
213
243
|
}], fileUpload: [{
|
|
214
244
|
type: Output
|
|
215
245
|
}] }); })();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-upload.js","sourceRoot":"","sources":["../../../src/lib/file-upload/file-upload.ts","../../../src/lib/file-upload/file-upload.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';\nimport { MJFileEntity, MJFileSchema, MJFileStorageProviderEntity, FileStorageEngineBase } from '@memberjunction/core-entities';\nimport { GraphQLDataProvider, gql } from '@memberjunction/graphql-dataprovider';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\nimport { z } from 'zod';\n\n/**\n * Minimal file info interface replacing Kendo's FileInfo.\n */\nexport interface FileSelectInfo {\n name: string;\n size: number;\n rawFile: File;\n}\n\nexport type FileUploadEvent = { success: true; file: MJFileEntity } | { success: false; file: FileSelectInfo };\n\nconst FileFieldsFragment = gql`\n fragment FileFields on MJFile_ {\n Category\n CategoryID\n ContentType\n _mj__CreatedAt\n Description\n ID\n Name\n Provider\n ProviderID\n ProviderKey\n Status\n _mj__UpdatedAt\n }\n`;\n\nconst FileUploadMutation = gql`\n ${FileFieldsFragment}\n mutation CreateFile($input: CreateMJFileInput!) {\n CreateFile(input: $input) {\n NameExists\n UploadUrl\n File {\n ...FileFields\n }\n }\n }\n`;\n\nconst FileUploadMutationSchema = z.object({\n CreateFile: z.object({\n NameExists: z.boolean(),\n UploadUrl: z.string(),\n File: MJFileSchema.omit({ __mj_CreatedAt: true, __mj_UpdatedAt: true }).passthrough(),\n }),\n});\n\ntype ApiFile = z.infer<typeof FileUploadMutationSchema>['CreateFile']['File'];\ntype UploadTuple = [FileSelectInfo, ApiFile, string];\n\n@Component({\n standalone: false,\n selector: 'mj-files-file-upload',\n templateUrl: './file-upload.html',\n styleUrls: ['./file-upload.css'],\n})\nexport class FileUploadComponent extends BaseAngularComponent implements OnInit {\n public ConfirmQueue: Array<UploadTuple> = [];\n public UploadQueue: Array<FileSelectInfo> = [];\n private defaultProviderID = '';\n private get md() { return this.ProviderToUse; }\n\n get IsUploading(): boolean {\n return this.UploadQueue.length + this.ConfirmQueue.length > 0;\n }\n\n constructor() { super(); }\n\n @Input() disabled = false;\n @Input() CategoryID: string | undefined = undefined;\n @Output() uploadStarted = new EventEmitter<void>();\n @Output() fileUpload = new EventEmitter<FileUploadEvent>();\n\n ngOnInit(): void {\n this.Refresh();\n }\n\n async Refresh() {\n await FileStorageEngineBase.Instance.Config(false);\n const activeProviders = FileStorageEngineBase.Instance.Providers\n .filter(p => p.IsActive)\n .sort((a, b) => (b.Priority ?? 0) - (a.Priority ?? 0));\n const provider: MJFileStorageProviderEntity | undefined = activeProviders[0];\n if (typeof provider?.ID === 'string') {\n this.defaultProviderID = provider.ID;\n }\n }\n\n Confirm() {\n const confirmed = this.ConfirmQueue.shift();\n if (confirmed) {\n this._uploadFile(...confirmed);\n }\n }\n\n async CancelConfirm() {\n const cancelled = this.ConfirmQueue.shift();\n if (cancelled) {\n const [file, fileRecord] = cancelled;\n\n const fileEntity: MJFileEntity = await this.md.GetEntityObject('MJ: Files');\n await fileEntity.LoadFromData(fileRecord);\n await fileEntity.Delete();\n\n this.fileUpload.emit({ success: false, file });\n }\n }\n\n /**\n * Handles the native file input change event.\n */\n OnFileSelected(event: Event) {\n const input = event.target as HTMLInputElement;\n if (!input.files || input.files.length === 0) {\n return;\n }\n\n this.uploadStarted.emit();\n\n // Convert native File objects to our FileSelectInfo format\n for (let i = 0; i < input.files.length; i++) {\n const nativeFile = input.files[i];\n const fileInfo: FileSelectInfo = {\n name: nativeFile.name,\n size: nativeFile.size,\n rawFile: nativeFile,\n };\n this.UploadQueue.push(fileInfo);\n }\n\n // Reset input so the same file can be selected again\n input.value = '';\n\n this._processUploadQueue();\n }\n\n private async _processUploadQueue() {\n // for each selected file to upload\n let file = this.UploadQueue.shift();\n while (file) {\n const input = {\n Name: file.name,\n ProviderID: this.defaultProviderID,\n Status: 'Pending',\n CategoryID: this.CategoryID,\n };\n\n // call the gql\n const result = await GraphQLDataProvider.ExecuteGQL(FileUploadMutation, { input });\n\n // make sure the response is correct\n const parsedResult = FileUploadMutationSchema.safeParse(result);\n if (parsedResult.success) {\n const { File, UploadUrl, NameExists } = parsedResult.data.CreateFile;\n const uploadTuple: UploadTuple = [file, File, UploadUrl];\n\n // Confirm we want to overwrite\n if (NameExists) {\n this.ConfirmQueue.push(uploadTuple);\n } else {\n await this._uploadFile(...uploadTuple);\n }\n } else {\n console.error('The API returned an unexpected result', parsedResult.error.issues);\n this.fileUpload.emit({ success: false, file });\n }\n file = this.UploadQueue.shift();\n }\n }\n\n private async _uploadFile(file: FileSelectInfo, fileRecord: ApiFile, uploadUrl: string) {\n try {\n // now upload to the url\n await window.fetch(uploadUrl, {\n method: 'PUT',\n headers: { 'x-ms-blob-type': 'BlockBlob' },\n body: file.rawFile,\n });\n\n // now update that file to set status\n const fileEntity: MJFileEntity = await this.md.GetEntityObject('MJ: Files');\n await fileEntity.LoadFromData(fileRecord);\n fileEntity.Status = 'Uploaded';\n await fileEntity.Save();\n\n // emit an event about a new file uploaded, include the file data\n this.fileUpload.emit({ success: true, file: fileEntity });\n // Could also emit a progress event with each iteration\n } catch (e) {\n console.error(e);\n // something failed when actually uploading or when updating the API, what do to about pending file?\n this.fileUpload.emit({ success: false, file });\n }\n }\n}\n","<div>\n <label class=\"mj-file-select\" [class.disabled]=\"IsUploading || disabled\">\n <i class=\"fa-solid fa-upload\"></i>\n <span>Select file to upload</span>\n <input\n type=\"file\"\n class=\"mj-file-input\"\n [disabled]=\"IsUploading || disabled\"\n (change)=\"OnFileSelected($event)\" />\n </label>\n\n <mj-dialog\n [Visible]=\"ConfirmQueue.length > 0\"\n Title=\"Please confirm\"\n [Width]=\"450\"\n [MinWidth]=\"250\"\n (Close)=\"CancelConfirm()\">\n @if (ConfirmQueue.length > 0) {\n <p class=\"confirm-message\">\n This will overwrite an existing file named '{{ ConfirmQueue[0][0].name }}'. Are you sure you want to continue?\n </p>\n }\n <mj-dialog-actions>\n <button mjButton variant=\"primary\" (click)=\"Confirm()\">Overwrite</button>\n <button mjButton (click)=\"CancelConfirm()\">Cancel</button>\n </mj-dialog-actions>\n </mj-dialog>\n</div>\n"]}
|
|
1
|
+
{"version":3,"file":"file-upload.js","sourceRoot":"","sources":["../../../src/lib/file-upload/file-upload.ts","../../../src/lib/file-upload/file-upload.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';\nimport { MJFileEntity, MJFileSchema, MJFileStorageProviderEntity, FileStorageEngineBase } from '@memberjunction/core-entities';\nimport { GraphQLDataProvider, gql } from '@memberjunction/graphql-dataprovider';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\nimport { z } from 'zod';\n\n/**\n * Minimal file info interface replacing Kendo's FileInfo.\n */\nexport interface FileSelectInfo {\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 size: number; // 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 rawFile: File; // 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\nexport type FileUploadEvent = { success: true; file: MJFileEntity } | { success: false; file: FileSelectInfo }; // 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\nconst FileFieldsFragment = gql`\n fragment FileFields on MJFile_ {\n Category\n CategoryID\n ContentType\n _mj__CreatedAt\n Description\n ID\n Name\n Provider\n ProviderID\n ProviderKey\n Status\n _mj__UpdatedAt\n }\n`;\n\nconst FileUploadMutation = gql`\n ${FileFieldsFragment}\n mutation CreateFile($input: CreateMJFileInput!) {\n CreateFile(input: $input) {\n NameExists\n UploadUrl\n File {\n ...FileFields\n }\n }\n }\n`;\n\nconst FileUploadMutationSchema = z.object({\n CreateFile: z.object({\n NameExists: z.boolean(),\n UploadUrl: z.string(),\n File: MJFileSchema.omit({ __mj_CreatedAt: true, __mj_UpdatedAt: true }).passthrough(),\n }),\n});\n\ntype ApiFile = z.infer<typeof FileUploadMutationSchema>['CreateFile']['File'];\ntype UploadTuple = [FileSelectInfo, ApiFile, string];\n\n@Component({\n standalone: false,\n selector: 'mj-files-file-upload',\n templateUrl: './file-upload.html',\n styleUrls: ['./file-upload.css'],\n})\nexport class FileUploadComponent extends BaseAngularComponent implements OnInit {\n public ConfirmQueue: Array<UploadTuple> = [];\n public UploadQueue: Array<FileSelectInfo> = [];\n private defaultProviderID = '';\n private get md() { return this.ProviderToUse; }\n\n get IsUploading(): boolean {\n return this.UploadQueue.length + this.ConfirmQueue.length > 0;\n }\n\n constructor() { super(); }\n\n @Input() Disabled = false;\n\n /** @deprecated Use {@link Disabled}. */\n @Input() set disabled(value: FileUploadComponent['Disabled']) {\n this.Disabled = value;\n }\n /** @deprecated Use {@link Disabled}. */\n get disabled(): FileUploadComponent['Disabled'] {\n return this.Disabled;\n }\n @Input() CategoryID: string | undefined = undefined;\n @Output() UploadStarted = new EventEmitter<void>();\n\n /**\n * @deprecated Use {@link UploadStarted}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (uploadStarted) keeps working. Must stay AFTER UploadStarted: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() uploadStarted = this.UploadStarted;\n @Output() FileUpload = new EventEmitter<FileUploadEvent>();\n\n /**\n * @deprecated Use {@link FileUpload}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (fileUpload) keeps working. Must stay AFTER FileUpload: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() fileUpload = this.FileUpload;\n\n ngOnInit(): void {\n this.Refresh();\n }\n\n async Refresh() {\n await FileStorageEngineBase.Instance.Config(false);\n const activeProviders = FileStorageEngineBase.Instance.Providers\n .filter(p => p.IsActive)\n .sort((a, b) => (b.Priority ?? 0) - (a.Priority ?? 0));\n const provider: MJFileStorageProviderEntity | undefined = activeProviders[0];\n if (typeof provider?.ID === 'string') {\n this.defaultProviderID = provider.ID;\n }\n }\n\n Confirm() {\n const confirmed = this.ConfirmQueue.shift();\n if (confirmed) {\n this._uploadFile(...confirmed);\n }\n }\n\n async CancelConfirm() {\n const cancelled = this.ConfirmQueue.shift();\n if (cancelled) {\n const [file, fileRecord] = cancelled;\n\n const fileEntity: MJFileEntity = await this.md.GetEntityObject('MJ: Files');\n await fileEntity.LoadFromData(fileRecord);\n await fileEntity.Delete();\n\n this.FileUpload.emit({ success: false, file });\n }\n }\n\n /**\n * Handles the native file input change event.\n */\n OnFileSelected(event: Event) {\n const input = event.target as HTMLInputElement;\n if (!input.files || input.files.length === 0) {\n return;\n }\n\n this.UploadStarted.emit();\n\n // Convert native File objects to our FileSelectInfo format\n for (let i = 0; i < input.files.length; i++) {\n const nativeFile = input.files[i];\n const fileInfo: FileSelectInfo = {\n name: nativeFile.name,\n size: nativeFile.size,\n rawFile: nativeFile,\n };\n this.UploadQueue.push(fileInfo);\n }\n\n // Reset input so the same file can be selected again\n input.value = '';\n\n this._processUploadQueue();\n }\n\n private async _processUploadQueue() {\n // for each selected file to upload\n let file = this.UploadQueue.shift();\n while (file) {\n const input = {\n Name: file.name,\n ProviderID: this.defaultProviderID,\n Status: 'Pending',\n CategoryID: this.CategoryID,\n };\n\n // call the gql\n const result = await GraphQLDataProvider.ExecuteGQL(FileUploadMutation, { input });\n\n // make sure the response is correct\n const parsedResult = FileUploadMutationSchema.safeParse(result);\n if (parsedResult.success) {\n const { File, UploadUrl, NameExists } = parsedResult.data.CreateFile;\n const uploadTuple: UploadTuple = [file, File, UploadUrl];\n\n // Confirm we want to overwrite\n if (NameExists) {\n this.ConfirmQueue.push(uploadTuple);\n } else {\n await this._uploadFile(...uploadTuple);\n }\n } else {\n console.error('The API returned an unexpected result', parsedResult.error.issues);\n this.FileUpload.emit({ success: false, file });\n }\n file = this.UploadQueue.shift();\n }\n }\n\n private async _uploadFile(file: FileSelectInfo, fileRecord: ApiFile, uploadUrl: string) {\n try {\n // now upload to the url\n await window.fetch(uploadUrl, {\n method: 'PUT',\n headers: { 'x-ms-blob-type': 'BlockBlob' },\n body: file.rawFile,\n });\n\n // now update that file to set status\n const fileEntity: MJFileEntity = await this.md.GetEntityObject('MJ: Files');\n await fileEntity.LoadFromData(fileRecord);\n fileEntity.Status = 'Uploaded';\n await fileEntity.Save();\n\n // emit an event about a new file uploaded, include the file data\n this.FileUpload.emit({ success: true, file: fileEntity });\n // Could also emit a progress event with each iteration\n } catch (e) {\n console.error(e);\n // something failed when actually uploading or when updating the API, what do to about pending file?\n this.FileUpload.emit({ success: false, file });\n }\n }\n}\n","<div>\n <label class=\"mj-file-select\" [class.disabled]=\"IsUploading || disabled\">\n <i class=\"fa-solid fa-upload\"></i>\n <span>Select file to upload</span>\n <input\n type=\"file\"\n class=\"mj-file-input\"\n [disabled]=\"IsUploading || disabled\"\n (change)=\"OnFileSelected($event)\" />\n </label>\n\n <mj-dialog\n [Visible]=\"ConfirmQueue.length > 0\"\n Title=\"Please confirm\"\n [Width]=\"450\"\n [MinWidth]=\"250\"\n (Close)=\"CancelConfirm()\">\n @if (ConfirmQueue.length > 0) {\n <p class=\"confirm-message\">\n This will overwrite an existing file named '{{ ConfirmQueue[0][0].name }}'. Are you sure you want to continue?\n </p>\n }\n <mj-dialog-actions>\n <button mjButton variant=\"primary\" (click)=\"Confirm()\">Overwrite</button>\n <button mjButton (click)=\"CancelConfirm()\">Cancel</button>\n </mj-dialog-actions>\n </mj-dialog>\n</div>\n"]}
|
|
@@ -7,9 +7,17 @@ import { FileUploadEvent } from '../file-upload/file-upload';
|
|
|
7
7
|
import * as i0 from "@angular/core";
|
|
8
8
|
export declare class FilesGridComponent extends BaseAngularComponent implements OnInit, OnChanges {
|
|
9
9
|
private notifications;
|
|
10
|
-
|
|
10
|
+
Files: MJFileEntity[];
|
|
11
|
+
/** @deprecated Use {@link Files}. */
|
|
12
|
+
get files(): MJFileEntity[];
|
|
13
|
+
/** @deprecated Use {@link Files}. */
|
|
14
|
+
set files(value: MJFileEntity[]);
|
|
11
15
|
isLoading: boolean;
|
|
12
|
-
|
|
16
|
+
EditFile: MJFileEntity | undefined;
|
|
17
|
+
/** @deprecated Use {@link EditFile}. */
|
|
18
|
+
get editFile(): MJFileEntity | undefined;
|
|
19
|
+
/** @deprecated Use {@link EditFile}. */
|
|
20
|
+
set editFile(value: MJFileEntity | undefined);
|
|
13
21
|
GridTheme: Theme;
|
|
14
22
|
ColumnDefs: ColDef[];
|
|
15
23
|
DefaultColDef: ColDef;
|
|
@@ -26,6 +34,8 @@ export declare class FilesGridComponent extends BaseAngularComponent implements
|
|
|
26
34
|
*
|
|
27
35
|
* @returns void
|
|
28
36
|
*/
|
|
37
|
+
ResetEditFile(): void;
|
|
38
|
+
/** @deprecated Use {@link ResetEditFile}. */
|
|
29
39
|
resetEditFile(): void;
|
|
30
40
|
/**
|
|
31
41
|
* Saves the edited file.
|
|
@@ -35,6 +45,8 @@ export declare class FilesGridComponent extends BaseAngularComponent implements
|
|
|
35
45
|
* @returns Promise<void> - A promise that resolves when the save operation is complete.
|
|
36
46
|
* @throws Error - If there is an error during the save operation.
|
|
37
47
|
*/
|
|
48
|
+
SaveEditFile(): Promise<void>;
|
|
49
|
+
/** @deprecated Use {@link SaveEditFile}. */
|
|
38
50
|
saveEditFile(): Promise<void>;
|
|
39
51
|
/**
|
|
40
52
|
* Downloads a file using the provided MJFileEntity.
|
|
@@ -43,13 +55,19 @@ export declare class FilesGridComponent extends BaseAngularComponent implements
|
|
|
43
55
|
* @returns Promise<void> - A promise that resolves when the file download is complete.
|
|
44
56
|
* @throws Error - If there is an error during the file download process.
|
|
45
57
|
*/
|
|
46
|
-
|
|
58
|
+
DownloadFile: (file: MJFileEntity) => Promise<void>;
|
|
59
|
+
/** @deprecated Use {@link DownloadFile}. */
|
|
60
|
+
get downloadFile(): (file: MJFileEntity) => Promise<void>;
|
|
61
|
+
/** @deprecated Use {@link DownloadFile}. */
|
|
62
|
+
set downloadFile(value: (file: MJFileEntity) => Promise<void>);
|
|
47
63
|
/**
|
|
48
64
|
* Determines whether a file can be deleted based on its status and creation time.
|
|
49
65
|
*
|
|
50
66
|
* @param file - The MJFileEntity representing the file to be checked.
|
|
51
67
|
* @returns boolean - True if the file can be deleted, false otherwise.
|
|
52
68
|
*/
|
|
69
|
+
CanBeDeleted(file: MJFileEntity): boolean;
|
|
70
|
+
/** @deprecated Use {@link CanBeDeleted}. */
|
|
53
71
|
canBeDeleted(file: MJFileEntity): boolean;
|
|
54
72
|
/**
|
|
55
73
|
* Deletes a file using the provided MJFileEntity.
|
|
@@ -58,13 +76,19 @@ export declare class FilesGridComponent extends BaseAngularComponent implements
|
|
|
58
76
|
* @returns Promise<void> - A promise that resolves when the file deletion is complete.
|
|
59
77
|
* @throws Error - If there is an error during the file deletion process.
|
|
60
78
|
*/
|
|
61
|
-
|
|
79
|
+
DeleteFile: (file: MJFileEntity) => Promise<void>;
|
|
80
|
+
/** @deprecated Use {@link DeleteFile}. */
|
|
81
|
+
get deleteFile(): (file: MJFileEntity) => Promise<void>;
|
|
82
|
+
/** @deprecated Use {@link DeleteFile}. */
|
|
83
|
+
set deleteFile(value: (file: MJFileEntity) => Promise<void>);
|
|
62
84
|
/**
|
|
63
85
|
* Handles the file upload event, sending a notification in case of failure and otherwise adding
|
|
64
86
|
* the newly uploaded files to the files currently displayed.
|
|
65
87
|
*
|
|
66
88
|
* @param e - The file upload event.
|
|
67
89
|
*/
|
|
90
|
+
HandleFileUpload(e: FileUploadEvent): void;
|
|
91
|
+
/** @deprecated Use {@link HandleFileUpload}. */
|
|
68
92
|
handleFileUpload(e: FileUploadEvent): void;
|
|
69
93
|
/**
|
|
70
94
|
* Refreshes the data by running a view and loading the files.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files-grid.d.ts","sourceRoot":"","sources":["../../../src/lib/files-grid/files-grid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnF,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAGrE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAG7D,OAAO,EACL,MAAM,EACN,cAAc,EAKd,KAAK,KAAK,EAEX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;;AAmD7D,qBAMa,kBAAmB,SAAQ,oBAAqB,YAAW,MAAM,EAAE,SAAS;
|
|
1
|
+
{"version":3,"file":"files-grid.d.ts","sourceRoot":"","sources":["../../../src/lib/files-grid/files-grid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnF,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAGrE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAG7D,OAAO,EACL,MAAM,EACN,cAAc,EAKd,KAAK,KAAK,EAEX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;;AAmD7D,qBAMa,kBAAmB,SAAQ,oBAAqB,YAAW,MAAM,EAAE,SAAS;IAmC3E,OAAO,CAAC,aAAa;IAlC1B,KAAK,EAAE,YAAY,EAAE,CAAM;IAElC,qCAAqC;IACrC,IAAW,KAAK,IAAI,YAAY,EAAE,CAEjC;IACD,qCAAqC;IACrC,IAAW,KAAK,CAAC,KAAK,EAAE,YAAY,EAAE,EAErC;IACM,SAAS,EAAE,OAAO,CAAS;IAC3B,QAAQ,EAAE,YAAY,GAAG,SAAS,CAAC;IAE1C,wCAAwC;IACxC,IAAW,QAAQ,IAAI,YAAY,GAAG,SAAS,CAE9C;IACD,wCAAwC;IACxC,IAAW,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,EAElD;IAKM,SAAS,EAAE,KAAK,CAAmD;IACnE,UAAU,EAAE,MAAM,EAAE,CAAM;IAC1B,aAAa,EAAE,MAAM,CAI1B;IACF,OAAO,CAAC,OAAO,CAAwB;gBAEnB,aAAa,EAAE,qBAAqB;IAK/C,UAAU,EAAE,MAAM,GAAG,SAAS,CAAa;IAEpD,QAAQ,IAAI,IAAI;IAIhB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAMlC,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAI/C;;;;;;OAMG;IACI,aAAa;IAKpB,6CAA6C;IACtC,aAAa;IAIpB;;;;;;;OAOG;IACU,YAAY;IAmBzB,4CAA4C;IAC/B,YAAY;IAIzB;;;;;;OAMG;IACI,YAAY,GAAU,MAAM,YAAY,mBAkB7C;IAEF,4CAA4C;IAC5C,IAAW,YAAY,WArBY,YAAY,mBAuB9C;IACD,4CAA4C;IAC5C,IAAW,YAAY,CAAC,KAAK,SAzBM,YAAY,kBAyBlB,EAE5B;IAED;;;;;OAKG;IACI,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO;IAMhD,4CAA4C;IACrC,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO;IAIhD;;;;;;OAMG;IACI,UAAU,GAAU,MAAM,YAAY,mBAY3C;IAEF,0CAA0C;IAC1C,IAAW,UAAU,WAfY,YAAY,mBAiB5C;IACD,0CAA0C;IAC1C,IAAW,UAAU,CAAC,KAAK,SAnBM,YAAY,kBAmBlB,EAE1B;IAED;;;;;OAKG;IACI,gBAAgB,CAAC,CAAC,EAAE,eAAe;IAW1C,gDAAgD;IACzC,gBAAgB,CAAC,CAAC,EAAE,eAAe;IAI1C;;;OAGG;IACG,OAAO;IAiBb;;OAEG;IACH,OAAO,CAAC,eAAe;IAmCvB;;OAEG;IACH,OAAO,CAAC,kBAAkB;yCAhRf,kBAAkB;2CAAlB,kBAAkB;CAyR9B"}
|
|
@@ -85,9 +85,25 @@ const FileDownloadQuerySchema = z.object({
|
|
|
85
85
|
});
|
|
86
86
|
export class FilesGridComponent extends BaseAngularComponent {
|
|
87
87
|
notifications;
|
|
88
|
-
|
|
88
|
+
Files = [];
|
|
89
|
+
/** @deprecated Use {@link Files}. */
|
|
90
|
+
get files() {
|
|
91
|
+
return this.Files;
|
|
92
|
+
}
|
|
93
|
+
/** @deprecated Use {@link Files}. */
|
|
94
|
+
set files(value) {
|
|
95
|
+
this.Files = value;
|
|
96
|
+
}
|
|
89
97
|
isLoading = false;
|
|
90
|
-
|
|
98
|
+
EditFile;
|
|
99
|
+
/** @deprecated Use {@link EditFile}. */
|
|
100
|
+
get editFile() {
|
|
101
|
+
return this.EditFile;
|
|
102
|
+
}
|
|
103
|
+
/** @deprecated Use {@link EditFile}. */
|
|
104
|
+
set editFile(value) {
|
|
105
|
+
this.EditFile = value;
|
|
106
|
+
}
|
|
91
107
|
// AG Grid configuration
|
|
92
108
|
// Themed from the shared --mj-* token params so this grid follows light/dark and
|
|
93
109
|
// the org brand overlay, matching the main entity/query grids.
|
|
@@ -123,9 +139,13 @@ export class FilesGridComponent extends BaseAngularComponent {
|
|
|
123
139
|
*
|
|
124
140
|
* @returns void
|
|
125
141
|
*/
|
|
142
|
+
ResetEditFile() {
|
|
143
|
+
this.EditFile?.Revert();
|
|
144
|
+
this.EditFile = undefined;
|
|
145
|
+
}
|
|
146
|
+
/** @deprecated Use {@link ResetEditFile}. */
|
|
126
147
|
resetEditFile() {
|
|
127
|
-
this.
|
|
128
|
-
this.editFile = undefined;
|
|
148
|
+
return this.ResetEditFile();
|
|
129
149
|
}
|
|
130
150
|
/**
|
|
131
151
|
* Saves the edited file.
|
|
@@ -135,25 +155,29 @@ export class FilesGridComponent extends BaseAngularComponent {
|
|
|
135
155
|
* @returns Promise<void> - A promise that resolves when the save operation is complete.
|
|
136
156
|
* @throws Error - If there is an error during the save operation.
|
|
137
157
|
*/
|
|
138
|
-
async
|
|
139
|
-
if (this.
|
|
158
|
+
async SaveEditFile() {
|
|
159
|
+
if (this.EditFile) {
|
|
140
160
|
this.isLoading = true;
|
|
141
161
|
//
|
|
142
|
-
const success = await this.
|
|
162
|
+
const success = await this.EditFile.Save();
|
|
143
163
|
if (success) {
|
|
144
|
-
this.notifications.CreateSimpleNotification(`Successfully saved file ${this.
|
|
145
|
-
this.
|
|
164
|
+
this.notifications.CreateSimpleNotification(`Successfully saved file ${this.EditFile.ID} ${this.EditFile.Name}`, 'success');
|
|
165
|
+
this.EditFile = undefined;
|
|
146
166
|
// Refresh the grid to show the updated data
|
|
147
167
|
if (this.gridApi) {
|
|
148
|
-
this.gridApi.setGridOption('rowData', this.
|
|
168
|
+
this.gridApi.setGridOption('rowData', this.Files);
|
|
149
169
|
}
|
|
150
170
|
}
|
|
151
171
|
else {
|
|
152
|
-
this.notifications.CreateSimpleNotification(`Unable to save file ${this.
|
|
172
|
+
this.notifications.CreateSimpleNotification(`Unable to save file ${this.EditFile.ID} ${this.EditFile.Name}`, 'error');
|
|
153
173
|
}
|
|
154
174
|
this.isLoading = false;
|
|
155
175
|
}
|
|
156
176
|
}
|
|
177
|
+
/** @deprecated Use {@link SaveEditFile}. */
|
|
178
|
+
async saveEditFile() {
|
|
179
|
+
return this.SaveEditFile();
|
|
180
|
+
}
|
|
157
181
|
/**
|
|
158
182
|
* Downloads a file using the provided MJFileEntity.
|
|
159
183
|
*
|
|
@@ -161,7 +185,7 @@ export class FilesGridComponent extends BaseAngularComponent {
|
|
|
161
185
|
* @returns Promise<void> - A promise that resolves when the file download is complete.
|
|
162
186
|
* @throws Error - If there is an error during the file download process.
|
|
163
187
|
*/
|
|
164
|
-
|
|
188
|
+
DownloadFile = async (file) => {
|
|
165
189
|
this.isLoading = true;
|
|
166
190
|
const result = await GraphQLDataProvider.ExecuteGQL(FileDownloadQuery, {
|
|
167
191
|
FileID: file.ID,
|
|
@@ -180,17 +204,29 @@ export class FilesGridComponent extends BaseAngularComponent {
|
|
|
180
204
|
}
|
|
181
205
|
this.isLoading = false;
|
|
182
206
|
};
|
|
207
|
+
/** @deprecated Use {@link DownloadFile}. */
|
|
208
|
+
get downloadFile() {
|
|
209
|
+
return this.DownloadFile;
|
|
210
|
+
}
|
|
211
|
+
/** @deprecated Use {@link DownloadFile}. */
|
|
212
|
+
set downloadFile(value) {
|
|
213
|
+
this.DownloadFile = value;
|
|
214
|
+
}
|
|
183
215
|
/**
|
|
184
216
|
* Determines whether a file can be deleted based on its status and creation time.
|
|
185
217
|
*
|
|
186
218
|
* @param file - The MJFileEntity representing the file to be checked.
|
|
187
219
|
* @returns boolean - True if the file can be deleted, false otherwise.
|
|
188
220
|
*/
|
|
189
|
-
|
|
221
|
+
CanBeDeleted(file) {
|
|
190
222
|
const status = file.Status;
|
|
191
223
|
const deletable = status === 'Uploaded' || Date.now() - +file.__mj_CreatedAt > 10 * 60 * 60;
|
|
192
224
|
return deletable;
|
|
193
225
|
}
|
|
226
|
+
/** @deprecated Use {@link CanBeDeleted}. */
|
|
227
|
+
canBeDeleted(file) {
|
|
228
|
+
return this.CanBeDeleted(file);
|
|
229
|
+
}
|
|
194
230
|
/**
|
|
195
231
|
* Deletes a file using the provided MJFileEntity.
|
|
196
232
|
*
|
|
@@ -198,35 +234,47 @@ export class FilesGridComponent extends BaseAngularComponent {
|
|
|
198
234
|
* @returns Promise<void> - A promise that resolves when the file deletion is complete.
|
|
199
235
|
* @throws Error - If there is an error during the file deletion process.
|
|
200
236
|
*/
|
|
201
|
-
|
|
237
|
+
DeleteFile = async (file) => {
|
|
202
238
|
this.isLoading = true;
|
|
203
239
|
const ID = file.ID;
|
|
204
240
|
const Name = file.Name;
|
|
205
241
|
const deleteResult = await file.Delete();
|
|
206
242
|
if (deleteResult) {
|
|
207
243
|
this.notifications.CreateSimpleNotification(`Successfully deleted file ${ID} ${Name}`, 'info');
|
|
208
|
-
this.
|
|
244
|
+
this.Files = this.Files.filter((f) => typeof f.ID === 'string' && f.ID !== ID);
|
|
209
245
|
}
|
|
210
246
|
else {
|
|
211
247
|
this.notifications.CreateSimpleNotification(`Unable to delete file ${ID} ${Name}`, 'error');
|
|
212
248
|
}
|
|
213
249
|
this.isLoading = false;
|
|
214
250
|
};
|
|
251
|
+
/** @deprecated Use {@link DeleteFile}. */
|
|
252
|
+
get deleteFile() {
|
|
253
|
+
return this.DeleteFile;
|
|
254
|
+
}
|
|
255
|
+
/** @deprecated Use {@link DeleteFile}. */
|
|
256
|
+
set deleteFile(value) {
|
|
257
|
+
this.DeleteFile = value;
|
|
258
|
+
}
|
|
215
259
|
/**
|
|
216
260
|
* Handles the file upload event, sending a notification in case of failure and otherwise adding
|
|
217
261
|
* the newly uploaded files to the files currently displayed.
|
|
218
262
|
*
|
|
219
263
|
* @param e - The file upload event.
|
|
220
264
|
*/
|
|
221
|
-
|
|
265
|
+
HandleFileUpload(e) {
|
|
222
266
|
if (!e.success) {
|
|
223
267
|
this.notifications.CreateSimpleNotification(`Unable to upload file '${e.file.name}'`, 'error');
|
|
224
268
|
return;
|
|
225
269
|
}
|
|
226
|
-
this.
|
|
227
|
-
this.
|
|
270
|
+
this.Files.push(e.file);
|
|
271
|
+
this.Files = [...this.Files]; // trigger AG Grid row data change
|
|
228
272
|
this.isLoading = false;
|
|
229
273
|
}
|
|
274
|
+
/** @deprecated Use {@link HandleFileUpload}. */
|
|
275
|
+
handleFileUpload(e) {
|
|
276
|
+
return this.HandleFileUpload(e);
|
|
277
|
+
}
|
|
230
278
|
/**
|
|
231
279
|
* Refreshes the data by running a view and loading the files.
|
|
232
280
|
* @returns {Promise<void>} - A promise that resolves when the data is refreshed.
|
|
@@ -240,7 +288,7 @@ export class FilesGridComponent extends BaseAngularComponent {
|
|
|
240
288
|
...(this.CategoryID !== undefined && { ExtraFilter: `CategoryID='${this.CategoryID}'` }),
|
|
241
289
|
});
|
|
242
290
|
if (result.Success) {
|
|
243
|
-
this.
|
|
291
|
+
this.Files = result.Results ?? [];
|
|
244
292
|
}
|
|
245
293
|
else {
|
|
246
294
|
throw new Error('Error loading files: ' + result.ErrorMessage);
|
|
@@ -266,11 +314,11 @@ export class FilesGridComponent extends BaseAngularComponent {
|
|
|
266
314
|
const container = document.createElement('div');
|
|
267
315
|
container.className = 'action-buttons';
|
|
268
316
|
const downloadBtn = this.createActionButton('fa-download', params.data?.Status !== 'Uploaded');
|
|
269
|
-
downloadBtn.addEventListener('click', () => this.
|
|
270
|
-
const deleteBtn = this.createActionButton('fa-trash-can', !this.
|
|
271
|
-
deleteBtn.addEventListener('click', () => this.
|
|
317
|
+
downloadBtn.addEventListener('click', () => this.DownloadFile(params.data));
|
|
318
|
+
const deleteBtn = this.createActionButton('fa-trash-can', !this.CanBeDeleted(params.data));
|
|
319
|
+
deleteBtn.addEventListener('click', () => this.DeleteFile(params.data));
|
|
272
320
|
const editBtn = this.createActionButton('fa-pen-to-square', params.data?.Status !== 'Uploaded');
|
|
273
|
-
editBtn.addEventListener('click', () => { this.
|
|
321
|
+
editBtn.addEventListener('click', () => { this.EditFile = params.data; });
|
|
274
322
|
container.appendChild(downloadBtn);
|
|
275
323
|
container.appendChild(deleteBtn);
|
|
276
324
|
container.appendChild(editBtn);
|