@memberjunction/ng-entity-viewer 5.39.0 → 5.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/__tests__/view-types.test.d.ts +2 -0
  2. package/dist/__tests__/view-types.test.d.ts.map +1 -0
  3. package/dist/__tests__/view-types.test.js +102 -0
  4. package/dist/__tests__/view-types.test.js.map +1 -0
  5. package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts.map +1 -1
  6. package/dist/lib/entity-data-grid/entity-data-grid.component.js +8 -0
  7. package/dist/lib/entity-data-grid/entity-data-grid.component.js.map +1 -1
  8. package/dist/lib/entity-viewer/entity-viewer.component.d.ts +356 -341
  9. package/dist/lib/entity-viewer/entity-viewer.component.d.ts.map +1 -1
  10. package/dist/lib/entity-viewer/entity-viewer.component.js +993 -1097
  11. package/dist/lib/entity-viewer/entity-viewer.component.js.map +1 -1
  12. package/dist/lib/view-config-panel/view-config-panel.component.d.ts +126 -126
  13. package/dist/lib/view-config-panel/view-config-panel.component.js +635 -635
  14. package/dist/lib/view-config-panel/view-config-panel.component.js.map +1 -1
  15. package/dist/lib/view-selector/view-selector.component.d.ts +226 -0
  16. package/dist/lib/view-selector/view-selector.component.d.ts.map +1 -0
  17. package/dist/lib/view-selector/view-selector.component.js +861 -0
  18. package/dist/lib/view-selector/view-selector.component.js.map +1 -0
  19. package/dist/lib/view-type-switcher/view-type-switcher.component.d.ts +114 -0
  20. package/dist/lib/view-type-switcher/view-type-switcher.component.d.ts.map +1 -0
  21. package/dist/lib/view-type-switcher/view-type-switcher.component.js +209 -0
  22. package/dist/lib/view-type-switcher/view-type-switcher.component.js.map +1 -0
  23. package/dist/lib/view-types/descriptors/cards-view-type.d.ts +18 -0
  24. package/dist/lib/view-types/descriptors/cards-view-type.d.ts.map +1 -0
  25. package/dist/lib/view-types/descriptors/cards-view-type.js +31 -0
  26. package/dist/lib/view-types/descriptors/cards-view-type.js.map +1 -0
  27. package/dist/lib/view-types/descriptors/grid-view-type.d.ts +17 -0
  28. package/dist/lib/view-types/descriptors/grid-view-type.d.ts.map +1 -0
  29. package/dist/lib/view-types/descriptors/grid-view-type.js +30 -0
  30. package/dist/lib/view-types/descriptors/grid-view-type.js.map +1 -0
  31. package/dist/lib/view-types/descriptors/map-view-type.d.ts +21 -0
  32. package/dist/lib/view-types/descriptors/map-view-type.d.ts.map +1 -0
  33. package/dist/lib/view-types/descriptors/map-view-type.js +35 -0
  34. package/dist/lib/view-types/descriptors/map-view-type.js.map +1 -0
  35. package/dist/lib/view-types/descriptors/timeline-view-type.d.ts +22 -0
  36. package/dist/lib/view-types/descriptors/timeline-view-type.d.ts.map +1 -0
  37. package/dist/lib/view-types/descriptors/timeline-view-type.js +40 -0
  38. package/dist/lib/view-types/descriptors/timeline-view-type.js.map +1 -0
  39. package/dist/lib/view-types/index.d.ts +20 -0
  40. package/dist/lib/view-types/index.d.ts.map +1 -0
  41. package/dist/lib/view-types/index.js +29 -0
  42. package/dist/lib/view-types/index.js.map +1 -0
  43. package/dist/lib/view-types/renderers/cards-view-renderer.component.d.ts +93 -0
  44. package/dist/lib/view-types/renderers/cards-view-renderer.component.d.ts.map +1 -0
  45. package/dist/lib/view-types/renderers/cards-view-renderer.component.js +144 -0
  46. package/dist/lib/view-types/renderers/cards-view-renderer.component.js.map +1 -0
  47. package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts +273 -0
  48. package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts.map +1 -0
  49. package/dist/lib/view-types/renderers/grid-view-renderer.component.js +558 -0
  50. package/dist/lib/view-types/renderers/grid-view-renderer.component.js.map +1 -0
  51. package/dist/lib/view-types/renderers/map-view-renderer.component.d.ts +135 -0
  52. package/dist/lib/view-types/renderers/map-view-renderer.component.d.ts.map +1 -0
  53. package/dist/lib/view-types/renderers/map-view-renderer.component.js +216 -0
  54. package/dist/lib/view-types/renderers/map-view-renderer.component.js.map +1 -0
  55. package/dist/lib/view-types/renderers/timeline-view-renderer.component.d.ts +176 -0
  56. package/dist/lib/view-types/renderers/timeline-view-renderer.component.d.ts.map +1 -0
  57. package/dist/lib/view-types/renderers/timeline-view-renderer.component.js +535 -0
  58. package/dist/lib/view-types/renderers/timeline-view-renderer.component.js.map +1 -0
  59. package/dist/lib/view-types/view-type.contracts.d.ts +235 -0
  60. package/dist/lib/view-types/view-type.contracts.d.ts.map +1 -0
  61. package/dist/lib/view-types/view-type.contracts.js +51 -0
  62. package/dist/lib/view-types/view-type.contracts.js.map +1 -0
  63. package/dist/lib/view-types/view-type.engine.d.ts +76 -0
  64. package/dist/lib/view-types/view-type.engine.d.ts.map +1 -0
  65. package/dist/lib/view-types/view-type.engine.js +138 -0
  66. package/dist/lib/view-types/view-type.engine.js.map +1 -0
  67. package/dist/lib/view-workspace/view-workspace.component.d.ts +451 -0
  68. package/dist/lib/view-workspace/view-workspace.component.d.ts.map +1 -0
  69. package/dist/lib/view-workspace/view-workspace.component.js +1212 -0
  70. package/dist/lib/view-workspace/view-workspace.component.js.map +1 -0
  71. package/dist/module.d.ts +20 -11
  72. package/dist/module.d.ts.map +1 -1
  73. package/dist/module.js +50 -8
  74. package/dist/module.js.map +1 -1
  75. package/dist/public-api.d.ts +8 -0
  76. package/dist/public-api.d.ts.map +1 -1
  77. package/dist/public-api.js +14 -0
  78. package/dist/public-api.js.map +1 -1
  79. package/package.json +16 -15
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-selector.component.js","sourceRoot":"","sources":["../../../src/lib/view-selector/view-selector.component.ts","../../../src/lib/view-selector/view-selector.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges, ChangeDetectorRef, OnDestroy, ViewEncapsulation } from '@angular/core';\nimport { EntityInfo } from '@memberjunction/core';\nimport { MJUserViewEntityExtended, UserViewEngine, ViewInfo } from '@memberjunction/core-entities';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\n/**\n * Represents a view in the dropdown\n */\nexport interface ViewListItem {\n id: string;\n name: string;\n isOwned: boolean;\n isShared: boolean;\n isDefault: boolean;\n userCanEdit: boolean;\n entity: MJUserViewEntityExtended;\n}\n\n/**\n * Event emitted when a view is selected\n */\nexport interface ViewSelectedEvent {\n ViewID: string | null;\n View: MJUserViewEntityExtended | null;\n}\n\n/**\n * Event emitted when user requests to save the current view\n */\nexport interface SaveViewRequestedEvent {\n /** True if user wants to save as a new view */\n SaveAsNew: boolean;\n}\n\n/**\n * ViewSelectorComponent - Dropdown for selecting saved views\n *\n * Features:\n * - Shows \"(Default)\" option when no view is selected\n * - Groups views into \"My Views\" and \"Shared Views\"\n * - \"Save Current View\" and \"Manage Views\" actions\n * - \"Open in Tab\" button for saved views\n */\n@Component({\n standalone: false,\n selector: 'mj-view-selector',\n templateUrl: './view-selector.component.html',\n styleUrls: ['./view-selector.component.css'],\n encapsulation: ViewEncapsulation.None\n})\nexport class ViewSelectorComponent extends BaseAngularComponent implements OnChanges, OnDestroy {\n /**\n * The entity to load views for\n */\n @Input() Entity: EntityInfo | null = null;\n\n /**\n * Currently selected view ID (null = default view)\n */\n @Input() SelectedViewID: string | null = null;\n\n /**\n * Whether the current view has unsaved modifications\n */\n @Input() ViewModified: boolean = false;\n\n /**\n * Emitted when a view is selected\n */\n @Output() ViewSelected = new EventEmitter<ViewSelectedEvent>();\n\n /**\n * Emitted when user requests to save the current view\n */\n @Output() SaveViewRequested = new EventEmitter<SaveViewRequestedEvent>();\n\n /**\n * Emitted when user wants to open the view management panel\n */\n @Output() ManageViewsRequested = new EventEmitter<void>();\n\n /**\n * Emitted when user wants to open the current view in its own tab\n */\n @Output() OpenInTabRequested = new EventEmitter<string>();\n\n /**\n * Emitted when user wants to configure the current view\n */\n @Output() ConfigureViewRequested = new EventEmitter<void>();\n\n /**\n * Emitted when user wants to create a new record\n */\n @Output() CreateNewRecordRequested = new EventEmitter<void>();\n\n /**\n * Emitted when user wants to export data to Excel\n */\n @Output() ExportRequested = new EventEmitter<void>();\n\n /**\n * Emitted when user wants to duplicate a view (F-005)\n */\n @Output() DuplicateViewRequested = new EventEmitter<string>();\n\n /**\n * Emitted when user wants to use the quick save dialog (F-001)\n * Emits true when user explicitly requested \"Save As New\", false for general save\n */\n @Output() QuickSaveRequested = new EventEmitter<boolean>();\n\n /**\n * Emitted when user wants to revert to saved state (F-007)\n */\n @Output() RevertRequested = new EventEmitter<void>();\n\n // Internal state\n public IsLoading: boolean = false;\n public IsDropdownOpen: boolean = false;\n public MyViews: ViewListItem[] = [];\n public SharedViews: ViewListItem[] = [];\n public SelectedView: MJUserViewEntityExtended | null = null;\n public SearchText: string = '';\n\n private destroy$ = new Subject<void>();\n private get metadata() { return this.ProviderToUse; }\n\n constructor(private cdr: ChangeDetectorRef) { super(); }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['Entity']) {\n if (this.Entity) {\n this.LoadViews();\n } else {\n this.MyViews = [];\n this.SharedViews = [];\n this.SelectedView = null;\n }\n }\n\n if (changes['SelectedViewID'] && this.SelectedViewID) {\n // If we have a selected view ID and it's in our lists, update selectedView\n this.updateSelectedViewFromId();\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n /**\n * Load views for the current entity\n */\n public async LoadViews(): Promise<void> {\n if (!this.Entity) {\n return;\n }\n\n this.IsLoading = true;\n this.cdr.detectChanges();\n\n try {\n const userId = this.metadata.CurrentUser?.ID;\n\n // Use UserViewEngine cache instead of a direct RunView to avoid redundant DB calls.\n // The engine is initialized once and caches all views; GetAccessibleViewsForEntity()\n // already filters by owned + shared and checks UserCanView.\n await UserViewEngine.Instance.Config(false);\n const accessibleViews = UserViewEngine.Instance.GetAccessibleViewsForEntity(this.Entity.ID);\n\n // Separate into owned and shared\n this.MyViews = accessibleViews\n .filter(v => UUIDsEqual(v.UserID, userId))\n .map(v => this.mapViewToListItem(v, true));\n\n this.SharedViews = accessibleViews\n .filter(v => !UUIDsEqual(v.UserID, userId))\n .map(v => this.mapViewToListItem(v, false));\n\n // Update selected view reference\n this.updateSelectedViewFromId();\n } catch (error) {\n console.error('Failed to load views:', error);\n } finally {\n this.IsLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Map a view entity to a list item\n */\n private mapViewToListItem(view: MJUserViewEntityExtended, isOwned: boolean): ViewListItem {\n return {\n id: view.ID,\n name: view.Name,\n isOwned,\n isShared: view.IsShared,\n isDefault: view.IsDefault,\n userCanEdit: view.UserCanEdit,\n entity: view\n };\n }\n\n /**\n * Update the selectedView reference based on selectedViewId\n */\n private updateSelectedViewFromId(): void {\n if (!this.SelectedViewID) {\n this.SelectedView = null;\n return;\n }\n\n // Search in both lists\n const myView = this.MyViews.find(v => v.id === this.SelectedViewID);\n if (myView) {\n this.SelectedView = myView.entity;\n return;\n }\n\n const sharedView = this.SharedViews.find(v => v.id === this.SelectedViewID);\n if (sharedView) {\n this.SelectedView = sharedView.entity;\n return;\n }\n\n // View not in lists yet - it might need to be loaded\n this.SelectedView = null;\n }\n\n /**\n * Get the display name for the current selection\n */\n get DisplayName(): string {\n if (this.SelectedView) {\n return this.SelectedView.Name;\n }\n return '(Default)';\n }\n\n /**\n * Toggle dropdown open/closed\n */\n ToggleDropdown(): void {\n this.IsDropdownOpen = !this.IsDropdownOpen;\n this.cdr.detectChanges();\n }\n\n /**\n * Close the dropdown\n */\n CloseDropdown(): void {\n this.IsDropdownOpen = false;\n this.SearchText = '';\n this.cdr.detectChanges();\n }\n\n /**\n * Select the default view (no saved view)\n */\n SelectDefault(): void {\n this.SelectedView = null;\n this.ViewSelected.emit({ ViewID: null, View: null });\n this.CloseDropdown();\n }\n\n /**\n * Select a view from the list\n */\n SelectView(item: ViewListItem): void {\n this.SelectedView = item.entity;\n this.ViewSelected.emit({ ViewID: item.id, View: item.entity });\n this.CloseDropdown();\n }\n\n /**\n * Request to save the current view\n */\n OnSaveView(): void {\n this.SaveViewRequested.emit({ SaveAsNew: false });\n this.CloseDropdown();\n }\n\n /**\n * Request to save as a new view - opens Quick Save dialog in \"Save As New\" mode\n */\n OnSaveAsNewView(): void {\n this.QuickSaveRequested.emit(true);\n this.CloseDropdown();\n }\n\n /**\n * Request to manage views\n */\n OnManageViews(): void {\n this.ManageViewsRequested.emit();\n this.CloseDropdown();\n }\n\n /**\n * Request to open the current view in a tab\n */\n OnOpenInTab(): void {\n if (this.SelectedViewID) {\n this.OpenInTabRequested.emit(this.SelectedViewID);\n }\n }\n\n /**\n * Request to configure the current view\n */\n OnConfigureView(): void {\n this.ConfigureViewRequested.emit();\n }\n\n /**\n * Request to create a new record\n */\n OnCreateNewRecord(): void {\n this.CreateNewRecordRequested.emit();\n }\n\n /**\n * Request to export data to Excel\n */\n OnExport(): void {\n this.ExportRequested.emit();\n }\n\n /**\n * Request to duplicate a view (F-005)\n */\n OnDuplicateView(viewId: string, event: MouseEvent): void {\n event.stopPropagation(); // Don't select the view\n this.DuplicateViewRequested.emit(viewId);\n this.CloseDropdown();\n }\n\n /**\n * Request to open the quick save dialog (F-001)\n */\n OnQuickSave(): void {\n this.QuickSaveRequested.emit(false);\n this.CloseDropdown();\n }\n\n /**\n * Request to revert view to saved state (F-007)\n */\n OnRevert(): void {\n this.RevertRequested.emit();\n }\n\n /**\n * Check if there are any views to show\n */\n get HasViews(): boolean {\n return this.MyViews.length > 0 || this.SharedViews.length > 0;\n }\n\n /**\n * Check if the current user can edit the selected view\n */\n get CanEditSelectedView(): boolean {\n return this.SelectedView?.UserCanEdit ?? false;\n }\n\n /**\n * Handle click outside to close dropdown\n */\n OnClickOutside(event: Event): void {\n this.CloseDropdown();\n }\n\n // ========================================\n // RICH VIEW PANEL: Search & Metadata\n // ========================================\n\n /**\n * My views filtered by search text\n */\n get FilteredMyViews(): ViewListItem[] {\n if (!this.SearchText.trim()) return this.MyViews;\n const term = this.SearchText.toLowerCase();\n return this.MyViews.filter(v =>\n v.name.toLowerCase().includes(term) ||\n (v.entity.Description || '').toLowerCase().includes(term)\n );\n }\n\n /**\n * Shared views filtered by search text\n */\n get FilteredSharedViews(): ViewListItem[] {\n if (!this.SearchText.trim()) return this.SharedViews;\n const term = this.SearchText.toLowerCase();\n return this.SharedViews.filter(v =>\n v.name.toLowerCase().includes(term) ||\n (v.entity.Description || '').toLowerCase().includes(term)\n );\n }\n\n /**\n * Get the number of filters configured in a view by parsing its FilterState\n */\n GetViewFilterCount(view: ViewListItem): number {\n try {\n const filterState = view.entity.FilterState;\n if (!filterState) return 0;\n const parsed = JSON.parse(filterState);\n if (parsed?.filters?.length) return parsed.filters.length;\n // CompositeFilterDescriptor format\n if (parsed?.logic && parsed?.filters) return parsed.filters.length;\n return 0;\n } catch {\n return 0;\n }\n }\n\n /**\n * Get the number of visible columns in a view by parsing GridState\n */\n GetViewColumnCount(view: ViewListItem): number {\n try {\n const gridState = view.entity.GridState;\n if (!gridState) return 0;\n const parsed = JSON.parse(gridState);\n if (Array.isArray(parsed)) {\n return parsed.filter((c: Record<string, unknown>) => !c['hidden']).length;\n }\n return 0;\n } catch {\n return 0;\n }\n }\n\n /**\n * Get sort info string from a view's SortState\n */\n GetViewSortInfo(view: ViewListItem): string {\n try {\n const sortState = view.entity.SortState;\n if (!sortState) return '';\n const parsed = JSON.parse(sortState);\n if (Array.isArray(parsed) && parsed.length > 0) {\n return `${parsed.length} sort${parsed.length > 1 ? 's' : ''}`;\n }\n return '';\n } catch {\n return '';\n }\n }\n\n /**\n * Select a specific view and open the config panel for it\n */\n OnConfigureViewById(viewId: string, event: MouseEvent): void {\n event.stopPropagation();\n // First select the view, then open config\n const item = this.MyViews.find(v => v.id === viewId) || this.SharedViews.find(v => v.id === viewId);\n if (item) {\n this.SelectedView = item.entity;\n this.ViewSelected.emit({ ViewID: item.id, View: item.entity });\n }\n this.ConfigureViewRequested.emit();\n this.CloseDropdown();\n }\n\n /**\n * Open a specific view in a new tab\n */\n OnOpenViewInTab(viewId: string, event: MouseEvent): void {\n event.stopPropagation();\n this.OpenInTabRequested.emit(viewId);\n this.CloseDropdown();\n }\n\n /**\n * Reset to default view (select no view)\n */\n OnResetToDefault(): void {\n this.SelectDefault();\n }\n}\n","<div class=\"vs-container\">\n <!-- Backdrop for closing panel -->\n @if (IsDropdownOpen) {\n <div class=\"vs-backdrop\" (click)=\"CloseDropdown()\"></div>\n }\n\n <!-- Main View Selector Button -->\n <div class=\"vs-wrapper\">\n <button\n class=\"vs-button\"\n [class.modified]=\"ViewModified\"\n [class.open]=\"IsDropdownOpen\"\n (click)=\"ToggleDropdown()\"\n [disabled]=\"IsLoading\"\n title=\"Select a saved view\">\n <i class=\"fa-solid fa-layer-group vs-btn-icon\"></i>\n <span class=\"vs-btn-name\">{{ DisplayName }}</span>\n @if (ViewModified) {\n <span class=\"vs-modified-dot\" title=\"View has unsaved changes\">•</span>\n }\n <i class=\"fa-solid fa-chevron-down vs-arrow\" [class.rotated]=\"IsDropdownOpen\"></i>\n </button>\n\n <!-- Rich View Panel -->\n @if (IsDropdownOpen) {\n <div class=\"vs-panel\">\n <!-- Panel Header -->\n <div class=\"vs-panel-header\">\n <i class=\"fa-solid fa-table-list vs-header-icon\"></i>\n <span class=\"vs-panel-title\">Views</span>\n @if (Entity) {\n <span class=\"vs-Entity-badge\">{{ Entity.DisplayNameOrName }}</span>\n }\n <button class=\"vs-close-btn\" (click)=\"CloseDropdown()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Search -->\n <div class=\"vs-panel-search\">\n <input\n type=\"text\"\n class=\"vs-search-input\"\n placeholder=\"Search views...\"\n [(ngModel)]=\"SearchText\"\n (keydown.escape)=\"SearchText = ''\"\n />\n </div>\n\n <!-- Panel Body -->\n <div class=\"vs-panel-body\">\n <!-- Default Option -->\n <div class=\"vs-section\">\n <div\n class=\"vs-card\"\n [class.active]=\"!SelectedViewID\"\n (click)=\"SelectDefault()\">\n <div class=\"vs-card-icon\" [class.active]=\"!SelectedViewID\">\n <i class=\"fa-solid fa-table\"></i>\n </div>\n <div class=\"vs-card-content\">\n <div class=\"vs-card-name\">(Default)</div>\n </div>\n @if (!SelectedViewID) {\n <i class=\"fa-solid fa-check vs-card-check\"></i>\n }\n </div>\n </div>\n\n <!-- My Views Section -->\n @if (FilteredMyViews.length > 0) {\n <div class=\"vs-section\">\n <div class=\"vs-section-header\">\n <i class=\"fa-solid fa-user\"></i>\n <span>My Views</span>\n <span class=\"vs-section-count\">{{ FilteredMyViews.length }}</span>\n </div>\n @for (view of FilteredMyViews; track view.id) {\n <div\n class=\"vs-card\"\n [class.active]=\"SelectedViewID === view.id\"\n (click)=\"SelectView(view)\">\n <div class=\"vs-card-icon\" [class.active]=\"SelectedViewID === view.id\">\n <i class=\"fa-solid fa-table-list\"></i>\n </div>\n <div class=\"vs-card-content\">\n <div class=\"vs-card-name\">\n {{ view.name }}\n @if (view.isDefault) {\n <span class=\"vs-default-badge\">Default</span>\n }\n </div>\n @if (view.entity.Description) {\n <div class=\"vs-card-desc\">{{ view.entity.Description }}</div>\n }\n @if (GetViewFilterCount(view) > 0 || GetViewColumnCount(view) > 0 || GetViewSortInfo(view)) {\n <div class=\"vs-card-meta\">\n @if (GetViewFilterCount(view) > 0) {\n <span><i class=\"fa-solid fa-filter\"></i> {{ GetViewFilterCount(view) }} filter{{ GetViewFilterCount(view) !== 1 ? 's' : '' }}</span>\n }\n @if (GetViewColumnCount(view) > 0) {\n <span><i class=\"fa-solid fa-table-columns\"></i> {{ GetViewColumnCount(view) }} col{{ GetViewColumnCount(view) !== 1 ? 's' : '' }}</span>\n }\n @if (GetViewSortInfo(view)) {\n <span><i class=\"fa-solid fa-arrow-down-short-wide\"></i> {{ GetViewSortInfo(view) }}</span>\n }\n </div>\n }\n </div>\n <div class=\"vs-card-actions\">\n <button\n class=\"vs-action-btn\"\n (click)=\"OnDuplicateView(view.id, $event)\"\n title=\"Duplicate\">\n <i class=\"fa-regular fa-copy\"></i>\n </button>\n <button\n class=\"vs-action-btn\"\n (click)=\"OnConfigureViewById(view.id, $event)\"\n title=\"Configure\">\n <i class=\"fa-solid fa-sliders\"></i>\n </button>\n <button\n class=\"vs-action-btn\"\n (click)=\"OnOpenViewInTab(view.id, $event)\"\n title=\"Open in Tab\">\n <i class=\"fa-solid fa-up-right-from-square\"></i>\n </button>\n </div>\n @if (SelectedViewID === view.id) {\n <i class=\"fa-solid fa-check vs-card-check\"></i>\n }\n </div>\n }\n </div>\n }\n\n <!-- Shared Views Section -->\n @if (FilteredSharedViews.length > 0) {\n <div class=\"vs-section\">\n <div class=\"vs-section-header\">\n <i class=\"fa-solid fa-share-nodes\"></i>\n <span>Shared With Me</span>\n <span class=\"vs-section-count\">{{ FilteredSharedViews.length }}</span>\n </div>\n @for (view of FilteredSharedViews; track view.id) {\n <div\n class=\"vs-card\"\n [class.active]=\"SelectedViewID === view.id\"\n (click)=\"SelectView(view)\">\n <div class=\"vs-card-icon shared\">\n <i class=\"fa-solid fa-users\"></i>\n </div>\n <div class=\"vs-card-content\">\n <div class=\"vs-card-name\">\n {{ view.name }}\n @if (!view.userCanEdit) {\n <span class=\"vs-shared-badge\">View Only</span>\n } @else {\n <span class=\"vs-shared-badge editable\">Can Edit</span>\n }\n </div>\n @if (view.entity.Description) {\n <div class=\"vs-card-desc\">{{ view.entity.Description }}</div>\n }\n @if (GetViewFilterCount(view) > 0 || GetViewColumnCount(view) > 0) {\n <div class=\"vs-card-meta\">\n @if (GetViewFilterCount(view) > 0) {\n <span><i class=\"fa-solid fa-filter\"></i> {{ GetViewFilterCount(view) }} filter{{ GetViewFilterCount(view) !== 1 ? 's' : '' }}</span>\n }\n @if (GetViewColumnCount(view) > 0) {\n <span><i class=\"fa-solid fa-table-columns\"></i> {{ GetViewColumnCount(view) }} col{{ GetViewColumnCount(view) !== 1 ? 's' : '' }}</span>\n }\n </div>\n }\n </div>\n <div class=\"vs-card-actions\">\n <button\n class=\"vs-action-btn\"\n (click)=\"OnDuplicateView(view.id, $event)\"\n title=\"Duplicate as My View\">\n <i class=\"fa-regular fa-copy\"></i>\n </button>\n @if (view.userCanEdit) {\n <button\n class=\"vs-action-btn\"\n (click)=\"OnConfigureViewById(view.id, $event)\"\n title=\"Configure\">\n <i class=\"fa-solid fa-sliders\"></i>\n </button>\n }\n </div>\n @if (SelectedViewID === view.id) {\n <i class=\"fa-solid fa-check vs-card-check\"></i>\n }\n </div>\n }\n </div>\n }\n\n <!-- No Views Message -->\n @if (!HasViews && !IsLoading) {\n <div class=\"vs-empty-message\">\n <i class=\"fa-solid fa-bookmark\"></i>\n <div class=\"vs-empty-text\">\n <strong>No saved views yet</strong>\n <span>Save your current configuration as a view</span>\n </div>\n </div>\n }\n\n <!-- No Search Results -->\n @if (HasViews && FilteredMyViews.length === 0 && FilteredSharedViews.length === 0 && SearchText) {\n <div class=\"vs-empty-message\">\n <i class=\"fa-solid fa-search\"></i>\n <span>No views match \"{{ SearchText }}\"</span>\n </div>\n }\n\n <!-- Loading Indicator -->\n @if (IsLoading) {\n <div class=\"vs-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading views...</span>\n </div>\n }\n </div>\n\n <!-- Panel Footer -->\n <div class=\"vs-panel-footer\">\n <button\n class=\"vs-panel-btn primary\"\n (click)=\"OnQuickSave()\"\n title=\"Save current view configuration\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>New View</span>\n </button>\n <button\n class=\"vs-panel-btn\"\n (click)=\"OnResetToDefault()\"\n title=\"Reset to default view\">\n <i class=\"fa-solid fa-arrow-rotate-left\"></i>\n <span>Reset to Default</span>\n </button>\n </div>\n </div>\n }\n </div>\n\n <!-- Open in Tab Button (only visible when a view is selected) -->\n @if (SelectedViewID) {\n <button\n class=\"vs-icon-btn\"\n (click)=\"OnOpenInTab()\"\n title=\"Open this view in a new tab\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n </button>\n }\n\n <!-- Configure View Button -->\n <button\n class=\"vs-icon-btn\"\n (click)=\"OnConfigureView()\"\n title=\"Configure view settings (columns, filters, sorting)\">\n <i class=\"fa-solid fa-sliders-h\"></i>\n </button>\n\n <!-- Create New Record Button -->\n <button\n class=\"vs-icon-btn\"\n (click)=\"OnCreateNewRecord()\"\n title=\"Create new record\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n\n <!-- Export Button -->\n <button\n class=\"vs-icon-btn vs-export-btn\"\n (click)=\"OnExport()\"\n title=\"Export to Excel\">\n <i class=\"fa-solid fa-file-excel\"></i>\n </button>\n</div>\n"]}
@@ -0,0 +1,114 @@
1
+ import { EventEmitter, OnInit } from '@angular/core';
2
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
3
+ import { EntityInfo } from '@memberjunction/core';
4
+ import * as i0 from "@angular/core";
5
+ /**
6
+ * A single selectable entry in the view-type switcher. Built from the
7
+ * `MJ: View Types` registry (via {@link ViewTypeEngine}) for the bound entity.
8
+ */
9
+ export interface ViewTypeSwitcherOption {
10
+ /**
11
+ * Stable key — the descriptor's `Name` (== `MJ: View Types.DriverClass`),
12
+ * e.g. "GridViewType", "ClusterViewType". Used as the `@for` track key.
13
+ */
14
+ Key: string;
15
+ /** The `MJ: View Types` row ID — what gets emitted and persisted as the active view type. */
16
+ ViewTypeId: string;
17
+ /** User-facing label (from `ViewType.DisplayName`). */
18
+ Label: string;
19
+ /** Font Awesome icon class (from `ViewType.Icon` metadata). */
20
+ Icon: string;
21
+ }
22
+ /**
23
+ * Payload emitted by {@link ViewTypeSwitcherComponent.ViewTypeSelected} when the user picks a
24
+ * view type from the menu.
25
+ */
26
+ export interface ViewTypeSelectedEvent {
27
+ /** The `MJ: View Types` row ID that was selected. */
28
+ viewTypeId: string;
29
+ /** The descriptor `DriverClass` / Name of the selected view type (e.g. "ClusterViewType"). */
30
+ driverClass: string;
31
+ }
32
+ /**
33
+ * `mj-view-type-switcher` — a small, self-contained dropdown that lets the user switch between
34
+ * the view types available for an entity (Grid / Cards / Timeline / Map / Cluster / third-party
35
+ * plug-ins).
36
+ *
37
+ * It computes its own available types from the `MJ: View Types` registry via the
38
+ * {@link ViewTypeEngine} — the exact same source the {@link EntityViewerComponent} uses — gated by
39
+ * each descriptor's `IsAvailableFor` predicate (e.g. Timeline needs a date field, Map needs
40
+ * geocoding, Cluster needs vectors). Icons come from `ViewType.Icon` metadata. There is
41
+ * intentionally no hardcoded fallback list: when the registry yields one type or fewer, the
42
+ * switcher renders nothing.
43
+ *
44
+ * The component is purely presentational with respect to selection — it does NOT switch the
45
+ * actual rendering. It emits {@link ViewTypeSelected} and the host (the entity-viewer header or
46
+ * the view-workspace toolbar) routes that to its existing view-type selection logic. This keeps
47
+ * the switcher reusable both inside the viewer's own header and lifted up into a parent toolbar
48
+ * without the parent-reads-child `ExpressionChangedAfterItHasBeenCheckedError` anti-pattern.
49
+ *
50
+ * @example
51
+ * ```html
52
+ * <mj-view-type-switcher
53
+ * [Provider]="Provider"
54
+ * [Entity]="Entity"
55
+ * [ActiveViewTypeID]="activeViewTypeId"
56
+ * (ViewTypeSelected)="onViewTypeSelected($event)">
57
+ * </mj-view-type-switcher>
58
+ * ```
59
+ */
60
+ export declare class ViewTypeSwitcherComponent extends BaseAngularComponent implements OnInit {
61
+ private readonly cdr;
62
+ private _entity;
63
+ private _activeViewTypeId;
64
+ private _initialized;
65
+ /**
66
+ * The entity whose available view types are offered. When it changes the available types
67
+ * are recomputed from the registry.
68
+ */
69
+ get Entity(): EntityInfo | null;
70
+ set Entity(value: EntityInfo | null);
71
+ /**
72
+ * The currently-active view type's `MJ: View Types` row ID (drives the trigger label/icon and
73
+ * the active highlight in the menu). The host owns this — the switcher only requests changes.
74
+ */
75
+ get ActiveViewTypeID(): string | null;
76
+ set ActiveViewTypeID(value: string | null);
77
+ /**
78
+ * Emitted when the user selects a view type from the menu. The host routes this to its existing
79
+ * view-type selection logic (by `viewTypeId`). The switcher does not change rendering itself.
80
+ */
81
+ ViewTypeSelected: EventEmitter<ViewTypeSelectedEvent>;
82
+ /** The available view types for the current entity, sourced from the registry. */
83
+ AvailableViewTypes: ViewTypeSwitcherOption[];
84
+ /** Whether the dropdown menu is currently open. */
85
+ DropdownOpen: boolean;
86
+ /** Initializes the switcher and performs the first registry resolution. */
87
+ ngOnInit(): void;
88
+ /**
89
+ * The option matching {@link ActiveViewTypeID} (for the trigger's icon + label), or the first
90
+ * available option as a sensible default, or null before the registry resolves.
91
+ */
92
+ get ActiveOption(): ViewTypeSwitcherOption | null;
93
+ /**
94
+ * Loads the view-type registry once (including each descriptor's availability-data hook) and
95
+ * then computes the available types. Fire-and-forget from {@link ngOnInit}; on failure the
96
+ * switcher simply renders nothing (registry not seeded).
97
+ */
98
+ private ensureViewTypesLoaded;
99
+ /**
100
+ * Recomputes {@link AvailableViewTypes} from the registry for the current entity. Each available
101
+ * `MJ: View Types` row is mapped to a switcher option using its descriptor's display metadata.
102
+ */
103
+ private refreshAvailableTypes;
104
+ /** Toggles the dropdown menu open/closed. */
105
+ ToggleDropdown(): void;
106
+ /**
107
+ * Handles a menu selection. Closes the menu and emits {@link ViewTypeSelected} so the host can
108
+ * apply the switch through its own selection logic.
109
+ */
110
+ SelectViewType(option: ViewTypeSwitcherOption): void;
111
+ static ɵfac: i0.ɵɵFactoryDeclaration<ViewTypeSwitcherComponent, never>;
112
+ static ɵcmp: i0.ɵɵComponentDeclaration<ViewTypeSwitcherComponent, "mj-view-type-switcher", never, { "Entity": { "alias": "Entity"; "required": false; }; "ActiveViewTypeID": { "alias": "ActiveViewTypeID"; "required": false; }; }, { "ViewTypeSelected": "ViewTypeSelected"; }, never, never, false, never>;
113
+ }
114
+ //# sourceMappingURL=view-type-switcher.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-type-switcher.component.d.ts","sourceRoot":"","sources":["../../../src/lib/view-type-switcher/view-type-switcher.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,YAAY,EACZ,MAAM,EAGP,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;;AAIlD;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,6FAA6F;IAC7F,UAAU,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAMa,yBAA0B,SAAQ,oBAAqB,YAAW,MAAM;IACnF,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA6B;IAEjD,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,YAAY,CAAS;IAE7B;;;OAGG;IACH,IACI,MAAM,IAAI,UAAU,GAAG,IAAI,CAE9B;IACD,IAAI,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,EAMlC;IAED;;;OAGG;IACH,IACI,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAEpC;IACD,IAAI,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAExC;IAED;;;OAGG;IACO,gBAAgB,sCAA6C;IAEvE,kFAAkF;IAC3E,kBAAkB,EAAE,sBAAsB,EAAE,CAAM;IAEzD,mDAAmD;IAC5C,YAAY,UAAS;IAE5B,2EAA2E;IAC3E,QAAQ,IAAI,IAAI;IAKhB;;;OAGG;IACH,IAAI,YAAY,IAAI,sBAAsB,GAAG,IAAI,CAGhD;IAED;;;;OAIG;YACW,qBAAqB;IAYnC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAwB7B,6CAA6C;IACtC,cAAc,IAAI,IAAI;IAI7B;;;OAGG;IACI,cAAc,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI;yCApHhD,yBAAyB;2CAAzB,yBAAyB;CAwHrC"}
@@ -0,0 +1,209 @@
1
+ import { Component, Input, Output, EventEmitter, ChangeDetectorRef, inject } from '@angular/core';
2
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
3
+ import { UUIDsEqual } from '@memberjunction/global';
4
+ import { ViewTypeEngine } from '../view-types';
5
+ import * as i0 from "@angular/core";
6
+ const _forTrack0 = ($index, $item) => $item.Key;
7
+ function ViewTypeSwitcherComponent_Conditional_0_Conditional_6_For_2_Template(rf, ctx) { if (rf & 1) {
8
+ const _r3 = i0.ɵɵgetCurrentView();
9
+ i0.ɵɵelementStart(0, "button", 6);
10
+ i0.ɵɵlistener("click", function ViewTypeSwitcherComponent_Conditional_0_Conditional_6_For_2_Template_button_click_0_listener() { const vt_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.SelectViewType(vt_r4)); });
11
+ i0.ɵɵelement(1, "i");
12
+ i0.ɵɵelementStart(2, "span");
13
+ i0.ɵɵtext(3);
14
+ i0.ɵɵelementEnd()();
15
+ } if (rf & 2) {
16
+ const vt_r4 = ctx.$implicit;
17
+ const ctx_r1 = i0.ɵɵnextContext(3);
18
+ i0.ɵɵclassProp("active", (ctx_r1.ActiveOption == null ? null : ctx_r1.ActiveOption.Key) === vt_r4.Key);
19
+ i0.ɵɵadvance();
20
+ i0.ɵɵclassMap(vt_r4.Icon);
21
+ i0.ɵɵadvance(2);
22
+ i0.ɵɵtextInterpolate(vt_r4.Label);
23
+ } }
24
+ function ViewTypeSwitcherComponent_Conditional_0_Conditional_6_Template(rf, ctx) { if (rf & 1) {
25
+ i0.ɵɵelementStart(0, "div", 4);
26
+ i0.ɵɵrepeaterCreate(1, ViewTypeSwitcherComponent_Conditional_0_Conditional_6_For_2_Template, 4, 5, "button", 5, _forTrack0);
27
+ i0.ɵɵelementEnd();
28
+ } if (rf & 2) {
29
+ const ctx_r1 = i0.ɵɵnextContext(2);
30
+ i0.ɵɵadvance();
31
+ i0.ɵɵrepeater(ctx_r1.AvailableViewTypes);
32
+ } }
33
+ function ViewTypeSwitcherComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
34
+ const _r1 = i0.ɵɵgetCurrentView();
35
+ i0.ɵɵelementStart(0, "div", 0)(1, "button", 1);
36
+ i0.ɵɵlistener("click", function ViewTypeSwitcherComponent_Conditional_0_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ToggleDropdown()); });
37
+ i0.ɵɵelement(2, "i");
38
+ i0.ɵɵelementStart(3, "span", 2);
39
+ i0.ɵɵtext(4);
40
+ i0.ɵɵelementEnd();
41
+ i0.ɵɵelement(5, "i", 3);
42
+ i0.ɵɵelementEnd();
43
+ i0.ɵɵconditionalCreate(6, ViewTypeSwitcherComponent_Conditional_0_Conditional_6_Template, 3, 0, "div", 4);
44
+ i0.ɵɵelementEnd();
45
+ } if (rf & 2) {
46
+ const ctx_r1 = i0.ɵɵnextContext();
47
+ i0.ɵɵadvance();
48
+ i0.ɵɵclassProp("active", ctx_r1.DropdownOpen);
49
+ i0.ɵɵproperty("title", ((ctx_r1.ActiveOption == null ? null : ctx_r1.ActiveOption.Label) ?? "") + " View");
50
+ i0.ɵɵadvance();
51
+ i0.ɵɵclassMap(ctx_r1.ActiveOption == null ? null : ctx_r1.ActiveOption.Icon);
52
+ i0.ɵɵadvance(2);
53
+ i0.ɵɵtextInterpolate(ctx_r1.ActiveOption == null ? null : ctx_r1.ActiveOption.Label);
54
+ i0.ɵɵadvance(2);
55
+ i0.ɵɵconditional(ctx_r1.DropdownOpen ? 6 : -1);
56
+ } }
57
+ /**
58
+ * `mj-view-type-switcher` — a small, self-contained dropdown that lets the user switch between
59
+ * the view types available for an entity (Grid / Cards / Timeline / Map / Cluster / third-party
60
+ * plug-ins).
61
+ *
62
+ * It computes its own available types from the `MJ: View Types` registry via the
63
+ * {@link ViewTypeEngine} — the exact same source the {@link EntityViewerComponent} uses — gated by
64
+ * each descriptor's `IsAvailableFor` predicate (e.g. Timeline needs a date field, Map needs
65
+ * geocoding, Cluster needs vectors). Icons come from `ViewType.Icon` metadata. There is
66
+ * intentionally no hardcoded fallback list: when the registry yields one type or fewer, the
67
+ * switcher renders nothing.
68
+ *
69
+ * The component is purely presentational with respect to selection — it does NOT switch the
70
+ * actual rendering. It emits {@link ViewTypeSelected} and the host (the entity-viewer header or
71
+ * the view-workspace toolbar) routes that to its existing view-type selection logic. This keeps
72
+ * the switcher reusable both inside the viewer's own header and lifted up into a parent toolbar
73
+ * without the parent-reads-child `ExpressionChangedAfterItHasBeenCheckedError` anti-pattern.
74
+ *
75
+ * @example
76
+ * ```html
77
+ * <mj-view-type-switcher
78
+ * [Provider]="Provider"
79
+ * [Entity]="Entity"
80
+ * [ActiveViewTypeID]="activeViewTypeId"
81
+ * (ViewTypeSelected)="onViewTypeSelected($event)">
82
+ * </mj-view-type-switcher>
83
+ * ```
84
+ */
85
+ export class ViewTypeSwitcherComponent extends BaseAngularComponent {
86
+ cdr = inject(ChangeDetectorRef);
87
+ _entity = null;
88
+ _activeViewTypeId = null;
89
+ _initialized = false;
90
+ /**
91
+ * The entity whose available view types are offered. When it changes the available types
92
+ * are recomputed from the registry.
93
+ */
94
+ get Entity() {
95
+ return this._entity;
96
+ }
97
+ set Entity(value) {
98
+ const previous = this._entity;
99
+ this._entity = value;
100
+ if (this._initialized && (!previous || !value || !UUIDsEqual(value.ID, previous.ID))) {
101
+ this.refreshAvailableTypes();
102
+ }
103
+ }
104
+ /**
105
+ * The currently-active view type's `MJ: View Types` row ID (drives the trigger label/icon and
106
+ * the active highlight in the menu). The host owns this — the switcher only requests changes.
107
+ */
108
+ get ActiveViewTypeID() {
109
+ return this._activeViewTypeId;
110
+ }
111
+ set ActiveViewTypeID(value) {
112
+ this._activeViewTypeId = value;
113
+ }
114
+ /**
115
+ * Emitted when the user selects a view type from the menu. The host routes this to its existing
116
+ * view-type selection logic (by `viewTypeId`). The switcher does not change rendering itself.
117
+ */
118
+ ViewTypeSelected = new EventEmitter();
119
+ /** The available view types for the current entity, sourced from the registry. */
120
+ AvailableViewTypes = [];
121
+ /** Whether the dropdown menu is currently open. */
122
+ DropdownOpen = false;
123
+ /** Initializes the switcher and performs the first registry resolution. */
124
+ ngOnInit() {
125
+ this._initialized = true;
126
+ void this.ensureViewTypesLoaded();
127
+ }
128
+ /**
129
+ * The option matching {@link ActiveViewTypeID} (for the trigger's icon + label), or the first
130
+ * available option as a sensible default, or null before the registry resolves.
131
+ */
132
+ get ActiveOption() {
133
+ const active = this.AvailableViewTypes.find(o => o.ViewTypeId === this._activeViewTypeId);
134
+ return active ?? this.AvailableViewTypes[0] ?? null;
135
+ }
136
+ /**
137
+ * Loads the view-type registry once (including each descriptor's availability-data hook) and
138
+ * then computes the available types. Fire-and-forget from {@link ngOnInit}; on failure the
139
+ * switcher simply renders nothing (registry not seeded).
140
+ */
141
+ async ensureViewTypesLoaded() {
142
+ try {
143
+ const provider = this.ProviderToUse;
144
+ await ViewTypeEngine.Instance.Config(false, provider?.CurrentUser, provider ?? undefined);
145
+ await ViewTypeEngine.Instance.EnsureAvailabilityData(provider ?? undefined);
146
+ this.refreshAvailableTypes();
147
+ }
148
+ catch {
149
+ this.AvailableViewTypes = [];
150
+ this.cdr.detectChanges();
151
+ }
152
+ }
153
+ /**
154
+ * Recomputes {@link AvailableViewTypes} from the registry for the current entity. Each available
155
+ * `MJ: View Types` row is mapped to a switcher option using its descriptor's display metadata.
156
+ */
157
+ refreshAvailableTypes() {
158
+ const entity = this._entity;
159
+ if (!entity) {
160
+ this.AvailableViewTypes = [];
161
+ this.cdr.detectChanges();
162
+ return;
163
+ }
164
+ let rows = [];
165
+ try {
166
+ rows = ViewTypeEngine.Instance.GetAvailableViewTypeRows(entity, this.ProviderToUse ?? undefined);
167
+ }
168
+ catch {
169
+ rows = [];
170
+ }
171
+ this.AvailableViewTypes = rows.map(({ ViewType, Descriptor }) => ({
172
+ Key: Descriptor.Name,
173
+ ViewTypeId: ViewType.ID,
174
+ Label: Descriptor.DisplayName,
175
+ Icon: Descriptor.Icon ?? ''
176
+ }));
177
+ this.cdr.detectChanges();
178
+ }
179
+ /** Toggles the dropdown menu open/closed. */
180
+ ToggleDropdown() {
181
+ this.DropdownOpen = !this.DropdownOpen;
182
+ }
183
+ /**
184
+ * Handles a menu selection. Closes the menu and emits {@link ViewTypeSelected} so the host can
185
+ * apply the switch through its own selection logic.
186
+ */
187
+ SelectViewType(option) {
188
+ this.DropdownOpen = false;
189
+ this.ViewTypeSelected.emit({ viewTypeId: option.ViewTypeId, driverClass: option.Key });
190
+ }
191
+ static ɵfac = /*@__PURE__*/ (() => { let ɵViewTypeSwitcherComponent_BaseFactory; return function ViewTypeSwitcherComponent_Factory(__ngFactoryType__) { return (ɵViewTypeSwitcherComponent_BaseFactory || (ɵViewTypeSwitcherComponent_BaseFactory = i0.ɵɵgetInheritedFactory(ViewTypeSwitcherComponent)))(__ngFactoryType__ || ViewTypeSwitcherComponent); }; })();
192
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ViewTypeSwitcherComponent, selectors: [["mj-view-type-switcher"]], inputs: { Entity: "Entity", ActiveViewTypeID: "ActiveViewTypeID" }, outputs: { ViewTypeSelected: "ViewTypeSelected" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 1, consts: [[1, "view-type-dropdown"], ["type", "button", 1, "toggle-btn", "view-type-dropdown-trigger", 3, "click", "title"], [1, "view-type-dropdown-label"], [1, "fa-solid", "fa-chevron-down", "view-type-dropdown-caret"], [1, "view-type-dropdown-menu"], ["type", "button", 1, "view-type-dropdown-item", 3, "active"], ["type", "button", 1, "view-type-dropdown-item", 3, "click"]], template: function ViewTypeSwitcherComponent_Template(rf, ctx) { if (rf & 1) {
193
+ i0.ɵɵconditionalCreate(0, ViewTypeSwitcherComponent_Conditional_0_Template, 7, 7, "div", 0);
194
+ } if (rf & 2) {
195
+ i0.ɵɵconditional(ctx.AvailableViewTypes.length > 1 ? 0 : -1);
196
+ } }, styles: ["[_nghost-%COMP%] {\n display: inline-flex;\n}\n\n\n\n.toggle-btn[_ngcontent-%COMP%] {\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.toggle-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n}\n\n.toggle-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n}\n\n\n\n.view-type-dropdown[_ngcontent-%COMP%] {\n position: relative;\n display: inline-flex;\n}\n\n.view-type-dropdown-trigger[_ngcontent-%COMP%] {\n width: auto;\n gap: 6px;\n padding: 0 10px;\n border: 1px solid var(--mj-border-default);\n}\n\n.view-type-dropdown-trigger[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-border-strong);\n}\n\n.view-type-dropdown-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n}\n\n.view-type-dropdown-caret[_ngcontent-%COMP%] {\n font-size: 10px;\n opacity: 0.7;\n}\n\n.view-type-dropdown-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n z-index: 20;\n min-width: 180px;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 8px 24px color-mix(in srgb, var(--mj-text-primary) 14%, transparent);\n padding: 4px;\n display: flex;\n flex-direction: column;\n}\n\n.view-type-dropdown-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 8px 10px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 13px;\n text-align: left;\n transition: background 0.12s ease, color 0.12s ease;\n}\n\n.view-type-dropdown-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.view-type-dropdown-item.active[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.view-type-dropdown-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 16px;\n text-align: center;\n}"] });
197
+ }
198
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ViewTypeSwitcherComponent, [{
199
+ type: Component,
200
+ args: [{ standalone: false, selector: 'mj-view-type-switcher', template: "<!-- View-type switcher: a single dropdown driven entirely by the MJ: View Types registry.\n Available types + icons come from metadata, filtered by each descriptor's availability\n predicate. Renders nothing when the registry yields one type or fewer. -->\n@if (AvailableViewTypes.length > 1) {\n <div class=\"view-type-dropdown\">\n <button\n type=\"button\"\n class=\"toggle-btn view-type-dropdown-trigger\"\n [class.active]=\"DropdownOpen\"\n (click)=\"ToggleDropdown()\"\n [title]=\"(ActiveOption?.Label ?? '') + ' View'\">\n <i [class]=\"ActiveOption?.Icon\"></i>\n <span class=\"view-type-dropdown-label\">{{ ActiveOption?.Label }}</span>\n <i class=\"fa-solid fa-chevron-down view-type-dropdown-caret\"></i>\n </button>\n @if (DropdownOpen) {\n <div class=\"view-type-dropdown-menu\">\n @for (vt of AvailableViewTypes; track vt.Key) {\n <button\n type=\"button\"\n class=\"view-type-dropdown-item\"\n [class.active]=\"ActiveOption?.Key === vt.Key\"\n (click)=\"SelectViewType(vt)\">\n <i [class]=\"vt.Icon\"></i>\n <span>{{ vt.Label }}</span>\n </button>\n }\n </div>\n }\n </div>\n}\n", styles: [":host {\n display: inline-flex;\n}\n\n/* Shared trigger button base (mirrors the entity-viewer toggle-btn) */\n.toggle-btn {\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.toggle-btn:hover {\n color: var(--mj-text-secondary);\n}\n\n.toggle-btn.active {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n}\n\n/* Compact view-type dropdown */\n.view-type-dropdown {\n position: relative;\n display: inline-flex;\n}\n\n.view-type-dropdown-trigger {\n width: auto;\n gap: 6px;\n padding: 0 10px;\n border: 1px solid var(--mj-border-default);\n}\n\n.view-type-dropdown-trigger:hover {\n border-color: var(--mj-border-strong);\n}\n\n.view-type-dropdown-label {\n font-size: 13px;\n font-weight: 500;\n}\n\n.view-type-dropdown-caret {\n font-size: 10px;\n opacity: 0.7;\n}\n\n.view-type-dropdown-menu {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n z-index: 20;\n min-width: 180px;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 8px 24px color-mix(in srgb, var(--mj-text-primary) 14%, transparent);\n padding: 4px;\n display: flex;\n flex-direction: column;\n}\n\n.view-type-dropdown-item {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n padding: 8px 10px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 13px;\n text-align: left;\n transition: background 0.12s ease, color 0.12s ease;\n}\n\n.view-type-dropdown-item:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.view-type-dropdown-item.active {\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.view-type-dropdown-item i {\n width: 16px;\n text-align: center;\n}\n"] }]
201
+ }], null, { Entity: [{
202
+ type: Input
203
+ }], ActiveViewTypeID: [{
204
+ type: Input
205
+ }], ViewTypeSelected: [{
206
+ type: Output
207
+ }] }); })();
208
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ViewTypeSwitcherComponent, { className: "ViewTypeSwitcherComponent", filePath: "src/lib/view-type-switcher/view-type-switcher.component.ts", lineNumber: 78 }); })();
209
+ //# sourceMappingURL=view-type-switcher.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-type-switcher.component.js","sourceRoot":"","sources":["../../../src/lib/view-type-switcher/view-type-switcher.component.ts","../../../src/lib/view-type-switcher/view-type-switcher.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n OnInit,\n ChangeDetectorRef,\n inject\n} from '@angular/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { EntityInfo } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { IViewTypeDescriptor, ViewTypeEngine } from '../view-types';\n\n/**\n * A single selectable entry in the view-type switcher. Built from the\n * `MJ: View Types` registry (via {@link ViewTypeEngine}) for the bound entity.\n */\nexport interface ViewTypeSwitcherOption {\n /**\n * Stable key — the descriptor's `Name` (== `MJ: View Types.DriverClass`),\n * e.g. \"GridViewType\", \"ClusterViewType\". Used as the `@for` track key.\n */\n Key: string;\n /** The `MJ: View Types` row ID — what gets emitted and persisted as the active view type. */\n ViewTypeId: string;\n /** User-facing label (from `ViewType.DisplayName`). */\n Label: string;\n /** Font Awesome icon class (from `ViewType.Icon` metadata). */\n Icon: string;\n}\n\n/**\n * Payload emitted by {@link ViewTypeSwitcherComponent.ViewTypeSelected} when the user picks a\n * view type from the menu.\n */\nexport interface ViewTypeSelectedEvent {\n /** The `MJ: View Types` row ID that was selected. */\n viewTypeId: string;\n /** The descriptor `DriverClass` / Name of the selected view type (e.g. \"ClusterViewType\"). */\n driverClass: string;\n}\n\n/**\n * `mj-view-type-switcher` — a small, self-contained dropdown that lets the user switch between\n * the view types available for an entity (Grid / Cards / Timeline / Map / Cluster / third-party\n * plug-ins).\n *\n * It computes its own available types from the `MJ: View Types` registry via the\n * {@link ViewTypeEngine} — the exact same source the {@link EntityViewerComponent} uses — gated by\n * each descriptor's `IsAvailableFor` predicate (e.g. Timeline needs a date field, Map needs\n * geocoding, Cluster needs vectors). Icons come from `ViewType.Icon` metadata. There is\n * intentionally no hardcoded fallback list: when the registry yields one type or fewer, the\n * switcher renders nothing.\n *\n * The component is purely presentational with respect to selection — it does NOT switch the\n * actual rendering. It emits {@link ViewTypeSelected} and the host (the entity-viewer header or\n * the view-workspace toolbar) routes that to its existing view-type selection logic. This keeps\n * the switcher reusable both inside the viewer's own header and lifted up into a parent toolbar\n * without the parent-reads-child `ExpressionChangedAfterItHasBeenCheckedError` anti-pattern.\n *\n * @example\n * ```html\n * <mj-view-type-switcher\n * [Provider]=\"Provider\"\n * [Entity]=\"Entity\"\n * [ActiveViewTypeID]=\"activeViewTypeId\"\n * (ViewTypeSelected)=\"onViewTypeSelected($event)\">\n * </mj-view-type-switcher>\n * ```\n */\n@Component({\n standalone: false,\n selector: 'mj-view-type-switcher',\n templateUrl: './view-type-switcher.component.html',\n styleUrls: ['./view-type-switcher.component.css']\n})\nexport class ViewTypeSwitcherComponent extends BaseAngularComponent implements OnInit {\n private readonly cdr = inject(ChangeDetectorRef);\n\n private _entity: EntityInfo | null = null;\n private _activeViewTypeId: string | null = null;\n private _initialized = false;\n\n /**\n * The entity whose available view types are offered. When it changes the available types\n * are recomputed from the registry.\n */\n @Input()\n get Entity(): EntityInfo | null {\n return this._entity;\n }\n set Entity(value: EntityInfo | null) {\n const previous = this._entity;\n this._entity = value;\n if (this._initialized && (!previous || !value || !UUIDsEqual(value.ID, previous.ID))) {\n this.refreshAvailableTypes();\n }\n }\n\n /**\n * The currently-active view type's `MJ: View Types` row ID (drives the trigger label/icon and\n * the active highlight in the menu). The host owns this — the switcher only requests changes.\n */\n @Input()\n get ActiveViewTypeID(): string | null {\n return this._activeViewTypeId;\n }\n set ActiveViewTypeID(value: string | null) {\n this._activeViewTypeId = value;\n }\n\n /**\n * Emitted when the user selects a view type from the menu. The host routes this to its existing\n * view-type selection logic (by `viewTypeId`). The switcher does not change rendering itself.\n */\n @Output() ViewTypeSelected = new EventEmitter<ViewTypeSelectedEvent>();\n\n /** The available view types for the current entity, sourced from the registry. */\n public AvailableViewTypes: ViewTypeSwitcherOption[] = [];\n\n /** Whether the dropdown menu is currently open. */\n public DropdownOpen = false;\n\n /** Initializes the switcher and performs the first registry resolution. */\n ngOnInit(): void {\n this._initialized = true;\n void this.ensureViewTypesLoaded();\n }\n\n /**\n * The option matching {@link ActiveViewTypeID} (for the trigger's icon + label), or the first\n * available option as a sensible default, or null before the registry resolves.\n */\n get ActiveOption(): ViewTypeSwitcherOption | null {\n const active = this.AvailableViewTypes.find(o => o.ViewTypeId === this._activeViewTypeId);\n return active ?? this.AvailableViewTypes[0] ?? null;\n }\n\n /**\n * Loads the view-type registry once (including each descriptor's availability-data hook) and\n * then computes the available types. Fire-and-forget from {@link ngOnInit}; on failure the\n * switcher simply renders nothing (registry not seeded).\n */\n private async ensureViewTypesLoaded(): Promise<void> {\n try {\n const provider = this.ProviderToUse;\n await ViewTypeEngine.Instance.Config(false, provider?.CurrentUser, provider ?? undefined);\n await ViewTypeEngine.Instance.EnsureAvailabilityData(provider ?? undefined);\n this.refreshAvailableTypes();\n } catch {\n this.AvailableViewTypes = [];\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Recomputes {@link AvailableViewTypes} from the registry for the current entity. Each available\n * `MJ: View Types` row is mapped to a switcher option using its descriptor's display metadata.\n */\n private refreshAvailableTypes(): void {\n const entity = this._entity;\n if (!entity) {\n this.AvailableViewTypes = [];\n this.cdr.detectChanges();\n return;\n }\n\n let rows: Array<{ ViewType: { ID: string }; Descriptor: IViewTypeDescriptor }> = [];\n try {\n rows = ViewTypeEngine.Instance.GetAvailableViewTypeRows(entity, this.ProviderToUse ?? undefined);\n } catch {\n rows = [];\n }\n\n this.AvailableViewTypes = rows.map(({ ViewType, Descriptor }) => ({\n Key: Descriptor.Name,\n ViewTypeId: ViewType.ID,\n Label: Descriptor.DisplayName,\n Icon: Descriptor.Icon ?? ''\n }));\n this.cdr.detectChanges();\n }\n\n /** Toggles the dropdown menu open/closed. */\n public ToggleDropdown(): void {\n this.DropdownOpen = !this.DropdownOpen;\n }\n\n /**\n * Handles a menu selection. Closes the menu and emits {@link ViewTypeSelected} so the host can\n * apply the switch through its own selection logic.\n */\n public SelectViewType(option: ViewTypeSwitcherOption): void {\n this.DropdownOpen = false;\n this.ViewTypeSelected.emit({ viewTypeId: option.ViewTypeId, driverClass: option.Key });\n }\n}\n","<!-- View-type switcher: a single dropdown driven entirely by the MJ: View Types registry.\n Available types + icons come from metadata, filtered by each descriptor's availability\n predicate. Renders nothing when the registry yields one type or fewer. -->\n@if (AvailableViewTypes.length > 1) {\n <div class=\"view-type-dropdown\">\n <button\n type=\"button\"\n class=\"toggle-btn view-type-dropdown-trigger\"\n [class.active]=\"DropdownOpen\"\n (click)=\"ToggleDropdown()\"\n [title]=\"(ActiveOption?.Label ?? '') + ' View'\">\n <i [class]=\"ActiveOption?.Icon\"></i>\n <span class=\"view-type-dropdown-label\">{{ ActiveOption?.Label }}</span>\n <i class=\"fa-solid fa-chevron-down view-type-dropdown-caret\"></i>\n </button>\n @if (DropdownOpen) {\n <div class=\"view-type-dropdown-menu\">\n @for (vt of AvailableViewTypes; track vt.Key) {\n <button\n type=\"button\"\n class=\"view-type-dropdown-item\"\n [class.active]=\"ActiveOption?.Key === vt.Key\"\n (click)=\"SelectViewType(vt)\">\n <i [class]=\"vt.Icon\"></i>\n <span>{{ vt.Label }}</span>\n </button>\n }\n </div>\n }\n </div>\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import { Type } from '@angular/core';
2
+ import { BaseViewTypeDescriptor } from '../view-type.contracts';
3
+ /**
4
+ * Cards view type — renders each record as a card in a responsive grid. Available for
5
+ * every entity.
6
+ *
7
+ * Registration key (`DriverClass`) matches the `MJ: View Types` metadata seed:
8
+ * `metadata/view-types/.view-types.json` → "CardsViewType".
9
+ */
10
+ export declare class CardsViewType extends BaseViewTypeDescriptor {
11
+ readonly Name = "CardsViewType";
12
+ readonly DisplayName = "Cards";
13
+ readonly Icon = "fa-solid fa-grip";
14
+ readonly RendererComponent: Type<unknown>;
15
+ }
16
+ /** Tree-shaking guard — call from a barrel/module to keep the registration alive. */
17
+ export declare function LoadCardsViewType(): void;
18
+ //# sourceMappingURL=cards-view-type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cards-view-type.d.ts","sourceRoot":"","sources":["../../../../src/lib/view-types/descriptors/cards-view-type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAGhE;;;;;;GAMG;AACH,qBACa,aAAc,SAAQ,sBAAsB;IACvD,QAAQ,CAAC,IAAI,mBAAmB;IAChC,QAAQ,CAAC,WAAW,WAAW;IAC/B,QAAQ,CAAC,IAAI,sBAAsB;IACnC,QAAQ,CAAC,iBAAiB,EAAE,IAAI,CAAC,OAAO,CAAC,CAA8B;CAGxE;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
@@ -0,0 +1,31 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { RegisterClass } from '@memberjunction/global';
8
+ import { BaseViewTypeDescriptor } from '../view-type.contracts';
9
+ import { CardsViewRendererComponent } from '../renderers/cards-view-renderer.component';
10
+ /**
11
+ * Cards view type — renders each record as a card in a responsive grid. Available for
12
+ * every entity.
13
+ *
14
+ * Registration key (`DriverClass`) matches the `MJ: View Types` metadata seed:
15
+ * `metadata/view-types/.view-types.json` → "CardsViewType".
16
+ */
17
+ let CardsViewType = class CardsViewType extends BaseViewTypeDescriptor {
18
+ Name = 'CardsViewType';
19
+ DisplayName = 'Cards';
20
+ Icon = 'fa-solid fa-grip';
21
+ RendererComponent = CardsViewRendererComponent;
22
+ };
23
+ CardsViewType = __decorate([
24
+ RegisterClass(BaseViewTypeDescriptor, 'CardsViewType')
25
+ ], CardsViewType);
26
+ export { CardsViewType };
27
+ /** Tree-shaking guard — call from a barrel/module to keep the registration alive. */
28
+ export function LoadCardsViewType() {
29
+ // no-op
30
+ }
31
+ //# sourceMappingURL=cards-view-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cards-view-type.js","sourceRoot":"","sources":["../../../../src/lib/view-types/descriptors/cards-view-type.ts"],"names":[],"mappings":";;;;;;AACA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,0BAA0B,EAAE,MAAM,4CAA4C,CAAC;AAExF;;;;;;GAMG;AAEI,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,sBAAsB;IAC9C,IAAI,GAAG,eAAe,CAAC;IACvB,WAAW,GAAG,OAAO,CAAC;IACtB,IAAI,GAAG,kBAAkB,CAAC;IAC1B,iBAAiB,GAAkB,0BAA0B,CAAC;CAGxE,CAAA;AAPY,aAAa;IADzB,aAAa,CAAC,sBAAsB,EAAE,eAAe,CAAC;GAC1C,aAAa,CAOzB;;AAED,qFAAqF;AACrF,MAAM,UAAU,iBAAiB;IAC/B,QAAQ;AACV,CAAC","sourcesContent":["import { Type } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseViewTypeDescriptor } from '../view-type.contracts';\nimport { CardsViewRendererComponent } from '../renderers/cards-view-renderer.component';\n\n/**\n * Cards view type — renders each record as a card in a responsive grid. Available for\n * every entity.\n *\n * Registration key (`DriverClass`) matches the `MJ: View Types` metadata seed:\n * `metadata/view-types/.view-types.json` → \"CardsViewType\".\n */\n@RegisterClass(BaseViewTypeDescriptor, 'CardsViewType')\nexport class CardsViewType extends BaseViewTypeDescriptor {\n readonly Name = 'CardsViewType';\n readonly DisplayName = 'Cards';\n readonly Icon = 'fa-solid fa-grip';\n readonly RendererComponent: Type<unknown> = CardsViewRendererComponent;\n\n // IsAvailableFor inherits the base \"always available\" behavior.\n}\n\n/** Tree-shaking guard — call from a barrel/module to keep the registration alive. */\nexport function LoadCardsViewType(): void {\n // no-op\n}\n"]}
@@ -0,0 +1,17 @@
1
+ import { Type } from '@angular/core';
2
+ import { BaseViewTypeDescriptor } from '../view-type.contracts';
3
+ /**
4
+ * Grid view type — the classic tabular AG-Grid renderer. Available for every entity.
5
+ *
6
+ * Registration key (`DriverClass`) matches the `MJ: View Types` metadata seed:
7
+ * `metadata/view-types/.view-types.json` → "GridViewType".
8
+ */
9
+ export declare class GridViewType extends BaseViewTypeDescriptor {
10
+ readonly Name = "GridViewType";
11
+ readonly DisplayName = "Grid";
12
+ readonly Icon = "fa-solid fa-table";
13
+ readonly RendererComponent: Type<unknown>;
14
+ }
15
+ /** Tree-shaking guard — call from a barrel/module to keep the registration alive. */
16
+ export declare function LoadGridViewType(): void;
17
+ //# sourceMappingURL=grid-view-type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid-view-type.d.ts","sourceRoot":"","sources":["../../../../src/lib/view-types/descriptors/grid-view-type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAGhE;;;;;GAKG;AACH,qBACa,YAAa,SAAQ,sBAAsB;IACtD,QAAQ,CAAC,IAAI,kBAAkB;IAC/B,QAAQ,CAAC,WAAW,UAAU;IAC9B,QAAQ,CAAC,IAAI,uBAAuB;IACpC,QAAQ,CAAC,iBAAiB,EAAE,IAAI,CAAC,OAAO,CAAC,CAA6B;CAGvE;AAED,qFAAqF;AACrF,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC"}
@@ -0,0 +1,30 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { RegisterClass } from '@memberjunction/global';
8
+ import { BaseViewTypeDescriptor } from '../view-type.contracts';
9
+ import { GridViewRendererComponent } from '../renderers/grid-view-renderer.component';
10
+ /**
11
+ * Grid view type — the classic tabular AG-Grid renderer. Available for every entity.
12
+ *
13
+ * Registration key (`DriverClass`) matches the `MJ: View Types` metadata seed:
14
+ * `metadata/view-types/.view-types.json` → "GridViewType".
15
+ */
16
+ let GridViewType = class GridViewType extends BaseViewTypeDescriptor {
17
+ Name = 'GridViewType';
18
+ DisplayName = 'Grid';
19
+ Icon = 'fa-solid fa-table';
20
+ RendererComponent = GridViewRendererComponent;
21
+ };
22
+ GridViewType = __decorate([
23
+ RegisterClass(BaseViewTypeDescriptor, 'GridViewType')
24
+ ], GridViewType);
25
+ export { GridViewType };
26
+ /** Tree-shaking guard — call from a barrel/module to keep the registration alive. */
27
+ export function LoadGridViewType() {
28
+ // no-op
29
+ }
30
+ //# sourceMappingURL=grid-view-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid-view-type.js","sourceRoot":"","sources":["../../../../src/lib/view-types/descriptors/grid-view-type.ts"],"names":[],"mappings":";;;;;;AACA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AAEtF;;;;;GAKG;AAEI,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,sBAAsB;IAC7C,IAAI,GAAG,cAAc,CAAC;IACtB,WAAW,GAAG,MAAM,CAAC;IACrB,IAAI,GAAG,mBAAmB,CAAC;IAC3B,iBAAiB,GAAkB,yBAAyB,CAAC;CAGvE,CAAA;AAPY,YAAY;IADxB,aAAa,CAAC,sBAAsB,EAAE,cAAc,CAAC;GACzC,YAAY,CAOxB;;AAED,qFAAqF;AACrF,MAAM,UAAU,gBAAgB;IAC9B,QAAQ;AACV,CAAC","sourcesContent":["import { Type } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseViewTypeDescriptor } from '../view-type.contracts';\nimport { GridViewRendererComponent } from '../renderers/grid-view-renderer.component';\n\n/**\n * Grid view type — the classic tabular AG-Grid renderer. Available for every entity.\n *\n * Registration key (`DriverClass`) matches the `MJ: View Types` metadata seed:\n * `metadata/view-types/.view-types.json` → \"GridViewType\".\n */\n@RegisterClass(BaseViewTypeDescriptor, 'GridViewType')\nexport class GridViewType extends BaseViewTypeDescriptor {\n readonly Name = 'GridViewType';\n readonly DisplayName = 'Grid';\n readonly Icon = 'fa-solid fa-table';\n readonly RendererComponent: Type<unknown> = GridViewRendererComponent;\n\n // IsAvailableFor inherits the base \"always available\" behavior.\n}\n\n/** Tree-shaking guard — call from a barrel/module to keep the registration alive. */\nexport function LoadGridViewType(): void {\n // no-op\n}\n"]}
@@ -0,0 +1,21 @@
1
+ import { Type } from '@angular/core';
2
+ import { EntityInfo, IMetadataProvider } from '@memberjunction/core';
3
+ import { BaseViewTypeDescriptor } from '../view-type.contracts';
4
+ /**
5
+ * Map view type — renders geocoded records as markers on an interactive map. Available
6
+ * only for entities that support geocoding (lifted from the host's `updateGeoCodingSupport`
7
+ * logic, which checks `entity.SupportsGeoCoding`).
8
+ *
9
+ * Registration key (`DriverClass`) matches the `MJ: View Types` metadata seed:
10
+ * `metadata/view-types/.view-types.json` → "MapViewType".
11
+ */
12
+ export declare class MapViewType extends BaseViewTypeDescriptor {
13
+ readonly Name = "MapViewType";
14
+ readonly DisplayName = "Map";
15
+ readonly Icon = "fa-solid fa-map-location-dot";
16
+ readonly RendererComponent: Type<unknown>;
17
+ IsAvailableFor(entity: EntityInfo, _provider?: IMetadataProvider): boolean;
18
+ }
19
+ /** Tree-shaking guard — call from a barrel/module to keep the registration alive. */
20
+ export declare function LoadMapViewType(): void;
21
+ //# sourceMappingURL=map-view-type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"map-view-type.d.ts","sourceRoot":"","sources":["../../../../src/lib/view-types/descriptors/map-view-type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAErE,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAGhE;;;;;;;GAOG;AACH,qBACa,WAAY,SAAQ,sBAAsB;IACrD,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,WAAW,SAAS;IAC7B,QAAQ,CAAC,IAAI,kCAAkC;IAC/C,QAAQ,CAAC,iBAAiB,EAAE,IAAI,CAAC,OAAO,CAAC,CAA4B;IAE5D,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,iBAAiB,GAAG,OAAO;CAGpF;AAED,qFAAqF;AACrF,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}