@memberjunction/ng-dashboards 5.8.0 → 5.10.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.
- package/dist/AI/components/models/model-management.component.d.ts +2 -0
- package/dist/AI/components/models/model-management.component.d.ts.map +1 -1
- package/dist/AI/components/models/model-management.component.js +44 -2
- package/dist/AI/components/models/model-management.component.js.map +1 -1
- package/dist/DashboardBrowser/dashboard-browser-resource.component.d.ts.map +1 -1
- package/dist/DashboardBrowser/dashboard-browser-resource.component.js +15 -12
- package/dist/DashboardBrowser/dashboard-browser-resource.component.js.map +1 -1
- package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts.map +1 -1
- package/dist/DataExplorer/components/view-selector/view-selector.component.js +16 -22
- package/dist/DataExplorer/components/view-selector/view-selector.component.js.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +31 -11
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/Home/home-dashboard.component.d.ts.map +1 -1
- package/dist/Home/home-dashboard.component.js +10 -7
- package/dist/Home/home-dashboard.component.js.map +1 -1
- package/dist/Integration/components/activity/activity.component.d.ts +96 -0
- package/dist/Integration/components/activity/activity.component.d.ts.map +1 -0
- package/dist/Integration/components/activity/activity.component.js +961 -0
- package/dist/Integration/components/activity/activity.component.js.map +1 -0
- package/dist/Integration/components/connections/connections.component.d.ts +194 -0
- package/dist/Integration/components/connections/connections.component.d.ts.map +1 -0
- package/dist/Integration/components/connections/connections.component.js +2368 -0
- package/dist/Integration/components/connections/connections.component.js.map +1 -0
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.d.ts +213 -15
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.d.ts.map +1 -1
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js +2093 -187
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js.map +1 -1
- package/dist/Integration/components/overview/overview.component.d.ts +60 -0
- package/dist/Integration/components/overview/overview.component.d.ts.map +1 -0
- package/dist/Integration/components/overview/overview.component.js +628 -0
- package/dist/Integration/components/overview/overview.component.js.map +1 -0
- package/dist/Integration/components/pipelines/pipelines.component.d.ts +203 -0
- package/dist/Integration/components/pipelines/pipelines.component.d.ts.map +1 -0
- package/dist/Integration/components/pipelines/pipelines.component.js +2057 -0
- package/dist/Integration/components/pipelines/pipelines.component.js.map +1 -0
- package/dist/Integration/components/schedules/schedules.component.d.ts +110 -0
- package/dist/Integration/components/schedules/schedules.component.d.ts.map +1 -0
- package/dist/Integration/components/schedules/schedules.component.js +842 -0
- package/dist/Integration/components/schedules/schedules.component.js.map +1 -0
- package/dist/Integration/components/visual-editor/visual-editor.component.d.ts +141 -0
- package/dist/Integration/components/visual-editor/visual-editor.component.d.ts.map +1 -0
- package/dist/Integration/components/visual-editor/visual-editor.component.js +1538 -0
- package/dist/Integration/components/visual-editor/visual-editor.component.js.map +1 -0
- package/dist/Integration/components/widgets/run-history-panel.component.js +3 -2
- package/dist/Integration/components/widgets/run-history-panel.component.js.map +1 -1
- package/dist/Integration/index.d.ts +5 -3
- package/dist/Integration/index.d.ts.map +1 -1
- package/dist/Integration/index.js +11 -7
- package/dist/Integration/index.js.map +1 -1
- package/dist/Integration/integration.module.d.ts +20 -16
- package/dist/Integration/integration.module.d.ts.map +1 -1
- package/dist/Integration/integration.module.js +40 -21
- package/dist/Integration/integration.module.js.map +1 -1
- package/dist/Integration/services/integration-data.service.d.ts +123 -9
- package/dist/Integration/services/integration-data.service.d.ts.map +1 -1
- package/dist/Integration/services/integration-data.service.js +385 -68
- package/dist/Integration/services/integration-data.service.js.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.d.ts +27 -4
- package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.js +338 -144
- package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
- package/dist/__tests__/integration-data-service.test.js.map +1 -1
- package/dist/__tests__/mapping-validation.test.d.ts +2 -0
- package/dist/__tests__/mapping-validation.test.d.ts.map +1 -0
- package/dist/__tests__/mapping-validation.test.js +170 -0
- package/dist/__tests__/mapping-validation.test.js.map +1 -0
- package/package.json +40 -38
- package/dist/Integration/components/connection-studio/connection-studio.component.d.ts +0 -81
- package/dist/Integration/components/connection-studio/connection-studio.component.d.ts.map +0 -1
- package/dist/Integration/components/connection-studio/connection-studio.component.js +0 -960
- package/dist/Integration/components/connection-studio/connection-studio.component.js.map +0 -1
- package/dist/Integration/components/control-tower/control-tower.component.d.ts +0 -43
- package/dist/Integration/components/control-tower/control-tower.component.d.ts.map +0 -1
- package/dist/Integration/components/control-tower/control-tower.component.js +0 -446
- package/dist/Integration/components/control-tower/control-tower.component.js.map +0 -1
- package/dist/Integration/components/sync-activity/sync-activity.component.d.ts +0 -65
- package/dist/Integration/components/sync-activity/sync-activity.component.d.ts.map +0 -1
- package/dist/Integration/components/sync-activity/sync-activity.component.js +0 -671
- package/dist/Integration/components/sync-activity/sync-activity.component.js.map +0 -1
- package/dist/__tests__/connection-studio.test.d.ts +0 -2
- package/dist/__tests__/connection-studio.test.d.ts.map +0 -1
- package/dist/__tests__/connection-studio.test.js +0 -186
- package/dist/__tests__/connection-studio.test.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-browser-resource.component.js","sourceRoot":"","sources":["../../src/QueryBrowser/query-browser-resource.component.ts","../../src/QueryBrowser/query-browser-resource.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ChangeDetectorRef, ChangeDetectionStrategy, ElementRef, NgZone } from '@angular/core';\nimport { Router, NavigationEnd } from '@angular/router';\nimport { Subject } from 'rxjs';\nimport { takeUntil, filter } from 'rxjs/operators';\nimport { RegisterClass , UUIDsEqual } from '@memberjunction/global';\nimport { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';\nimport { Metadata, QueryInfo, QueryCategoryInfo, CompositeKey } from '@memberjunction/core';\nimport { ResourceData, UserInfoEngine } from '@memberjunction/core-entities';\nimport {\n QueryEntityLinkClickEvent,\n QueryRowClickEvent\n} from '@memberjunction/ng-query-viewer';\n/**\n * Tree node for the query category hierarchy\n */\ninterface CategoryNode {\n category: QueryCategoryInfo;\n children: CategoryNode[];\n queries: QueryInfo[];\n expanded: boolean;\n level: number;\n}\n\n/**\n * A resource component for browsing and executing stored queries.\n * Features:\n * - Hierarchical category navigation\n * - Query search\n * - Query viewer with parameter input\n * - Entity linking for clickable record IDs\n */\n@RegisterClass(BaseResourceComponent, 'QueryBrowserResource')\n@Component({\n standalone: false,\n selector: 'mj-query-browser-resource',\n templateUrl: './query-browser-resource.component.html',\n styleUrls: ['./query-browser-resource.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class QueryBrowserResourceComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n private static readonly SETTINGS_KEY = 'QueryBrowser/panelWidth';\n private static readonly DEFAULT_PANEL_WIDTH = 320;\n private static readonly MIN_PANEL_WIDTH = 200;\n private static readonly MAX_PANEL_WIDTH = 600;\n\n public isLoading = true;\n public categories: QueryCategoryInfo[] = [];\n public categoryTree: CategoryNode[] = [];\n public queries: QueryInfo[] = [];\n public filteredQueries: QueryInfo[] = [];\n public selectedQuery: QueryInfo | null = null;\n public searchText = '';\n public PanelWidth = QueryBrowserResourceComponent.DEFAULT_PANEL_WIDTH;\n public IsResizing = false;\n\n private metadata = new Metadata();\n private destroy$ = new Subject<void>();\n private dataLoaded = false;\n private skipUrlUpdate = true; // Skip URL updates during initialization\n private lastNavigatedUrl = ''; // Track URL to avoid reacting to our own navigation\n\n // Bound event handlers for resize (need references for removeEventListener)\n private boundOnResizeMove = this.onResizeMove.bind(this);\n private boundOnResizeEnd = this.onResizeEnd.bind(this);\n\n constructor(\n private cdr: ChangeDetectorRef,\n private navigationService: NavigationService,\n private router: Router,\n private elementRef: ElementRef,\n private zone: NgZone\n ) {\n super();\n }\n\n ngOnInit(): void {\n this.loadSavedPanelWidth();\n this.loadData();\n\n // Subscribe to router NavigationEnd events for back/forward button support\n this.router.events\n .pipe(\n filter((event): event is NavigationEnd => event instanceof NavigationEnd),\n takeUntil(this.destroy$)\n )\n .subscribe(event => {\n const currentUrl = event.urlAfterRedirects || event.url;\n if (currentUrl !== this.lastNavigatedUrl && this.dataLoaded) {\n this.onExternalNavigation(currentUrl);\n }\n });\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n // Ensure any pending debounced settings are flushed\n UserInfoEngine.Instance.FlushPendingSettings();\n // Remove resize listeners if active\n document.removeEventListener('mousemove', this.boundOnResizeMove);\n document.removeEventListener('mouseup', this.boundOnResizeEnd);\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n return 'Queries';\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-database';\n }\n\n // ========================================\n // Data Loading\n // ========================================\n\n private async loadData(forceRefresh = false): Promise<void> {\n try {\n this.isLoading = true;\n this.cdr.markForCheck();\n\n // Force re-fetch from server when explicitly refreshing\n if (forceRefresh) {\n await this.metadata.Refresh();\n }\n\n // Load from metadata\n this.categories = this.metadata.QueryCategories || [];\n this.queries = (this.metadata.Queries || []).filter(q =>\n q.Status === 'Approved' && q.UserCanRun(this.metadata.CurrentUser)\n );\n\n this.filteredQueries = [...this.queries];\n this.buildCategoryTree();\n\n // Mark data as loaded and apply any query params for deep linking\n this.dataLoaded = true;\n\n // Parse initial URL state\n const urlState = this.parseUrlState();\n if (urlState?.queryId) {\n const query = this.queries.find(q => UUIDsEqual(q.ID, urlState.queryId));\n if (query) {\n this.selectedQuery = query;\n this.expandCategoryForQuery(query);\n }\n }\n\n // Enable URL updates after initialization\n this.skipUrlUpdate = false;\n\n } catch (error) {\n console.error('Error loading queries:', error);\n } finally {\n this.isLoading = false;\n this.NotifyLoadComplete();\n this.cdr.markForCheck();\n }\n }\n\n private buildCategoryTree(): void {\n const categoryMap = new Map<string, CategoryNode>();\n\n // Create nodes for all categories\n for (const category of this.categories) {\n const queriesInCategory = this.queries.filter(q => UUIDsEqual(q.CategoryID, category.ID));\n categoryMap.set(category.ID, {\n category,\n children: [],\n queries: queriesInCategory,\n expanded: true,\n level: 0\n });\n }\n\n // Build tree structure\n const roots: CategoryNode[] = [];\n for (const category of this.categories) {\n const node = categoryMap.get(category.ID)!;\n if (category.ParentID) {\n const parent = categoryMap.get(category.ParentID);\n if (parent) {\n node.level = parent.level + 1;\n parent.children.push(node);\n } else {\n roots.push(node);\n }\n } else {\n roots.push(node);\n }\n }\n\n // Add uncategorized queries to a virtual root\n const uncategorizedQueries = this.queries.filter(q => !q.CategoryID);\n if (uncategorizedQueries.length > 0) {\n const uncategorizedCategory = new QueryCategoryInfo({\n ID: '__uncategorized__',\n Name: 'Uncategorized',\n Description: 'Queries without a category'\n });\n roots.push({\n category: uncategorizedCategory,\n children: [],\n queries: uncategorizedQueries,\n expanded: true,\n level: 0\n });\n }\n\n // Sort children recursively\n const sortNodes = (nodes: CategoryNode[]): void => {\n nodes.sort((a, b) => a.category.Name.localeCompare(b.category.Name));\n for (const node of nodes) {\n node.queries.sort((a, b) => a.Name.localeCompare(b.Name));\n sortNodes(node.children);\n }\n };\n sortNodes(roots);\n\n this.categoryTree = roots;\n }\n\n // ========================================\n // Search\n // ========================================\n\n public onSearchChange(value: string): void {\n this.searchText = value;\n\n if (!value.trim()) {\n this.filteredQueries = [...this.queries];\n } else {\n const searchLower = value.toLowerCase();\n this.filteredQueries = this.queries.filter(q =>\n q.Name.toLowerCase().includes(searchLower) ||\n q.Description?.toLowerCase().includes(searchLower) ||\n q.Category?.toLowerCase().includes(searchLower)\n );\n }\n\n // Expand all categories when searching\n if (value) {\n this.expandAll();\n }\n\n this.cdr.markForCheck();\n }\n\n public clearSearch(): void {\n this.searchText = '';\n this.filteredQueries = [...this.queries];\n this.cdr.markForCheck();\n }\n\n // ========================================\n // Tree Navigation\n // ========================================\n\n public toggleExpand(node: CategoryNode, event?: Event): void {\n if (event) {\n event.stopPropagation();\n }\n node.expanded = !node.expanded;\n this.cdr.markForCheck();\n }\n\n public expandAll(): void {\n const expand = (nodes: CategoryNode[]): void => {\n for (const node of nodes) {\n node.expanded = true;\n expand(node.children);\n }\n };\n expand(this.categoryTree);\n this.cdr.markForCheck();\n }\n\n public collapseAll(): void {\n const collapse = (nodes: CategoryNode[]): void => {\n for (const node of nodes) {\n node.expanded = false;\n collapse(node.children);\n }\n };\n collapse(this.categoryTree);\n this.cdr.markForCheck();\n }\n\n public selectQuery(query: QueryInfo, event?: Event): void {\n if (event) {\n event.stopPropagation();\n }\n this.selectedQuery = query;\n this.updateUrl();\n this.cdr.markForCheck();\n }\n\n public isQueryVisible(query: QueryInfo): boolean {\n if (!this.searchText) return true;\n return this.filteredQueries.some(q => UUIDsEqual(q.ID, query.ID));\n }\n\n public hasVisibleContent(node: CategoryNode): boolean {\n if (!this.searchText) return true;\n\n // Check if any queries in this category match\n if (node.queries.some(q => this.isQueryVisible(q))) {\n return true;\n }\n\n // Check if any child categories have visible content\n return node.children.some(child => this.hasVisibleContent(child));\n }\n\n // ========================================\n // Query Viewer Events\n // ========================================\n\n public onEntityLinkClick(event: QueryEntityLinkClickEvent): void {\n // Open the entity record using navigation service\n // Convert the recordId string to a CompositeKey (assumes single-field primary key)\n const compositeKey = CompositeKey.FromID(event.recordId);\n this.navigationService.OpenEntityRecord(event.entityName, compositeKey);\n }\n\n public onRowDoubleClick(event: QueryRowClickEvent): void {\n // Could show record details or other action\n }\n\n public onOpenQueryRecord(event: { queryId: string; queryName: string }): void {\n // Open the Query entity record using navigation service\n const compositeKey = CompositeKey.FromID(event.queryId);\n this.navigationService.OpenEntityRecord('MJ: Queries', compositeKey);\n }\n\n public openQueryDetails(query: QueryInfo, event: Event): void {\n // Stop propagation so clicking the button doesn't also select the query\n event.stopPropagation();\n // Open the Query entity record\n const compositeKey = CompositeKey.FromID(query.ID);\n this.navigationService.OpenEntityRecord('MJ: Queries', compositeKey);\n }\n\n // ========================================\n // Utilities\n // ========================================\n\n public getTotalQueryCount(): number {\n return this.queries.length;\n }\n\n public getNodeQueryCount(node: CategoryNode): number {\n let count = node.queries.length;\n for (const child of node.children) {\n count += this.getNodeQueryCount(child);\n }\n return count;\n }\n\n public refresh(): void {\n this.selectedQuery = null;\n this.loadData(true);\n }\n\n public trackByCategory(index: number, node: CategoryNode): string {\n return node.category.ID;\n }\n\n public trackByQuery(index: number, query: QueryInfo): string {\n return query.ID;\n }\n\n // ========================================\n // Deep Linking\n // ========================================\n\n /**\n * Parse URL query string for query state.\n * Query params: queryId\n */\n private parseUrlState(): { queryId?: string } | null {\n const url = this.router.url;\n const queryIndex = url.indexOf('?');\n if (queryIndex === -1) return null;\n\n const queryString = url.substring(queryIndex + 1);\n const params = new URLSearchParams(queryString);\n const queryId = params.get('queryId');\n\n if (!queryId) return null;\n\n return { queryId };\n }\n\n /**\n * Update URL query string to reflect current state.\n * Uses NavigationService for proper URL management that respects app-scoped routes.\n */\n private updateUrl(): void {\n if (this.skipUrlUpdate) return;\n\n const queryParams: Record<string, string | null> = {};\n\n // Add query ID if selected, null to remove\n if (this.selectedQuery?.ID) {\n queryParams['queryId'] = this.selectedQuery.ID;\n } else {\n queryParams['queryId'] = null;\n }\n\n // Use NavigationService to update query params properly\n this.navigationService.UpdateActiveTabQueryParams(queryParams);\n }\n\n /**\n * Handle external navigation (back/forward buttons).\n * Parses the URL and applies the state without triggering a new navigation.\n */\n private onExternalNavigation(url: string): void {\n // Check if this URL is for our component (contains our base path)\n const currentPath = this.router.url.split('?')[0];\n const newPath = url.split('?')[0];\n\n // Only handle if we're still on the same base path (same component instance)\n if (currentPath !== newPath) {\n return; // Different route entirely, shell will handle it\n }\n\n // Parse the new URL state\n const urlState = this.parseUrlFromString(url);\n\n // Apply the state without triggering URL updates\n this.skipUrlUpdate = true;\n if (urlState?.queryId) {\n const query = this.queries.find(q => UUIDsEqual(q.ID, urlState.queryId));\n if (query) {\n if (!UUIDsEqual(this.selectedQuery?.ID, query.ID)) {\n this.selectedQuery = query;\n this.expandCategoryForQuery(query);\n }\n }\n } else {\n // No queryId means clear selection\n this.selectedQuery = null;\n }\n this.skipUrlUpdate = false;\n\n // Update the tracked URL\n this.lastNavigatedUrl = url;\n\n this.cdr.markForCheck();\n }\n\n /**\n * Parse URL state from a URL string (used for external navigation).\n */\n private parseUrlFromString(url: string): { queryId?: string } | null {\n const queryIndex = url.indexOf('?');\n if (queryIndex === -1) return null;\n\n const queryString = url.substring(queryIndex + 1);\n const params = new URLSearchParams(queryString);\n const queryId = params.get('queryId');\n\n if (!queryId) return null;\n\n return { queryId };\n }\n\n /**\n * Expands the category tree to show the given query\n */\n private expandCategoryForQuery(query: QueryInfo): void {\n if (!query.CategoryID) return;\n\n const expandCategory = (nodes: CategoryNode[], targetCategoryId: string): boolean => {\n for (const node of nodes) {\n if (UUIDsEqual(node.category.ID, targetCategoryId)) {\n node.expanded = true;\n return true;\n }\n if (this.expandCategoryForQueryRecursive(node.children, targetCategoryId)) {\n node.expanded = true;\n return true;\n }\n }\n return false;\n };\n\n expandCategory(this.categoryTree, query.CategoryID);\n }\n\n /**\n * Helper for recursive category expansion\n */\n private expandCategoryForQueryRecursive(nodes: CategoryNode[], targetCategoryId: string): boolean {\n for (const node of nodes) {\n if (UUIDsEqual(node.category.ID, targetCategoryId)) {\n node.expanded = true;\n return true;\n }\n if (node.children.length > 0 && this.expandCategoryForQueryRecursive(node.children, targetCategoryId)) {\n node.expanded = true;\n return true;\n }\n }\n return false;\n }\n\n // ========================================\n // Panel Resize\n // ========================================\n\n /**\n * Load saved panel width from user settings\n */\n private loadSavedPanelWidth(): void {\n const saved = UserInfoEngine.Instance.GetSetting(QueryBrowserResourceComponent.SETTINGS_KEY);\n if (saved) {\n const width = parseInt(saved, 10);\n if (!isNaN(width) && width >= QueryBrowserResourceComponent.MIN_PANEL_WIDTH && width <= QueryBrowserResourceComponent.MAX_PANEL_WIDTH) {\n this.PanelWidth = width;\n }\n }\n }\n\n /**\n * Start resizing the left panel via drag handle\n */\n public onResizeStart(event: MouseEvent): void {\n event.preventDefault();\n this.IsResizing = true;\n this.cdr.markForCheck();\n\n // Run outside Angular zone for performance during mousemove\n this.zone.runOutsideAngular(() => {\n document.addEventListener('mousemove', this.boundOnResizeMove);\n document.addEventListener('mouseup', this.boundOnResizeEnd);\n });\n }\n\n private onResizeMove(event: MouseEvent): void {\n if (!this.IsResizing) return;\n\n const containerRect = this.elementRef.nativeElement.querySelector('.query-browser-container')?.getBoundingClientRect();\n if (!containerRect) return;\n\n const newWidth = event.clientX - containerRect.left;\n const clamped = Math.max(\n QueryBrowserResourceComponent.MIN_PANEL_WIDTH,\n Math.min(QueryBrowserResourceComponent.MAX_PANEL_WIDTH, newWidth)\n );\n\n this.PanelWidth = clamped;\n this.zone.run(() => this.cdr.markForCheck());\n }\n\n private onResizeEnd(): void {\n if (!this.IsResizing) return;\n this.IsResizing = false;\n\n document.removeEventListener('mousemove', this.boundOnResizeMove);\n document.removeEventListener('mouseup', this.boundOnResizeEnd);\n\n // Persist width with debouncing\n UserInfoEngine.Instance.SetSettingDebounced(\n QueryBrowserResourceComponent.SETTINGS_KEY,\n this.PanelWidth.toString()\n );\n\n this.zone.run(() => this.cdr.markForCheck());\n }\n\n /** Case-insensitive UUID check whether a query is the currently selected query. */\n public IsQuerySelected(query: QueryInfo): boolean {\n return UUIDsEqual(this.selectedQuery?.ID, query.ID);\n }\n}\n","<!-- Query Browser Resource -->\n<div class=\"query-browser-container\" [class.resizing]=\"IsResizing\">\n <!-- Left Panel: Query Tree -->\n <div class=\"query-tree-panel\" [style.width.px]=\"PanelWidth\">\n <!-- Header -->\n <div class=\"tree-header\">\n <div class=\"header-title\">\n <i class=\"fa-solid fa-database\"></i>\n <span>Queries</span>\n <span class=\"query-count\">({{ getTotalQueryCount() }})</span>\n </div>\n <div class=\"header-actions\">\n <button class=\"icon-btn\" (click)=\"expandAll()\" title=\"Expand all\">\n <i class=\"fa-solid fa-folder-open\"></i>\n </button>\n <button class=\"icon-btn\" (click)=\"collapseAll()\" title=\"Collapse all\">\n <i class=\"fa-solid fa-folder\"></i>\n </button>\n <button class=\"icon-btn\" (click)=\"refresh()\" title=\"Refresh\">\n <i class=\"fa-solid fa-refresh\"></i>\n </button>\n </div>\n </div>\n\n <!-- Search -->\n <div class=\"tree-search\">\n <div class=\"search-input-wrapper\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input type=\"text\"\n class=\"search-input\"\n [value]=\"searchText\"\n placeholder=\"Search queries...\"\n (input)=\"onSearchChange($any($event.target).value)\">\n @if (searchText) {\n <button class=\"clear-btn\" (click)=\"clearSearch()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n </div>\n\n <!-- Tree Content -->\n <div class=\"tree-content\">\n <!-- Loading -->\n @if (isLoading) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading queries...\"></mj-loading>\n </div>\n }\n\n <!-- Empty -->\n @if (!isLoading && queries.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-database empty-icon\"></i>\n <p>No queries available</p>\n </div>\n }\n\n <!-- No results -->\n @if (!isLoading && searchText && filteredQueries.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-search empty-icon\"></i>\n <p>No queries match \"{{ searchText }}\"</p>\n </div>\n }\n\n <!-- Category Tree -->\n @if (!isLoading && queries.length > 0) {\n <div class=\"category-tree\">\n @for (node of categoryTree; track trackByCategory($index, node)) {\n <ng-container *ngTemplateOutlet=\"categoryNode; context: { node: node }\"></ng-container>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Resize Handle -->\n <div class=\"resize-handle\"\n [class.active]=\"IsResizing\"\n (mousedown)=\"onResizeStart($event)\">\n <div class=\"resize-handle-grip\"></div>\n </div>\n\n <!-- Right Panel: Query Viewer -->\n <div class=\"query-viewer-panel\">\n <!-- No query selected -->\n @if (!selectedQuery) {\n <div class=\"no-selection\">\n <i class=\"fa-solid fa-hand-pointer no-selection-icon\"></i>\n <p class=\"no-selection-message\">Select a query from the list</p>\n <p class=\"no-selection-hint\">Click on a query to view and run it</p>\n </div>\n }\n\n <!-- Query Viewer -->\n @if (selectedQuery) {\n <mj-query-viewer\n [QueryId]=\"selectedQuery.ID\"\n [AutoRun]=\"true\"\n [SelectionMode]=\"'multiple'\"\n (EntityLinkClick)=\"onEntityLinkClick($event)\"\n (RowDoubleClick)=\"onRowDoubleClick($event)\"\n (OpenQueryRecord)=\"onOpenQueryRecord($event)\">\n </mj-query-viewer>\n }\n </div>\n</div>\n\n<!-- Category Node Template -->\n<ng-template #categoryNode let-node=\"node\">\n @if (hasVisibleContent(node)) {\n <div class=\"category-item\"\n [class.expanded]=\"node.expanded\"\n [style.padding-left.px]=\"node.level * 16 + 8\">\n <div class=\"category-header\" (click)=\"toggleExpand(node)\">\n <i class=\"fa-solid expand-icon\"\n [class.fa-chevron-down]=\"node.expanded\"\n [class.fa-chevron-right]=\"!node.expanded\"></i>\n <i class=\"fa-solid fa-folder category-icon\"\n [class.fa-folder-open]=\"node.expanded\"></i>\n <span class=\"category-name\">{{ node.category.Name }}</span>\n <span class=\"category-count\">({{ getNodeQueryCount(node) }})</span>\n </div>\n <!-- Queries in this category -->\n @if (node.expanded) {\n <div class=\"category-queries\">\n @for (query of node.queries; track trackByQuery($index, query)) {\n <div class=\"query-item\"\n [class.selected]=\"IsQuerySelected(query)\"\n [class.hidden]=\"!isQueryVisible(query)\"\n (click)=\"selectQuery(query, $event)\">\n <i class=\"fa-solid fa-file-code query-icon\"></i>\n <div class=\"query-info\">\n <span class=\"query-name\">{{ query.Name }}</span>\n @if (query.Description) {\n <span class=\"query-description\">{{ query.Description }}</span>\n }\n </div>\n @if (query.UsesTemplate) {\n <i class=\"fa-solid fa-sliders param-icon\" title=\"Has parameters\"></i>\n }\n </div>\n }\n </div>\n }\n <!-- Child categories -->\n @if (node.expanded) {\n @for (child of node.children; track trackByCategory($index, child)) {\n <ng-container *ngTemplateOutlet=\"categoryNode; context: { node: child }\"></ng-container>\n }\n }\n </div>\n }\n</ng-template>\n"]}
|
|
1
|
+
{"version":3,"file":"query-browser-resource.component.js","sourceRoot":"","sources":["../../src/QueryBrowser/query-browser-resource.component.ts","../../src/QueryBrowser/query-browser-resource.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ChangeDetectorRef, ChangeDetectionStrategy, ElementRef, NgZone } from '@angular/core';\nimport { Router, NavigationEnd } from '@angular/router';\nimport { Subject } from 'rxjs';\nimport { takeUntil, filter } from 'rxjs/operators';\nimport { RegisterClass , UUIDsEqual } from '@memberjunction/global';\nimport { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';\nimport { Metadata, QueryInfo, QueryCategoryInfo, CompositeKey } from '@memberjunction/core';\nimport { ResourceData, UserInfoEngine } from '@memberjunction/core-entities';\nimport {\n QueryEntityLinkClickEvent,\n QueryRowClickEvent\n} from '@memberjunction/ng-query-viewer';\n/**\n * Tree node for the query category hierarchy\n */\ninterface CategoryNode {\n category: QueryCategoryInfo;\n children: CategoryNode[];\n queries: QueryInfo[];\n expanded: boolean;\n level: number;\n}\n\n/**\n * A resource component for browsing and executing stored queries.\n * Features:\n * - Hierarchical category navigation\n * - Query search\n * - Query viewer with parameter input\n * - Entity linking for clickable record IDs\n */\n@RegisterClass(BaseResourceComponent, 'QueryBrowserResource')\n@Component({\n standalone: false,\n selector: 'mj-query-browser-resource',\n templateUrl: './query-browser-resource.component.html',\n styleUrls: ['./query-browser-resource.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class QueryBrowserResourceComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n private static readonly SETTINGS_KEY = 'QueryBrowser/panelWidth';\n private static readonly STATUS_FILTERS_KEY = 'QueryBrowser/statusFilters';\n private static readonly EXPANDED_STATE_KEY = 'QueryBrowser/expandedCategories';\n private static readonly DEFAULT_PANEL_WIDTH = 320;\n private static readonly MIN_PANEL_WIDTH = 200;\n private static readonly MAX_PANEL_WIDTH = 600;\n\n public isLoading = true;\n public categories: QueryCategoryInfo[] = [];\n public categoryTree: CategoryNode[] = [];\n /** All queries the user has permission to run */\n public queries: QueryInfo[] = [];\n public filteredQueries: QueryInfo[] = [];\n public selectedQuery: QueryInfo | null = null;\n public searchText = '';\n public PanelWidth = QueryBrowserResourceComponent.DEFAULT_PANEL_WIDTH;\n public IsResizing = false;\n\n /** Status filter toggles — which statuses to show in the tree */\n public StatusFilters: Record<string, boolean> = {\n 'Approved': true,\n 'Pending': true,\n 'Rejected': false,\n 'Expired': false\n };\n\n /** Ordered list of all possible statuses for the filter bar */\n public readonly AllStatuses: string[] = ['Approved', 'Pending', 'Rejected', 'Expired'];\n\n /** Tracks expanded state by category ID — persisted across sessions */\n private expandedState = new Map<string, boolean>();\n\n private metadata = new Metadata();\n private destroy$ = new Subject<void>();\n private dataLoaded = false;\n private skipUrlUpdate = true; // Skip URL updates during initialization\n private lastNavigatedUrl = ''; // Track URL to avoid reacting to our own navigation\n\n // Bound event handlers for resize (need references for removeEventListener)\n private boundOnResizeMove = this.onResizeMove.bind(this);\n private boundOnResizeEnd = this.onResizeEnd.bind(this);\n\n constructor(\n private cdr: ChangeDetectorRef,\n private navigationService: NavigationService,\n private router: Router,\n private elementRef: ElementRef,\n private zone: NgZone\n ) {\n super();\n }\n\n ngOnInit(): void {\n this.loadSavedPanelWidth();\n this.loadSavedStatusFilters();\n this.loadSavedExpandedState();\n this.loadData();\n\n // Subscribe to router NavigationEnd events for back/forward button support\n this.router.events\n .pipe(\n filter((event): event is NavigationEnd => event instanceof NavigationEnd),\n takeUntil(this.destroy$)\n )\n .subscribe(event => {\n const currentUrl = event.urlAfterRedirects || event.url;\n if (currentUrl !== this.lastNavigatedUrl && this.dataLoaded) {\n this.onExternalNavigation(currentUrl);\n }\n });\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n // Ensure any pending debounced settings are flushed\n UserInfoEngine.Instance.FlushPendingSettings();\n // Remove resize listeners if active\n document.removeEventListener('mousemove', this.boundOnResizeMove);\n document.removeEventListener('mouseup', this.boundOnResizeEnd);\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n return 'Queries';\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-database';\n }\n\n // ========================================\n // Data Loading\n // ========================================\n\n private async loadData(forceRefresh = false): Promise<void> {\n try {\n this.isLoading = true;\n this.cdr.markForCheck();\n\n // Force re-fetch from server when explicitly refreshing\n if (forceRefresh) {\n await this.metadata.Refresh();\n }\n\n // Load all queries the user has permission to run (regardless of status)\n this.categories = this.metadata.QueryCategories || [];\n this.queries = (this.metadata.Queries || []).filter(q =>\n q.UserCanRun(this.metadata.CurrentUser)\n );\n\n this.applyFilters();\n this.buildCategoryTree();\n\n // Mark data as loaded and apply any query params for deep linking\n this.dataLoaded = true;\n\n // Parse initial URL state\n const urlState = this.parseUrlState();\n if (urlState?.queryId) {\n const query = this.queries.find(q => UUIDsEqual(q.ID, urlState.queryId));\n if (query) {\n this.selectedQuery = query;\n this.expandCategoryForQuery(query);\n }\n }\n\n // Enable URL updates after initialization\n this.skipUrlUpdate = false;\n\n } catch (error) {\n console.error('Error loading queries:', error);\n } finally {\n this.isLoading = false;\n this.NotifyLoadComplete();\n this.cdr.markForCheck();\n }\n }\n\n private buildCategoryTree(): void {\n const categoryMap = new Map<string, CategoryNode>();\n\n // Use filtered queries (status + search filters applied)\n const visibleQueries = this.filteredQueries;\n\n // Create nodes for all categories, restoring expanded state\n for (const category of this.categories) {\n const queriesInCategory = visibleQueries.filter(q => UUIDsEqual(q.CategoryID, category.ID));\n categoryMap.set(category.ID, {\n category,\n children: [],\n queries: queriesInCategory,\n expanded: this.expandedState.get(category.ID) ?? false,\n level: 0\n });\n }\n\n // Build tree structure\n const roots: CategoryNode[] = [];\n for (const category of this.categories) {\n const node = categoryMap.get(category.ID)!;\n if (category.ParentID) {\n const parent = categoryMap.get(category.ParentID);\n if (parent) {\n node.level = parent.level + 1;\n parent.children.push(node);\n } else {\n roots.push(node);\n }\n } else {\n roots.push(node);\n }\n }\n\n // Add uncategorized queries to a virtual root\n const uncategorizedQueries = visibleQueries.filter(q => !q.CategoryID);\n if (uncategorizedQueries.length > 0) {\n const uncategorizedCategory = new QueryCategoryInfo({\n ID: '__uncategorized__',\n Name: 'Uncategorized',\n Description: 'Queries without a category'\n });\n roots.push({\n category: uncategorizedCategory,\n children: [],\n queries: uncategorizedQueries,\n expanded: this.expandedState.get('__uncategorized__') ?? false,\n level: 0\n });\n }\n\n // Sort children recursively\n const sortNodes = (nodes: CategoryNode[]): void => {\n nodes.sort((a, b) => a.category.Name.localeCompare(b.category.Name));\n for (const node of nodes) {\n node.queries.sort((a, b) => a.Name.localeCompare(b.Name));\n sortNodes(node.children);\n }\n };\n sortNodes(roots);\n\n this.categoryTree = roots;\n }\n\n // ========================================\n // Search\n // ========================================\n\n public onSearchChange(value: string): void {\n this.searchText = value;\n this.applyFilters();\n this.buildCategoryTree();\n\n // Expand all categories when searching so results are visible\n if (value) {\n this.expandAll();\n }\n\n this.cdr.markForCheck();\n }\n\n public clearSearch(): void {\n this.searchText = '';\n this.applyFilters();\n this.buildCategoryTree();\n this.cdr.markForCheck();\n }\n\n // ========================================\n // Status Filters\n // ========================================\n\n /** Toggle a status filter on/off and rebuild the tree */\n public toggleStatusFilter(status: string): void {\n this.StatusFilters[status] = !this.StatusFilters[status];\n this.applyFilters();\n this.buildCategoryTree();\n this.saveStatusFilters();\n this.cdr.markForCheck();\n }\n\n /** Get the count of queries with a given status */\n public getStatusCount(status: string): number {\n return this.queries.filter(q => q.Status === status).length;\n }\n\n /** Get the CSS color for a query status */\n public getStatusColor(status: string): string {\n switch (status) {\n case 'Approved': return '#28a745';\n case 'Pending': return '#f59e0b';\n case 'Rejected': return '#dc3545';\n case 'Expired': return '#6c757d';\n default: return '#6c757d';\n }\n }\n\n /** Get the Font Awesome icon for a query status */\n public getStatusIcon(status: string): string {\n switch (status) {\n case 'Approved': return 'fa-check-circle';\n case 'Pending': return 'fa-clock';\n case 'Rejected': return 'fa-times-circle';\n case 'Expired': return 'fa-archive';\n default: return 'fa-question-circle';\n }\n }\n\n /** Apply both status and search filters to produce filteredQueries */\n private applyFilters(): void {\n // First filter by status\n let result = this.queries.filter(q => this.StatusFilters[q.Status] === true);\n\n // Then filter by search text\n if (this.searchText.trim()) {\n const searchLower = this.searchText.toLowerCase();\n result = result.filter(q =>\n q.Name.toLowerCase().includes(searchLower) ||\n q.Description?.toLowerCase().includes(searchLower) ||\n q.Category?.toLowerCase().includes(searchLower)\n );\n }\n\n this.filteredQueries = result;\n }\n\n /** Load saved status filter preferences */\n private loadSavedStatusFilters(): void {\n const saved = UserInfoEngine.Instance.GetSetting(QueryBrowserResourceComponent.STATUS_FILTERS_KEY);\n if (saved) {\n try {\n const parsed = JSON.parse(saved);\n // Merge saved values onto defaults (preserves any new statuses added later)\n for (const key of Object.keys(this.StatusFilters)) {\n if (typeof parsed[key] === 'boolean') {\n this.StatusFilters[key] = parsed[key];\n }\n }\n } catch {\n // Ignore invalid JSON, keep defaults\n }\n }\n }\n\n /** Save status filter preferences with debouncing */\n private saveStatusFilters(): void {\n UserInfoEngine.Instance.SetSettingDebounced(\n QueryBrowserResourceComponent.STATUS_FILTERS_KEY,\n JSON.stringify(this.StatusFilters)\n );\n }\n\n /** Load saved expanded/collapsed state for category nodes */\n private loadSavedExpandedState(): void {\n const saved = UserInfoEngine.Instance.GetSetting(QueryBrowserResourceComponent.EXPANDED_STATE_KEY);\n if (saved) {\n try {\n const parsed: Record<string, boolean> = JSON.parse(saved);\n for (const [key, value] of Object.entries(parsed)) {\n if (typeof value === 'boolean') {\n this.expandedState.set(key, value);\n }\n }\n } catch {\n // Ignore invalid JSON, start fresh\n }\n }\n }\n\n /** Save expanded/collapsed state with debouncing */\n private saveExpandedState(): void {\n const obj: Record<string, boolean> = {};\n for (const [key, value] of this.expandedState.entries()) {\n obj[key] = value;\n }\n UserInfoEngine.Instance.SetSettingDebounced(\n QueryBrowserResourceComponent.EXPANDED_STATE_KEY,\n JSON.stringify(obj)\n );\n }\n\n // ========================================\n // Tree Navigation\n // ========================================\n\n public toggleExpand(node: CategoryNode, event?: Event): void {\n if (event) {\n event.stopPropagation();\n }\n node.expanded = !node.expanded;\n this.expandedState.set(node.category.ID, node.expanded);\n this.saveExpandedState();\n this.cdr.markForCheck();\n }\n\n public expandAll(): void {\n const expand = (nodes: CategoryNode[]): void => {\n for (const node of nodes) {\n node.expanded = true;\n this.expandedState.set(node.category.ID, true);\n expand(node.children);\n }\n };\n expand(this.categoryTree);\n this.saveExpandedState();\n this.cdr.markForCheck();\n }\n\n public collapseAll(): void {\n const collapse = (nodes: CategoryNode[]): void => {\n for (const node of nodes) {\n node.expanded = false;\n this.expandedState.set(node.category.ID, false);\n collapse(node.children);\n }\n };\n collapse(this.categoryTree);\n this.saveExpandedState();\n this.cdr.markForCheck();\n }\n\n public selectQuery(query: QueryInfo, event?: Event): void {\n if (event) {\n event.stopPropagation();\n }\n this.selectedQuery = query;\n this.updateUrl();\n this.cdr.markForCheck();\n }\n\n public isQueryVisible(query: QueryInfo): boolean {\n if (!this.searchText) return true;\n return this.filteredQueries.some(q => UUIDsEqual(q.ID, query.ID));\n }\n\n public hasVisibleContent(node: CategoryNode): boolean {\n if (!this.searchText) return true;\n\n // Check if any queries in this category match\n if (node.queries.some(q => this.isQueryVisible(q))) {\n return true;\n }\n\n // Check if any child categories have visible content\n return node.children.some(child => this.hasVisibleContent(child));\n }\n\n // ========================================\n // Query Viewer Events\n // ========================================\n\n public onEntityLinkClick(event: QueryEntityLinkClickEvent): void {\n // Look up the entity's actual primary key field name from metadata\n const md = new Metadata();\n const entity = md.Entities.find(e => e.Name === event.entityName);\n const pkField = entity?.FirstPrimaryKey;\n const pkFieldName = pkField?.Name || 'ID';\n\n const compositeKey = new CompositeKey([{ FieldName: pkFieldName, Value: event.recordId }]);\n this.navigationService.OpenEntityRecord(event.entityName, compositeKey);\n }\n\n public onRowDoubleClick(event: QueryRowClickEvent): void {\n // Could show record details or other action\n }\n\n public onOpenQueryRecord(event: { queryId: string; queryName: string }): void {\n // Open the Query entity record using navigation service\n const compositeKey = CompositeKey.FromID(event.queryId);\n this.navigationService.OpenEntityRecord('MJ: Queries', compositeKey);\n }\n\n public openQueryDetails(query: QueryInfo, event: Event): void {\n // Stop propagation so clicking the button doesn't also select the query\n event.stopPropagation();\n // Open the Query entity record\n const compositeKey = CompositeKey.FromID(query.ID);\n this.navigationService.OpenEntityRecord('MJ: Queries', compositeKey);\n }\n\n // ========================================\n // Utilities\n // ========================================\n\n public getTotalQueryCount(): number {\n return this.queries.length;\n }\n\n public getNodeQueryCount(node: CategoryNode): number {\n let count = node.queries.length;\n for (const child of node.children) {\n count += this.getNodeQueryCount(child);\n }\n return count;\n }\n\n public refresh(): void {\n this.selectedQuery = null;\n this.loadData(true);\n }\n\n public trackByCategory(index: number, node: CategoryNode): string {\n return node.category.ID;\n }\n\n public trackByQuery(index: number, query: QueryInfo): string {\n return query.ID;\n }\n\n // ========================================\n // Deep Linking\n // ========================================\n\n /**\n * Parse URL query string for query state.\n * Query params: queryId\n */\n private parseUrlState(): { queryId?: string } | null {\n const url = this.router.url;\n const queryIndex = url.indexOf('?');\n if (queryIndex === -1) return null;\n\n const queryString = url.substring(queryIndex + 1);\n const params = new URLSearchParams(queryString);\n const queryId = params.get('queryId');\n\n if (!queryId) return null;\n\n return { queryId };\n }\n\n /**\n * Update URL query string to reflect current state.\n * Uses NavigationService for proper URL management that respects app-scoped routes.\n */\n private updateUrl(): void {\n if (this.skipUrlUpdate) return;\n\n const queryParams: Record<string, string | null> = {};\n\n // Add query ID if selected, null to remove\n if (this.selectedQuery?.ID) {\n queryParams['queryId'] = this.selectedQuery.ID;\n } else {\n queryParams['queryId'] = null;\n }\n\n // Use NavigationService to update query params properly\n this.navigationService.UpdateActiveTabQueryParams(queryParams);\n }\n\n /**\n * Handle external navigation (back/forward buttons).\n * Parses the URL and applies the state without triggering a new navigation.\n */\n private onExternalNavigation(url: string): void {\n // Check if this URL is for our component (contains our base path)\n const currentPath = this.router.url.split('?')[0];\n const newPath = url.split('?')[0];\n\n // Only handle if we're still on the same base path (same component instance)\n if (currentPath !== newPath) {\n return; // Different route entirely, shell will handle it\n }\n\n // Parse the new URL state\n const urlState = this.parseUrlFromString(url);\n\n // Apply the state without triggering URL updates\n this.skipUrlUpdate = true;\n if (urlState?.queryId) {\n const query = this.queries.find(q => UUIDsEqual(q.ID, urlState.queryId));\n if (query) {\n if (!UUIDsEqual(this.selectedQuery?.ID, query.ID)) {\n this.selectedQuery = query;\n this.expandCategoryForQuery(query);\n }\n }\n } else {\n // No queryId means clear selection\n this.selectedQuery = null;\n }\n this.skipUrlUpdate = false;\n\n // Update the tracked URL\n this.lastNavigatedUrl = url;\n\n this.cdr.markForCheck();\n }\n\n /**\n * Parse URL state from a URL string (used for external navigation).\n */\n private parseUrlFromString(url: string): { queryId?: string } | null {\n const queryIndex = url.indexOf('?');\n if (queryIndex === -1) return null;\n\n const queryString = url.substring(queryIndex + 1);\n const params = new URLSearchParams(queryString);\n const queryId = params.get('queryId');\n\n if (!queryId) return null;\n\n return { queryId };\n }\n\n /**\n * Expands the category tree to show the given query\n */\n private expandCategoryForQuery(query: QueryInfo): void {\n if (!query.CategoryID) return;\n\n const expandToTarget = (nodes: CategoryNode[], targetCategoryId: string): boolean => {\n for (const node of nodes) {\n if (UUIDsEqual(node.category.ID, targetCategoryId)) {\n node.expanded = true;\n this.expandedState.set(node.category.ID, true);\n return true;\n }\n if (expandToTarget(node.children, targetCategoryId)) {\n node.expanded = true;\n this.expandedState.set(node.category.ID, true);\n return true;\n }\n }\n return false;\n };\n\n if (expandToTarget(this.categoryTree, query.CategoryID)) {\n this.saveExpandedState();\n }\n }\n\n // ========================================\n // Panel Resize\n // ========================================\n\n /**\n * Load saved panel width from user settings\n */\n private loadSavedPanelWidth(): void {\n const saved = UserInfoEngine.Instance.GetSetting(QueryBrowserResourceComponent.SETTINGS_KEY);\n if (saved) {\n const width = parseInt(saved, 10);\n if (!isNaN(width) && width >= QueryBrowserResourceComponent.MIN_PANEL_WIDTH && width <= QueryBrowserResourceComponent.MAX_PANEL_WIDTH) {\n this.PanelWidth = width;\n }\n }\n }\n\n /**\n * Start resizing the left panel via drag handle\n */\n public onResizeStart(event: MouseEvent): void {\n event.preventDefault();\n this.IsResizing = true;\n this.cdr.markForCheck();\n\n // Run outside Angular zone for performance during mousemove\n this.zone.runOutsideAngular(() => {\n document.addEventListener('mousemove', this.boundOnResizeMove);\n document.addEventListener('mouseup', this.boundOnResizeEnd);\n });\n }\n\n private onResizeMove(event: MouseEvent): void {\n if (!this.IsResizing) return;\n\n const containerRect = this.elementRef.nativeElement.querySelector('.query-browser-container')?.getBoundingClientRect();\n if (!containerRect) return;\n\n const newWidth = event.clientX - containerRect.left;\n const clamped = Math.max(\n QueryBrowserResourceComponent.MIN_PANEL_WIDTH,\n Math.min(QueryBrowserResourceComponent.MAX_PANEL_WIDTH, newWidth)\n );\n\n this.PanelWidth = clamped;\n this.zone.run(() => this.cdr.markForCheck());\n }\n\n private onResizeEnd(): void {\n if (!this.IsResizing) return;\n this.IsResizing = false;\n\n document.removeEventListener('mousemove', this.boundOnResizeMove);\n document.removeEventListener('mouseup', this.boundOnResizeEnd);\n\n // Persist width with debouncing\n UserInfoEngine.Instance.SetSettingDebounced(\n QueryBrowserResourceComponent.SETTINGS_KEY,\n this.PanelWidth.toString()\n );\n\n this.zone.run(() => this.cdr.markForCheck());\n }\n\n /** Case-insensitive UUID check whether a query is the currently selected query. */\n public IsQuerySelected(query: QueryInfo): boolean {\n return UUIDsEqual(this.selectedQuery?.ID, query.ID);\n }\n}\n","<!-- Query Browser Resource -->\n<div class=\"query-browser-container\" [class.resizing]=\"IsResizing\">\n <!-- Left Panel: Query Tree -->\n <div class=\"query-tree-panel\" [style.width.px]=\"PanelWidth\">\n <!-- Header -->\n <div class=\"tree-header\">\n <div class=\"header-title\">\n <i class=\"fa-solid fa-database\"></i>\n <span>Queries</span>\n <span class=\"query-count\">({{ getTotalQueryCount() }})</span>\n </div>\n <div class=\"header-actions\">\n <button class=\"icon-btn\" (click)=\"expandAll()\" title=\"Expand all\">\n <i class=\"fa-solid fa-folder-open\"></i>\n </button>\n <button class=\"icon-btn\" (click)=\"collapseAll()\" title=\"Collapse all\">\n <i class=\"fa-solid fa-folder\"></i>\n </button>\n <button class=\"icon-btn\" (click)=\"refresh()\" title=\"Refresh\">\n <i class=\"fa-solid fa-refresh\"></i>\n </button>\n </div>\n </div>\n\n <!-- Search -->\n <div class=\"tree-search\">\n <div class=\"search-input-wrapper\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input type=\"text\"\n class=\"search-input\"\n [value]=\"searchText\"\n placeholder=\"Search queries...\"\n (input)=\"onSearchChange($any($event.target).value)\">\n @if (searchText) {\n <button class=\"clear-btn\" (click)=\"clearSearch()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n </div>\n\n <!-- Status Filters -->\n <div class=\"status-filter-bar\">\n @for (status of AllStatuses; track status) {\n @if (getStatusCount(status) > 0) {\n <button class=\"status-filter-chip\"\n [class.active]=\"StatusFilters[status]\"\n [style.--chip-color]=\"getStatusColor(status)\"\n (click)=\"toggleStatusFilter(status)\"\n [title]=\"(StatusFilters[status] ? 'Hide' : 'Show') + ' ' + status + ' queries'\">\n <i class=\"fa-solid\" [class]=\"getStatusIcon(status)\"></i>\n <span>{{ status }}</span>\n <span class=\"chip-count\">{{ getStatusCount(status) }}</span>\n </button>\n }\n }\n </div>\n\n <!-- Tree Content -->\n <div class=\"tree-content\">\n <!-- Loading -->\n @if (isLoading) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading queries...\"></mj-loading>\n </div>\n }\n\n <!-- Empty -->\n @if (!isLoading && queries.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-database empty-icon\"></i>\n <p>No queries available</p>\n </div>\n }\n\n <!-- No results -->\n @if (!isLoading && searchText && filteredQueries.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-search empty-icon\"></i>\n <p>No queries match \"{{ searchText }}\"</p>\n </div>\n }\n\n <!-- Category Tree -->\n @if (!isLoading && queries.length > 0) {\n <div class=\"category-tree\">\n @for (node of categoryTree; track trackByCategory($index, node)) {\n <ng-container *ngTemplateOutlet=\"categoryNode; context: { node: node }\"></ng-container>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Resize Handle -->\n <div class=\"resize-handle\"\n [class.active]=\"IsResizing\"\n (mousedown)=\"onResizeStart($event)\">\n <div class=\"resize-handle-grip\"></div>\n </div>\n\n <!-- Right Panel: Query Viewer -->\n <div class=\"query-viewer-panel\">\n <!-- No query selected -->\n @if (!selectedQuery) {\n <div class=\"no-selection\">\n <i class=\"fa-solid fa-hand-pointer no-selection-icon\"></i>\n <p class=\"no-selection-message\">Select a query from the list</p>\n <p class=\"no-selection-hint\">Click on a query to view and run it</p>\n </div>\n }\n\n <!-- Query Viewer -->\n @if (selectedQuery) {\n <!-- Query Header with Status -->\n <div class=\"query-viewer-header\">\n <div class=\"query-viewer-title\">\n <i class=\"fa-solid fa-file-code\"></i>\n <span>{{ selectedQuery.Name }}</span>\n </div>\n @if (selectedQuery.Status !== 'Approved') {\n <span class=\"query-viewer-status-pill\"\n [style.background]=\"getStatusColor(selectedQuery.Status)\">\n <i class=\"fa-solid\" [class]=\"getStatusIcon(selectedQuery.Status)\"></i>\n {{ selectedQuery.Status }}\n </span>\n } @else {\n <span class=\"query-viewer-status-pill approved\"\n [style.background]=\"getStatusColor('Approved')\">\n <i class=\"fa-solid fa-check-circle\"></i>\n Approved\n </span>\n }\n </div>\n <mj-query-viewer\n [QueryId]=\"selectedQuery.ID\"\n [AutoRun]=\"true\"\n [SelectionMode]=\"'multiple'\"\n (EntityLinkClick)=\"onEntityLinkClick($event)\"\n (RowDoubleClick)=\"onRowDoubleClick($event)\"\n (OpenQueryRecord)=\"onOpenQueryRecord($event)\">\n </mj-query-viewer>\n }\n </div>\n</div>\n\n<!-- Category Node Template -->\n<ng-template #categoryNode let-node=\"node\">\n @if (hasVisibleContent(node)) {\n <div class=\"category-item\"\n [class.expanded]=\"node.expanded\"\n [style.padding-left.px]=\"node.level * 16 + 8\">\n <div class=\"category-header\" (click)=\"toggleExpand(node)\">\n <i class=\"fa-solid expand-icon\"\n [class.fa-chevron-down]=\"node.expanded\"\n [class.fa-chevron-right]=\"!node.expanded\"></i>\n <i class=\"fa-solid fa-folder category-icon\"\n [class.fa-folder-open]=\"node.expanded\"></i>\n <span class=\"category-name\">{{ node.category.Name }}</span>\n <span class=\"category-count\">({{ getNodeQueryCount(node) }})</span>\n </div>\n <!-- Queries in this category -->\n @if (node.expanded) {\n <div class=\"category-queries\">\n @for (query of node.queries; track trackByQuery($index, query)) {\n <div class=\"query-item\"\n [class.selected]=\"IsQuerySelected(query)\"\n [class.hidden]=\"!isQueryVisible(query)\"\n (click)=\"selectQuery(query, $event)\">\n <span class=\"status-dot\"\n [style.background]=\"getStatusColor(query.Status)\"\n [title]=\"query.Status\"></span>\n <i class=\"fa-solid fa-file-code query-icon\"></i>\n <div class=\"query-info\" [title]=\"query.Description || query.Name\">\n <span class=\"query-name\">{{ query.Name }}</span>\n @if (query.Description) {\n <span class=\"query-description\">{{ query.Description }}</span>\n }\n </div>\n @if (query.UsesTemplate) {\n <i class=\"fa-solid fa-sliders param-icon\" title=\"Has parameters\"></i>\n }\n @if (query.Status !== 'Approved') {\n <span class=\"query-status-badge\"\n [style.background]=\"getStatusColor(query.Status)\"\n [title]=\"query.Status\">\n {{ query.Status }}\n </span>\n }\n </div>\n }\n </div>\n }\n <!-- Child categories -->\n @if (node.expanded) {\n @for (child of node.children; track trackByCategory($index, child)) {\n <ng-container *ngTemplateOutlet=\"categoryNode; context: { node: child }\"></ng-container>\n }\n }\n </div>\n }\n</ng-template>\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration-data-service.test.js","sourceRoot":"","sources":["../../src/__tests__/integration-data-service.test.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAyC,MAAM,kDAAkD,CAAC;AAEjI,SAAS,aAAa;IACpB,OAAO,IAAI,sBAAsB,EAAE,CAAC;AACtC,CAAC;AAED,SAAS,aAAa,CAAC,YAAyC,EAAE;IAChE,OAAO;QACL,WAAW,EAAE;YACX,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI;YACtD,gBAAgB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ;YAC/D,WAAW,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI;SAC3C;QACD,UAAU,EAAE,IAAI;QAChB,SAAS,EAAE,IAAI;QACf,UAAU,EAAE,EAAE;QACd,WAAW,EAAE,MAAM;QACnB,YAAY,EAAE,WAAW;QACzB,uBAAuB,EAAE,CAAC;QAC1B,WAAW,EAAE,CAAC;QACd,UAAU,EAAE,IAAI;QAChB,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,YAAwC,EAAE;IAC3D,OAAO;QACL,EAAE,EAAE,GAAG,EAAE,oBAAoB,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI;QAClE,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI;QAClD,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO;QAC1D,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;QAC3B,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YACjC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACvC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,QAAQ,EAAE,CAAC;QAChD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;YAC5B,MAAM,SAAS,GAAG,CAAC,aAAa,EAAE,EAAE,aAAa,EAAE,EAAE,aAAa,EAAE,CAAC,CAAC;YACtE,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;YAC7D,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;YAC5B,MAAM,SAAS,GAAG;gBAChB,aAAa,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC;gBAClE,aAAa,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;gBAC9D,aAAa,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;aAC/D,CAAC;YACF,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;YAC5B,MAAM,SAAS,GAAG;gBAChB,aAAa,CAAC,EAAE,uBAAuB,EAAE,GAAG,EAAE,CAAC;gBAC/C,aAAa,CAAC,EAAE,uBAAuB,EAAE,GAAG,EAAE,CAAC;aAChD,CAAC;YACF,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;YAClE,MAAM,SAAS,GAAG;gBAChB,aAAa,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;aACpD,CAAC;YACF,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;YAC5B,MAAM,SAAS,GAAG;gBAChB,aAAa,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;gBACnC,aAAa,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;gBACnC,aAAa,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;aACpC,CAAC;YACF,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;YACnC,MAAM,CAAC,aAAa,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;YAC/B,MAAM,CAAC,aAAa,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;YAC3C,MAAM,CAAC,aAAa,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,CAAC,aAAa,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;YACpC,MAAM,CAAC,aAAa,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;QACnC,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;YAC5C,MAAM,CAAC,aAAa,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACtE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACrC,MAAM,CAAC,aAAa,EAAE,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;YAC/C,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;YACtE,MAAM,CAAC,aAAa,EAAE,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;YAC3C,MAAM,aAAa,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;YAC9E,MAAM,CAAC,aAAa,EAAE,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;YAChF,MAAM,CAAC,aAAa,EAAE,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["/**\n * Tests for IntegrationDataService\n * Covers pure logic methods (KPI computation, formatting, status calculation)\n */\nimport { describe, it, expect } from 'vitest';\nimport { IntegrationDataService, IntegrationSummary, IntegrationRunRow } from '../Integration/services/integration-data.service';\n\nfunction createService(): IntegrationDataService {\n return new IntegrationDataService();\n}\n\nfunction createSummary(overrides: Partial<IntegrationSummary> = {}): IntegrationSummary {\n return {\n Integration: {\n ID: '1', Name: 'Test', IsActive: true, LastRunID: null,\n LastRunStartedAt: null, LastRunEndedAt: null, Company: 'TestCo',\n Integration: 'Test', DriverClassName: null\n },\n SourceType: null,\n LatestRun: null,\n RecentRuns: [],\n StatusColor: 'gray',\n RelativeTime: 'Never run',\n TotalRecordsSyncedToday: 0,\n TotalErrors: 0,\n DurationMs: null,\n ...overrides\n };\n}\n\nfunction createRun(overrides: Partial<IntegrationRunRow> = {}): IntegrationRunRow {\n return {\n ID: '1', CompanyIntegrationID: '1', StartedAt: null, EndedAt: null,\n TotalRecords: 0, Status: 'Success', ErrorLog: null,\n Integration: 'Test', Company: 'TestCo', RunByUser: 'Admin',\n ...overrides\n };\n}\n\ndescribe('IntegrationDataService', () => {\n describe('ComputeKPIs', () => {\n it('should return zeros for empty summaries', () => {\n const svc = createService();\n const kpis = svc.ComputeKPIs([]);\n expect(kpis.TotalIntegrations).toBe(0);\n expect(kpis.ActiveSyncs).toBe(0);\n expect(kpis.RecordsSyncedToday).toBe(0);\n expect(kpis.ErrorRate).toBe(0);\n expect(kpis.AverageSyncDurationMs).toBeNull();\n });\n\n it('should count total integrations', () => {\n const svc = createService();\n const summaries = [createSummary(), createSummary(), createSummary()];\n const kpis = svc.ComputeKPIs(summaries);\n expect(kpis.TotalIntegrations).toBe(3);\n });\n\n it('should count active syncs (In Progress and Pending)', () => {\n const svc = createService();\n const summaries = [\n createSummary({ LatestRun: createRun({ Status: 'In Progress' }) }),\n createSummary({ LatestRun: createRun({ Status: 'Pending' }) }),\n createSummary({ LatestRun: createRun({ Status: 'Success' }) }),\n ];\n const kpis = svc.ComputeKPIs(summaries);\n expect(kpis.ActiveSyncs).toBe(2);\n });\n\n it('should sum records synced today', () => {\n const svc = createService();\n const summaries = [\n createSummary({ TotalRecordsSyncedToday: 100 }),\n createSummary({ TotalRecordsSyncedToday: 250 }),\n ];\n const kpis = svc.ComputeKPIs(summaries);\n expect(kpis.RecordsSyncedToday).toBe(350);\n });\n\n it('should compute error rate from recent runs', () => {\n const svc = createService();\n const runs = [createRun(), createRun(), createRun(), createRun()];\n const summaries = [\n createSummary({ RecentRuns: runs, TotalErrors: 1 }),\n ];\n const kpis = svc.ComputeKPIs(summaries);\n expect(kpis.ErrorRate).toBe(25);\n });\n\n it('should compute average sync duration', () => {\n const svc = createService();\n const summaries = [\n createSummary({ DurationMs: 1000 }),\n createSummary({ DurationMs: 3000 }),\n createSummary({ DurationMs: null }),\n ];\n const kpis = svc.ComputeKPIs(summaries);\n expect(kpis.AverageSyncDurationMs).toBe(2000);\n });\n });\n\n describe('FormatDuration', () => {\n it('should return -- for null', () => {\n expect(createService().FormatDuration(null)).toBe('--');\n });\n\n it('should format seconds', () => {\n expect(createService().FormatDuration(45000)).toBe('45s');\n });\n\n it('should format minutes and seconds', () => {\n expect(createService().FormatDuration(125000)).toBe('2m 5s');\n });\n\n it('should format hours and minutes', () => {\n expect(createService().FormatDuration(3720000)).toBe('1h 2m');\n });\n\n it('should format zero seconds', () => {\n expect(createService().FormatDuration(0)).toBe('0s');\n });\n });\n\n describe('ComputeRelativeTime', () => {\n it('should return \"Never run\" for null', () => {\n expect(createService().ComputeRelativeTime(null)).toBe('Never run');\n });\n\n it('should return \"Just now\" for recent dates', () => {\n const now = new Date().toISOString();\n expect(createService().ComputeRelativeTime(now)).toBe('Just now');\n });\n\n it('should return minutes for recent past', () => {\n const fiveMinAgo = new Date(Date.now() - 5 * 60 * 1000).toISOString();\n expect(createService().ComputeRelativeTime(fiveMinAgo)).toBe('5m ago');\n });\n\n it('should return hours for hours ago', () => {\n const threeHoursAgo = new Date(Date.now() - 3 * 60 * 60 * 1000).toISOString();\n expect(createService().ComputeRelativeTime(threeHoursAgo)).toBe('3h ago');\n });\n\n it('should return days for days ago', () => {\n const twoDaysAgo = new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString();\n expect(createService().ComputeRelativeTime(twoDaysAgo)).toBe('2d ago');\n });\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"integration-data-service.test.js","sourceRoot":"","sources":["../../src/__tests__/integration-data-service.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tests for IntegrationDataService\n * Covers pure logic methods (KPI computation, formatting, status calculation)\n */\nimport { describe, it, expect } from 'vitest';\nimport { IntegrationDataService, IntegrationSummary, IntegrationRunRow } from '../Integration/services/integration-data.service';\nimport { MJCompanyIntegrationEntity } from '@memberjunction/core-entities';\n\nfunction createService(): IntegrationDataService {\n return new IntegrationDataService();\n}\n\nfunction createSummary(overrides: Partial<IntegrationSummary> = {}): IntegrationSummary {\n return {\n Integration: {\n ID: '1', Name: 'Test', IsActive: true, LastRunID: null,\n LastRunStartedAt: null, LastRunEndedAt: null, Company: 'TestCo',\n Integration: 'Test', DriverClassName: null\n } as unknown as MJCompanyIntegrationEntity,\n SourceType: null,\n LatestRun: null,\n RecentRuns: [],\n StatusColor: 'gray',\n RelativeTime: 'Never run',\n TotalRecordsSyncedToday: 0,\n TotalErrors: 0,\n DurationMs: null,\n ...overrides\n };\n}\n\nfunction createRun(overrides: Partial<IntegrationRunRow> = {}): IntegrationRunRow {\n return {\n ID: '1', CompanyIntegrationID: '1', StartedAt: null, EndedAt: null,\n TotalRecords: 0, Status: 'Success', ErrorLog: null,\n Integration: 'Test', Company: 'TestCo', RunByUser: 'Admin',\n ...overrides\n };\n}\n\ndescribe('IntegrationDataService', () => {\n describe('ComputeKPIs', () => {\n it('should return zeros for empty summaries', () => {\n const svc = createService();\n const kpis = svc.ComputeKPIs([]);\n expect(kpis.TotalIntegrations).toBe(0);\n expect(kpis.ActiveSyncs).toBe(0);\n expect(kpis.RecordsSyncedToday).toBe(0);\n expect(kpis.ErrorRate).toBe(0);\n expect(kpis.AverageSyncDurationMs).toBeNull();\n });\n\n it('should count total integrations', () => {\n const svc = createService();\n const summaries = [createSummary(), createSummary(), createSummary()];\n const kpis = svc.ComputeKPIs(summaries);\n expect(kpis.TotalIntegrations).toBe(3);\n });\n\n it('should count active syncs (In Progress and Pending)', () => {\n const svc = createService();\n const summaries = [\n createSummary({ LatestRun: createRun({ Status: 'In Progress' }) }),\n createSummary({ LatestRun: createRun({ Status: 'Pending' }) }),\n createSummary({ LatestRun: createRun({ Status: 'Success' }) }),\n ];\n const kpis = svc.ComputeKPIs(summaries);\n expect(kpis.ActiveSyncs).toBe(2);\n });\n\n it('should sum records synced today', () => {\n const svc = createService();\n const summaries = [\n createSummary({ TotalRecordsSyncedToday: 100 }),\n createSummary({ TotalRecordsSyncedToday: 250 }),\n ];\n const kpis = svc.ComputeKPIs(summaries);\n expect(kpis.RecordsSyncedToday).toBe(350);\n });\n\n it('should compute error rate from recent runs', () => {\n const svc = createService();\n const runs = [createRun(), createRun(), createRun(), createRun()];\n const summaries = [\n createSummary({ RecentRuns: runs, TotalErrors: 1 }),\n ];\n const kpis = svc.ComputeKPIs(summaries);\n expect(kpis.ErrorRate).toBe(25);\n });\n\n it('should compute average sync duration', () => {\n const svc = createService();\n const summaries = [\n createSummary({ DurationMs: 1000 }),\n createSummary({ DurationMs: 3000 }),\n createSummary({ DurationMs: null }),\n ];\n const kpis = svc.ComputeKPIs(summaries);\n expect(kpis.AverageSyncDurationMs).toBe(2000);\n });\n });\n\n describe('FormatDuration', () => {\n it('should return -- for null', () => {\n expect(createService().FormatDuration(null)).toBe('--');\n });\n\n it('should format seconds', () => {\n expect(createService().FormatDuration(45000)).toBe('45s');\n });\n\n it('should format minutes and seconds', () => {\n expect(createService().FormatDuration(125000)).toBe('2m 5s');\n });\n\n it('should format hours and minutes', () => {\n expect(createService().FormatDuration(3720000)).toBe('1h 2m');\n });\n\n it('should format zero seconds', () => {\n expect(createService().FormatDuration(0)).toBe('0s');\n });\n });\n\n describe('ComputeRelativeTime', () => {\n it('should return \"Never run\" for null', () => {\n expect(createService().ComputeRelativeTime(null)).toBe('Never run');\n });\n\n it('should return \"Just now\" for recent dates', () => {\n const now = new Date().toISOString();\n expect(createService().ComputeRelativeTime(now)).toBe('Just now');\n });\n\n it('should return minutes for recent past', () => {\n const fiveMinAgo = new Date(Date.now() - 5 * 60 * 1000).toISOString();\n expect(createService().ComputeRelativeTime(fiveMinAgo)).toBe('5m ago');\n });\n\n it('should return hours for hours ago', () => {\n const threeHoursAgo = new Date(Date.now() - 3 * 60 * 60 * 1000).toISOString();\n expect(createService().ComputeRelativeTime(threeHoursAgo)).toBe('3h ago');\n });\n\n it('should return days for days ago', () => {\n const twoDaysAgo = new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString();\n expect(createService().ComputeRelativeTime(twoDaysAgo)).toBe('2d ago');\n });\n });\n});\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapping-validation.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/mapping-validation.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for MappingWorkspace validation logic
|
|
3
|
+
* Covers: UnmappedRequiredCount, HasKeyField, MappingValidation, ActiveEditableFields
|
|
4
|
+
* Tests pure logic extracted from the component's computed properties.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect } from 'vitest';
|
|
7
|
+
function createField(overrides = {}) {
|
|
8
|
+
return {
|
|
9
|
+
ID: 'fm-1',
|
|
10
|
+
SourceFieldName: 'source_field',
|
|
11
|
+
SourceFieldLabel: 'Source Field',
|
|
12
|
+
SourceFieldType: 'string',
|
|
13
|
+
DestinationFieldName: 'DestField',
|
|
14
|
+
DestinationFieldLabel: 'Dest Field',
|
|
15
|
+
IsKeyField: false,
|
|
16
|
+
IsRequired: false,
|
|
17
|
+
Direction: 'SourceToDest',
|
|
18
|
+
Status: 'Active',
|
|
19
|
+
IsNew: false,
|
|
20
|
+
IsDirty: false,
|
|
21
|
+
...overrides
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
// Replicates the component's computed properties as pure functions
|
|
25
|
+
function getActiveFields(fields) {
|
|
26
|
+
return fields.filter(f => f.Status !== 'Inactive');
|
|
27
|
+
}
|
|
28
|
+
function getUnmappedRequiredCount(fields) {
|
|
29
|
+
return fields.filter(f => f.Status === 'Active' && f.IsRequired && !f.DestinationFieldName).length;
|
|
30
|
+
}
|
|
31
|
+
function getHasKeyField(fields) {
|
|
32
|
+
return fields.some(f => f.Status === 'Active' && f.IsKeyField);
|
|
33
|
+
}
|
|
34
|
+
function getMappingValidation(fields) {
|
|
35
|
+
const warnings = [];
|
|
36
|
+
const unmappedRequired = getUnmappedRequiredCount(fields);
|
|
37
|
+
if (unmappedRequired > 0) {
|
|
38
|
+
warnings.push(`${unmappedRequired} required field(s) missing destination mapping`);
|
|
39
|
+
}
|
|
40
|
+
const activeFields = getActiveFields(fields);
|
|
41
|
+
if (!getHasKeyField(fields) && activeFields.length > 0) {
|
|
42
|
+
warnings.push('No key field configured — sync may create duplicates');
|
|
43
|
+
}
|
|
44
|
+
return { IsValid: warnings.length === 0, Warnings: warnings };
|
|
45
|
+
}
|
|
46
|
+
describe('MappingWorkspace Validation', () => {
|
|
47
|
+
describe('ActiveEditableFields', () => {
|
|
48
|
+
it('should return only active fields', () => {
|
|
49
|
+
const fields = [
|
|
50
|
+
createField({ Status: 'Active' }),
|
|
51
|
+
createField({ Status: 'Inactive' }),
|
|
52
|
+
createField({ Status: 'Active' }),
|
|
53
|
+
];
|
|
54
|
+
expect(getActiveFields(fields)).toHaveLength(2);
|
|
55
|
+
});
|
|
56
|
+
it('should return empty array when all fields are inactive', () => {
|
|
57
|
+
const fields = [
|
|
58
|
+
createField({ Status: 'Inactive' }),
|
|
59
|
+
createField({ Status: 'Inactive' }),
|
|
60
|
+
];
|
|
61
|
+
expect(getActiveFields(fields)).toHaveLength(0);
|
|
62
|
+
});
|
|
63
|
+
it('should return empty array for no fields', () => {
|
|
64
|
+
expect(getActiveFields([])).toHaveLength(0);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe('UnmappedRequiredCount', () => {
|
|
68
|
+
it('should return 0 when no required fields are unmapped', () => {
|
|
69
|
+
const fields = [
|
|
70
|
+
createField({ IsRequired: true, DestinationFieldName: 'Mapped' }),
|
|
71
|
+
createField({ IsRequired: false, DestinationFieldName: '' }),
|
|
72
|
+
];
|
|
73
|
+
expect(getUnmappedRequiredCount(fields)).toBe(0);
|
|
74
|
+
});
|
|
75
|
+
it('should count required fields with empty destination', () => {
|
|
76
|
+
const fields = [
|
|
77
|
+
createField({ IsRequired: true, DestinationFieldName: '' }),
|
|
78
|
+
createField({ IsRequired: true, DestinationFieldName: '' }),
|
|
79
|
+
createField({ IsRequired: true, DestinationFieldName: 'Name' }),
|
|
80
|
+
];
|
|
81
|
+
expect(getUnmappedRequiredCount(fields)).toBe(2);
|
|
82
|
+
});
|
|
83
|
+
it('should ignore inactive required fields', () => {
|
|
84
|
+
const fields = [
|
|
85
|
+
createField({ IsRequired: true, DestinationFieldName: '', Status: 'Inactive' }),
|
|
86
|
+
createField({ IsRequired: true, DestinationFieldName: '' }),
|
|
87
|
+
];
|
|
88
|
+
expect(getUnmappedRequiredCount(fields)).toBe(1);
|
|
89
|
+
});
|
|
90
|
+
it('should return 0 for empty field list', () => {
|
|
91
|
+
expect(getUnmappedRequiredCount([])).toBe(0);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe('HasKeyField', () => {
|
|
95
|
+
it('should return true when an active key field exists', () => {
|
|
96
|
+
const fields = [
|
|
97
|
+
createField({ IsKeyField: false }),
|
|
98
|
+
createField({ IsKeyField: true }),
|
|
99
|
+
];
|
|
100
|
+
expect(getHasKeyField(fields)).toBe(true);
|
|
101
|
+
});
|
|
102
|
+
it('should return false when no key fields exist', () => {
|
|
103
|
+
const fields = [
|
|
104
|
+
createField({ IsKeyField: false }),
|
|
105
|
+
createField({ IsKeyField: false }),
|
|
106
|
+
];
|
|
107
|
+
expect(getHasKeyField(fields)).toBe(false);
|
|
108
|
+
});
|
|
109
|
+
it('should ignore inactive key fields', () => {
|
|
110
|
+
const fields = [
|
|
111
|
+
createField({ IsKeyField: true, Status: 'Inactive' }),
|
|
112
|
+
];
|
|
113
|
+
expect(getHasKeyField(fields)).toBe(false);
|
|
114
|
+
});
|
|
115
|
+
it('should return false for empty list', () => {
|
|
116
|
+
expect(getHasKeyField([])).toBe(false);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe('MappingValidation', () => {
|
|
120
|
+
it('should be valid when all required fields are mapped and a key exists', () => {
|
|
121
|
+
const fields = [
|
|
122
|
+
createField({ IsRequired: true, DestinationFieldName: 'Email', IsKeyField: true }),
|
|
123
|
+
createField({ IsRequired: false, DestinationFieldName: 'Name' }),
|
|
124
|
+
];
|
|
125
|
+
const result = getMappingValidation(fields);
|
|
126
|
+
expect(result.IsValid).toBe(true);
|
|
127
|
+
expect(result.Warnings).toHaveLength(0);
|
|
128
|
+
});
|
|
129
|
+
it('should warn about unmapped required fields', () => {
|
|
130
|
+
const fields = [
|
|
131
|
+
createField({ IsRequired: true, DestinationFieldName: '', IsKeyField: true }),
|
|
132
|
+
];
|
|
133
|
+
const result = getMappingValidation(fields);
|
|
134
|
+
expect(result.IsValid).toBe(false);
|
|
135
|
+
expect(result.Warnings).toHaveLength(1);
|
|
136
|
+
expect(result.Warnings[0]).toContain('1 required field(s) missing');
|
|
137
|
+
});
|
|
138
|
+
it('should warn about missing key field when active fields exist', () => {
|
|
139
|
+
const fields = [
|
|
140
|
+
createField({ IsKeyField: false, DestinationFieldName: 'Name' }),
|
|
141
|
+
];
|
|
142
|
+
const result = getMappingValidation(fields);
|
|
143
|
+
expect(result.IsValid).toBe(false);
|
|
144
|
+
expect(result.Warnings).toHaveLength(1);
|
|
145
|
+
expect(result.Warnings[0]).toContain('No key field configured');
|
|
146
|
+
});
|
|
147
|
+
it('should report both warnings when both issues exist', () => {
|
|
148
|
+
const fields = [
|
|
149
|
+
createField({ IsRequired: true, DestinationFieldName: '', IsKeyField: false }),
|
|
150
|
+
createField({ IsRequired: false, DestinationFieldName: 'Name', IsKeyField: false }),
|
|
151
|
+
];
|
|
152
|
+
const result = getMappingValidation(fields);
|
|
153
|
+
expect(result.IsValid).toBe(false);
|
|
154
|
+
expect(result.Warnings).toHaveLength(2);
|
|
155
|
+
});
|
|
156
|
+
it('should be valid (no warnings) for empty field list', () => {
|
|
157
|
+
const result = getMappingValidation([]);
|
|
158
|
+
expect(result.IsValid).toBe(true);
|
|
159
|
+
expect(result.Warnings).toHaveLength(0);
|
|
160
|
+
});
|
|
161
|
+
it('should not warn about key field when no active fields exist', () => {
|
|
162
|
+
const fields = [
|
|
163
|
+
createField({ Status: 'Inactive', IsKeyField: false }),
|
|
164
|
+
];
|
|
165
|
+
const result = getMappingValidation(fields);
|
|
166
|
+
expect(result.IsValid).toBe(true);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
//# sourceMappingURL=mapping-validation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapping-validation.test.js","sourceRoot":"","sources":["../../src/__tests__/mapping-validation.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tests for MappingWorkspace validation logic\n * Covers: UnmappedRequiredCount, HasKeyField, MappingValidation, ActiveEditableFields\n * Tests pure logic extracted from the component's computed properties.\n */\nimport { describe, it, expect } from 'vitest';\n\n/** Mirrors the EditableFieldMap interface from the mapping workspace */\ninterface EditableFieldMap {\n ID: string | null;\n SourceFieldName: string;\n SourceFieldLabel: string;\n SourceFieldType: string;\n DestinationFieldName: string;\n DestinationFieldLabel: string;\n IsKeyField: boolean;\n IsRequired: boolean;\n Direction: 'Both' | 'DestToSource' | 'SourceToDest';\n Status: 'Active' | 'Inactive';\n IsNew: boolean;\n IsDirty: boolean;\n}\n\nfunction createField(overrides: Partial<EditableFieldMap> = {}): EditableFieldMap {\n return {\n ID: 'fm-1',\n SourceFieldName: 'source_field',\n SourceFieldLabel: 'Source Field',\n SourceFieldType: 'string',\n DestinationFieldName: 'DestField',\n DestinationFieldLabel: 'Dest Field',\n IsKeyField: false,\n IsRequired: false,\n Direction: 'SourceToDest',\n Status: 'Active',\n IsNew: false,\n IsDirty: false,\n ...overrides\n };\n}\n\n// Replicates the component's computed properties as pure functions\nfunction getActiveFields(fields: EditableFieldMap[]): EditableFieldMap[] {\n return fields.filter(f => f.Status !== 'Inactive');\n}\n\nfunction getUnmappedRequiredCount(fields: EditableFieldMap[]): number {\n return fields.filter(\n f => f.Status === 'Active' && f.IsRequired && !f.DestinationFieldName\n ).length;\n}\n\nfunction getHasKeyField(fields: EditableFieldMap[]): boolean {\n return fields.some(f => f.Status === 'Active' && f.IsKeyField);\n}\n\nfunction getMappingValidation(fields: EditableFieldMap[]): { IsValid: boolean; Warnings: string[] } {\n const warnings: string[] = [];\n const unmappedRequired = getUnmappedRequiredCount(fields);\n if (unmappedRequired > 0) {\n warnings.push(`${unmappedRequired} required field(s) missing destination mapping`);\n }\n const activeFields = getActiveFields(fields);\n if (!getHasKeyField(fields) && activeFields.length > 0) {\n warnings.push('No key field configured — sync may create duplicates');\n }\n return { IsValid: warnings.length === 0, Warnings: warnings };\n}\n\ndescribe('MappingWorkspace Validation', () => {\n\n describe('ActiveEditableFields', () => {\n it('should return only active fields', () => {\n const fields = [\n createField({ Status: 'Active' }),\n createField({ Status: 'Inactive' }),\n createField({ Status: 'Active' }),\n ];\n expect(getActiveFields(fields)).toHaveLength(2);\n });\n\n it('should return empty array when all fields are inactive', () => {\n const fields = [\n createField({ Status: 'Inactive' }),\n createField({ Status: 'Inactive' }),\n ];\n expect(getActiveFields(fields)).toHaveLength(0);\n });\n\n it('should return empty array for no fields', () => {\n expect(getActiveFields([])).toHaveLength(0);\n });\n });\n\n describe('UnmappedRequiredCount', () => {\n it('should return 0 when no required fields are unmapped', () => {\n const fields = [\n createField({ IsRequired: true, DestinationFieldName: 'Mapped' }),\n createField({ IsRequired: false, DestinationFieldName: '' }),\n ];\n expect(getUnmappedRequiredCount(fields)).toBe(0);\n });\n\n it('should count required fields with empty destination', () => {\n const fields = [\n createField({ IsRequired: true, DestinationFieldName: '' }),\n createField({ IsRequired: true, DestinationFieldName: '' }),\n createField({ IsRequired: true, DestinationFieldName: 'Name' }),\n ];\n expect(getUnmappedRequiredCount(fields)).toBe(2);\n });\n\n it('should ignore inactive required fields', () => {\n const fields = [\n createField({ IsRequired: true, DestinationFieldName: '', Status: 'Inactive' }),\n createField({ IsRequired: true, DestinationFieldName: '' }),\n ];\n expect(getUnmappedRequiredCount(fields)).toBe(1);\n });\n\n it('should return 0 for empty field list', () => {\n expect(getUnmappedRequiredCount([])).toBe(0);\n });\n });\n\n describe('HasKeyField', () => {\n it('should return true when an active key field exists', () => {\n const fields = [\n createField({ IsKeyField: false }),\n createField({ IsKeyField: true }),\n ];\n expect(getHasKeyField(fields)).toBe(true);\n });\n\n it('should return false when no key fields exist', () => {\n const fields = [\n createField({ IsKeyField: false }),\n createField({ IsKeyField: false }),\n ];\n expect(getHasKeyField(fields)).toBe(false);\n });\n\n it('should ignore inactive key fields', () => {\n const fields = [\n createField({ IsKeyField: true, Status: 'Inactive' }),\n ];\n expect(getHasKeyField(fields)).toBe(false);\n });\n\n it('should return false for empty list', () => {\n expect(getHasKeyField([])).toBe(false);\n });\n });\n\n describe('MappingValidation', () => {\n it('should be valid when all required fields are mapped and a key exists', () => {\n const fields = [\n createField({ IsRequired: true, DestinationFieldName: 'Email', IsKeyField: true }),\n createField({ IsRequired: false, DestinationFieldName: 'Name' }),\n ];\n const result = getMappingValidation(fields);\n expect(result.IsValid).toBe(true);\n expect(result.Warnings).toHaveLength(0);\n });\n\n it('should warn about unmapped required fields', () => {\n const fields = [\n createField({ IsRequired: true, DestinationFieldName: '', IsKeyField: true }),\n ];\n const result = getMappingValidation(fields);\n expect(result.IsValid).toBe(false);\n expect(result.Warnings).toHaveLength(1);\n expect(result.Warnings[0]).toContain('1 required field(s) missing');\n });\n\n it('should warn about missing key field when active fields exist', () => {\n const fields = [\n createField({ IsKeyField: false, DestinationFieldName: 'Name' }),\n ];\n const result = getMappingValidation(fields);\n expect(result.IsValid).toBe(false);\n expect(result.Warnings).toHaveLength(1);\n expect(result.Warnings[0]).toContain('No key field configured');\n });\n\n it('should report both warnings when both issues exist', () => {\n const fields = [\n createField({ IsRequired: true, DestinationFieldName: '', IsKeyField: false }),\n createField({ IsRequired: false, DestinationFieldName: 'Name', IsKeyField: false }),\n ];\n const result = getMappingValidation(fields);\n expect(result.IsValid).toBe(false);\n expect(result.Warnings).toHaveLength(2);\n });\n\n it('should be valid (no warnings) for empty field list', () => {\n const result = getMappingValidation([]);\n expect(result.IsValid).toBe(true);\n expect(result.Warnings).toHaveLength(0);\n });\n\n it('should not warn about key field when no active fields exist', () => {\n const fields = [\n createField({ Status: 'Inactive', IsKeyField: false }),\n ];\n const result = getMappingValidation(fields);\n expect(result.IsValid).toBe(true);\n });\n });\n});\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-dashboards",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.10.0",
|
|
4
4
|
"description": "MemberJunction Dashboards",
|
|
5
5
|
"main": "./dist/public-api.js",
|
|
6
6
|
"typings": "./dist/public-api.d.ts",
|
|
@@ -34,43 +34,45 @@
|
|
|
34
34
|
"@codemirror/merge": "^6.11.2",
|
|
35
35
|
"@codemirror/state": "^6.5.4",
|
|
36
36
|
"@codemirror/view": "^6.39.12",
|
|
37
|
-
"@memberjunction/actions-base": "5.
|
|
38
|
-
"@memberjunction/ai-engine-base": "5.
|
|
39
|
-
"@memberjunction/api-keys-base": "5.
|
|
40
|
-
"@memberjunction/ai-core-plus": "5.
|
|
41
|
-
"@memberjunction/core": "5.
|
|
42
|
-
"@memberjunction/export-engine": "5.
|
|
43
|
-
"@memberjunction/ng-entity-relationship-diagram": "5.
|
|
44
|
-
"@memberjunction/core-entities": "5.
|
|
45
|
-
"@memberjunction/global": "5.
|
|
46
|
-
"@memberjunction/graphql-dataprovider": "5.
|
|
47
|
-
"@memberjunction/
|
|
48
|
-
"@memberjunction/
|
|
49
|
-
"@memberjunction/ng-
|
|
50
|
-
"@memberjunction/ng-
|
|
51
|
-
"@memberjunction/ng-
|
|
52
|
-
"@memberjunction/ng-
|
|
53
|
-
"@memberjunction/ng-
|
|
54
|
-
"@memberjunction/ng-
|
|
55
|
-
"@memberjunction/ng-
|
|
56
|
-
"@memberjunction/ng-
|
|
57
|
-
"@memberjunction/ng-
|
|
58
|
-
"@memberjunction/ng-
|
|
59
|
-
"@memberjunction/ng-
|
|
60
|
-
"@memberjunction/ng-
|
|
61
|
-
"@memberjunction/ng-
|
|
62
|
-
"@memberjunction/ng-
|
|
63
|
-
"@memberjunction/ng-
|
|
64
|
-
"@memberjunction/ng-
|
|
65
|
-
"@memberjunction/ng-
|
|
66
|
-
"@memberjunction/ng-
|
|
67
|
-
"@memberjunction/ng-shared
|
|
68
|
-
"@memberjunction/ng-
|
|
69
|
-
"@memberjunction/ng-
|
|
70
|
-
"@memberjunction/
|
|
71
|
-
"@memberjunction/
|
|
72
|
-
"@memberjunction/
|
|
73
|
-
"@memberjunction/
|
|
37
|
+
"@memberjunction/actions-base": "5.10.0",
|
|
38
|
+
"@memberjunction/ai-engine-base": "5.10.0",
|
|
39
|
+
"@memberjunction/api-keys-base": "5.10.0",
|
|
40
|
+
"@memberjunction/ai-core-plus": "5.10.0",
|
|
41
|
+
"@memberjunction/core": "5.10.0",
|
|
42
|
+
"@memberjunction/export-engine": "5.10.0",
|
|
43
|
+
"@memberjunction/ng-entity-relationship-diagram": "5.10.0",
|
|
44
|
+
"@memberjunction/core-entities": "5.10.0",
|
|
45
|
+
"@memberjunction/global": "5.10.0",
|
|
46
|
+
"@memberjunction/graphql-dataprovider": "5.10.0",
|
|
47
|
+
"@memberjunction/integration-engine-base": "5.10.0",
|
|
48
|
+
"@memberjunction/interactive-component-types": "5.10.0",
|
|
49
|
+
"@memberjunction/ng-action-gallery": "5.10.0",
|
|
50
|
+
"@memberjunction/ng-actions": "5.10.0",
|
|
51
|
+
"@memberjunction/ng-agents": "5.10.0",
|
|
52
|
+
"@memberjunction/ng-ai-test-harness": "5.10.0",
|
|
53
|
+
"@memberjunction/ng-base-application": "5.10.0",
|
|
54
|
+
"@memberjunction/ng-code-editor": "5.10.0",
|
|
55
|
+
"@memberjunction/ng-container-directives": "5.10.0",
|
|
56
|
+
"@memberjunction/ng-core-entity-forms": "5.10.0",
|
|
57
|
+
"@memberjunction/ng-credentials": "5.10.0",
|
|
58
|
+
"@memberjunction/ng-dashboard-viewer": "5.10.0",
|
|
59
|
+
"@memberjunction/ng-entity-viewer": "5.10.0",
|
|
60
|
+
"@memberjunction/ng-export-service": "5.10.0",
|
|
61
|
+
"@memberjunction/ng-filter-builder": "5.10.0",
|
|
62
|
+
"@memberjunction/ng-list-management": "5.10.0",
|
|
63
|
+
"@memberjunction/ng-explorer-settings": "5.10.0",
|
|
64
|
+
"@memberjunction/ng-notifications": "5.10.0",
|
|
65
|
+
"@memberjunction/ng-query-viewer": "5.10.0",
|
|
66
|
+
"@memberjunction/ng-react": "5.10.0",
|
|
67
|
+
"@memberjunction/ng-shared": "5.10.0",
|
|
68
|
+
"@memberjunction/ng-shared-generic": "5.10.0",
|
|
69
|
+
"@memberjunction/ng-trees": "5.10.0",
|
|
70
|
+
"@memberjunction/ng-versions": "5.10.0",
|
|
71
|
+
"@memberjunction/ng-testing": "5.10.0",
|
|
72
|
+
"@memberjunction/skip-types": "5.10.0",
|
|
73
|
+
"@memberjunction/templates-base-types": "5.10.0",
|
|
74
|
+
"@memberjunction/testing-engine-base": "5.10.0",
|
|
75
|
+
"@memberjunction/ng-markdown": "5.10.0",
|
|
74
76
|
"@progress/kendo-angular-buttons": "22.0.1",
|
|
75
77
|
"@progress/kendo-angular-dateinputs": "22.0.1",
|
|
76
78
|
"@progress/kendo-angular-dialog": "22.0.1",
|