@memberjunction/ng-explorer-core 5.42.0 → 5.44.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 (61) hide show
  1. package/dist/generated/lazy-feature-config.d.ts +1 -1
  2. package/dist/generated/lazy-feature-config.d.ts.map +1 -1
  3. package/dist/generated/lazy-feature-config.js +14 -3
  4. package/dist/generated/lazy-feature-config.js.map +1 -1
  5. package/dist/lib/about/about-dialog.component.d.ts +0 -1
  6. package/dist/lib/about/about-dialog.component.d.ts.map +1 -1
  7. package/dist/lib/about/about-dialog.component.js +217 -218
  8. package/dist/lib/about/about-dialog.component.js.map +1 -1
  9. package/dist/lib/command-palette/command-palette.component.js +8 -14
  10. package/dist/lib/command-palette/command-palette.component.js.map +1 -1
  11. package/dist/lib/conversation-feedback/conversation-feedback.js +66 -73
  12. package/dist/lib/conversation-feedback/conversation-feedback.js.map +1 -1
  13. package/dist/lib/dashboard-preferences-dialog/dashboard-preferences-dialog.component.js +35 -45
  14. package/dist/lib/dashboard-preferences-dialog/dashboard-preferences-dialog.component.js.map +1 -1
  15. package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts +2 -1
  16. package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts.map +1 -1
  17. package/dist/lib/resource-wrappers/chat-conversations-resource.component.js +14 -8
  18. package/dist/lib/resource-wrappers/chat-conversations-resource.component.js.map +1 -1
  19. package/dist/lib/resource-wrappers/dashboard-resource.component.d.ts.map +1 -1
  20. package/dist/lib/resource-wrappers/dashboard-resource.component.js +9 -8
  21. package/dist/lib/resource-wrappers/dashboard-resource.component.js.map +1 -1
  22. package/dist/lib/resource-wrappers/livekit-room-resource.component.d.ts +62 -2
  23. package/dist/lib/resource-wrappers/livekit-room-resource.component.d.ts.map +1 -1
  24. package/dist/lib/resource-wrappers/livekit-room-resource.component.js +604 -105
  25. package/dist/lib/resource-wrappers/livekit-room-resource.component.js.map +1 -1
  26. package/dist/lib/resource-wrappers/search-results-resource.component.d.ts.map +1 -1
  27. package/dist/lib/resource-wrappers/search-results-resource.component.js +35 -43
  28. package/dist/lib/resource-wrappers/search-results-resource.component.js.map +1 -1
  29. package/dist/lib/shell/components/tabs/component-cache-manager.d.ts +10 -2
  30. package/dist/lib/shell/components/tabs/component-cache-manager.d.ts.map +1 -1
  31. package/dist/lib/shell/components/tabs/component-cache-manager.js +19 -1
  32. package/dist/lib/shell/components/tabs/component-cache-manager.js.map +1 -1
  33. package/dist/lib/shell/components/tabs/tab-container.component.d.ts +1 -0
  34. package/dist/lib/shell/components/tabs/tab-container.component.d.ts.map +1 -1
  35. package/dist/lib/shell/components/tabs/tab-container.component.js +3 -2
  36. package/dist/lib/shell/components/tabs/tab-container.component.js.map +1 -1
  37. package/dist/lib/shell/shell.module.d.ts +1 -1
  38. package/dist/lib/shell/shell.module.d.ts.map +1 -1
  39. package/dist/lib/shell/shell.module.js +4 -1
  40. package/dist/lib/shell/shell.module.js.map +1 -1
  41. package/dist/lib/single-dashboard/Components/add-item/add-item.component.js +5 -7
  42. package/dist/lib/single-dashboard/Components/add-item/add-item.component.js.map +1 -1
  43. package/dist/lib/single-dashboard/single-dashboard.component.js +17 -27
  44. package/dist/lib/single-dashboard/single-dashboard.component.js.map +1 -1
  45. package/dist/lib/single-list-detail/single-list-detail.component.d.ts +6 -2
  46. package/dist/lib/single-list-detail/single-list-detail.component.d.ts.map +1 -1
  47. package/dist/lib/single-list-detail/single-list-detail.component.js +48 -57
  48. package/dist/lib/single-list-detail/single-list-detail.component.js.map +1 -1
  49. package/dist/lib/single-search-result/single-search-result.component.js +17 -22
  50. package/dist/lib/single-search-result/single-search-result.component.js.map +1 -1
  51. package/dist/lib/user-notifications/user-notifications.component.js +60 -75
  52. package/dist/lib/user-notifications/user-notifications.component.js.map +1 -1
  53. package/dist/module.d.ts +1 -1
  54. package/dist/module.d.ts.map +1 -1
  55. package/dist/module.js +12 -5
  56. package/dist/module.js.map +1 -1
  57. package/package.json +47 -47
  58. package/dist/lib/__tests__/explorer-core.test.d.ts +0 -2
  59. package/dist/lib/__tests__/explorer-core.test.d.ts.map +0 -1
  60. package/dist/lib/__tests__/explorer-core.test.js +0 -229
  61. package/dist/lib/__tests__/explorer-core.test.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-feedback.js","sourceRoot":"","sources":["../../../src/lib/conversation-feedback/conversation-feedback.ts","../../../src/lib/conversation-feedback/conversation-feedback.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, ChangeDetectorRef, HostListener, inject } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { RunQuery } from '@memberjunction/core';\nimport { ApplicationManager } from '@memberjunction/ng-base-application';\n\nexport interface FeedbackRow {\n ratingID: string;\n rating: number;\n comments: string | null;\n createdAt: string;\n raterName: string | null;\n raterEmail: string | null;\n conversationDetailID: string;\n conversationID: string | null;\n conversationName: string | null;\n messageText: string | null;\n messageSnippet: string | null;\n messageRole: string | null;\n agentID: string | null;\n agentName: string | null;\n}\n\nexport type RatingBand = 'all' | 'high' | 'mid' | 'low';\nexport type DateRange = 'all' | '1d' | '7d' | '30d' | '90d';\n\n@Component({\n standalone: false,\n selector: 'mj-conversation-feedback',\n templateUrl: './conversation-feedback.html',\n styleUrls: ['./conversation-feedback.css']\n})\n@RegisterClass(BaseResourceComponent, 'ConversationFeedbackResource')\nexport class ConversationFeedbackResource extends BaseResourceComponent implements OnInit {\n isInitializing = true;\n loading = false;\n statsLoading = false;\n error: string | null = null;\n\n ratingBand: RatingBand = 'all';\n dateRange: DateRange = '7d';\n searchTerm = '';\n\n rows: FeedbackRow[] = [];\n totalRowCount = 0;\n\n pageSize: number = 10;\n currentPage: number = 1;\n readonly pageSizeOptions: number[] = [10, 25, 50, 100];\n\n stats = { total: 0, avgRating: 0, percentPositive: 0, percentNegative: 0 };\n\n selectedRow: FeedbackRow | null = null;\n\n private searchDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n private cdr = inject(ChangeDetectorRef);\n private appManager = inject(ApplicationManager);\n\n async GetResourceDisplayName(): Promise<string> {\n return 'Agent Feedback';\n }\n\n async GetResourceIconClass(): Promise<string> {\n return 'fa-solid fa-comment-dots';\n }\n\n override async ngOnInit(): Promise<void> {\n this.isInitializing = false;\n this.cdr.detectChanges();\n await this.applyFilters();\n this.NotifyLoadComplete();\n }\n\n /** Manual refresh from the page header — same path as a filter change. */\n async loadFeedback(): Promise<void> {\n await this.applyFilters();\n }\n\n setBand(band: RatingBand): void {\n if (this.ratingBand === band) return;\n this.ratingBand = band;\n this.currentPage = 1;\n void this.applyFilters();\n }\n\n setDateRange(range: DateRange): void {\n if (this.dateRange === range) return;\n this.dateRange = range;\n this.currentPage = 1;\n void this.applyFilters();\n }\n\n /**\n * Search input fires on every keystroke; debounce so we don't slam the\n * server while the user is typing. 250ms is enough to feel responsive\n * without firing on intermediate states.\n */\n onSearchChange(): void {\n if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer);\n this.searchDebounceTimer = setTimeout(() => {\n this.currentPage = 1;\n void this.applyFilters();\n }, 250);\n }\n\n onPageChange(event: { PageNumber: number; PageSize: number; StartRow: number }): void {\n if (event.PageNumber === this.currentPage) return;\n this.currentPage = event.PageNumber;\n void this.loadRows();\n }\n\n onPageSizeChange(size: number): void {\n const next = Number(size);\n if (!next || next === this.pageSize) return;\n this.pageSize = next;\n this.currentPage = 1;\n void this.loadRows();\n }\n\n openDrawer(row: FeedbackRow): void {\n this.selectedRow = row;\n this.cdr.detectChanges();\n }\n\n closeDrawer(): void {\n this.selectedRow = null;\n this.cdr.detectChanges();\n }\n\n async openConversation(): Promise<void> {\n if (!this.selectedRow?.conversationID) return;\n const conversationID = this.selectedRow.conversationID;\n\n // The Chat app owns the Conversations nav item; the active app (Agent\n // Feedback) does not, so we must target Chat explicitly. Fall back to\n // scanning all apps for a nav item whose DriverClass is the chat resource.\n let appId: string | undefined = this.appManager.GetAppByName('Chat')?.ID;\n let navItemLabel = 'Conversations';\n\n if (!appId) {\n for (const app of this.appManager.GetAllApps()) {\n const navItems = await app.GetNavItems();\n const match = navItems.find(n => (n as any).DriverClass === 'ChatConversationsResource');\n if (match) {\n appId = app.ID;\n navItemLabel = match.Label;\n break;\n }\n }\n }\n\n if (!appId) {\n this.error = 'Could not find a Chat application to open this conversation in.';\n this.cdr.detectChanges();\n return;\n }\n\n this.closeDrawer();\n await this.navigationService.OpenNavItemByName(navItemLabel, { conversationId: conversationID }, appId);\n }\n\n @HostListener('document:keydown.escape')\n onEscape(): void {\n if (this.selectedRow) this.closeDrawer();\n }\n\n bandClassFor(rating: number): string {\n if (rating >= 8) return 'rating-high';\n if (rating >= 4) return 'rating-mid';\n return 'rating-low';\n }\n\n trackByRatingID = (_: number, row: FeedbackRow): string => row.ratingID;\n\n /** 1-based index of the first row on the current page (0 when empty). */\n get rangeStart(): number {\n if (this.totalRowCount === 0) return 0;\n return (this.currentPage - 1) * this.pageSize + 1;\n }\n\n /** 1-based index of the last row on the current page (clamped to total). */\n get rangeEnd(): number {\n return Math.min(this.currentPage * this.pageSize, this.totalRowCount);\n }\n\n /**\n * True when the filtered set fits on a single page — in this case\n * mj-pagination hides itself, so the footer renders a fallback summary\n * line. When false we let mj-pagination own the bar (it has its own\n * `1-N of M` summary on the left + nav controls on the right).\n */\n get isSinglePage(): boolean {\n if (this.totalRowCount <= 0) return false;\n return Math.ceil(this.totalRowCount / this.pageSize) <= 1;\n }\n\n /**\n * Run both the rows-query (paged) and the stats-query (aggregate) against\n * the current filter state. Called when filters change or on initial load.\n */\n private async applyFilters(): Promise<void> {\n await Promise.all([this.loadRows(), this.loadStats()]);\n }\n\n /**\n * Fetch the current page of rows from the server. The mj-pagination\n * footer reads `totalRowCount` to derive the page count.\n */\n private async loadRows(): Promise<void> {\n this.loading = true;\n this.error = null;\n this.cdr.detectChanges();\n\n try {\n const rq = new RunQuery();\n const result = await rq.RunQuery({\n QueryName: 'ListConversationDetailFeedback',\n CategoryPath: '/MJ/Conversations',\n Parameters: this.buildQueryParameters(),\n StartRow: (this.currentPage - 1) * this.pageSize,\n MaxRows: this.pageSize\n });\n\n if (!result.Success) {\n this.error = result.ErrorMessage || 'Failed to load feedback';\n this.rows = [];\n this.totalRowCount = 0;\n return;\n }\n\n this.rows = (result.Results ?? []).map((r: any) => this.mapRow(r));\n this.totalRowCount = result.TotalRowCount ?? this.rows.length;\n } catch (e: any) {\n this.error = e?.message || 'Failed to load feedback';\n this.rows = [];\n this.totalRowCount = 0;\n } finally {\n this.loading = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Aggregate counts over the same filter universe as `loadRows()`. Runs in\n * parallel with the rows query so the stat cards and the table stay in\n * sync after every filter change.\n */\n private async loadStats(): Promise<void> {\n this.statsLoading = true;\n this.cdr.detectChanges();\n\n try {\n const rq = new RunQuery();\n const result = await rq.RunQuery({\n QueryName: 'ListConversationDetailFeedbackStats',\n CategoryPath: '/MJ/Conversations',\n Parameters: this.buildQueryParameters()\n });\n\n const row = (result.Results?.[0] as any) || {};\n const total = Number(row.Total ?? 0);\n const avg = Number(row.AvgRating ?? 0);\n const pos = Number(row.PositiveCount ?? 0);\n const neg = Number(row.NegativeCount ?? 0);\n\n this.stats = {\n total,\n avgRating: total ? Math.round(avg * 10) / 10 : 0,\n percentPositive: total ? Math.round((pos / total) * 100) : 0,\n percentNegative: total ? Math.round((neg / total) * 100) : 0\n };\n } catch (e) {\n // Stats are non-critical — the table is the primary surface. Log and\n // leave the previous stats values in place.\n console.warn('[Feedback] stats query failed', e);\n } finally {\n this.statsLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Build the Nunjucks-bound parameter set passed to both queries. Server-side\n * filtering: emit only the keys that actually have a value so the SQL's\n * `{% if X %}` blocks stay inert when filters are at their default.\n */\n private buildQueryParameters(): Record<string, unknown> {\n const params: {\n MinRating?: number;\n MaxRating?: number;\n StartDate?: string;\n SearchText?: string;\n } = {};\n\n if (this.ratingBand === 'high') {\n params.MinRating = 8;\n } else if (this.ratingBand === 'mid') {\n params.MinRating = 4;\n params.MaxRating = 7;\n } else if (this.ratingBand === 'low') {\n params.MaxRating = 3;\n }\n\n const cutoffIso = this.dateRangeCutoffIso();\n if (cutoffIso) {\n params.StartDate = cutoffIso;\n }\n\n const term = this.searchTerm.trim();\n if (term) {\n params.SearchText = term;\n }\n\n return params;\n }\n\n private dateRangeCutoffIso(): string | null {\n if (this.dateRange === 'all') return null;\n const days = this.dateRange === '1d' ? 1\n : this.dateRange === '7d' ? 7\n : this.dateRange === '30d' ? 30\n : 90;\n const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000);\n return cutoff.toISOString();\n }\n\n private mapRow(r: any): FeedbackRow {\n const message: string | null = r.MessageText ?? null;\n const snippet = message\n ? (message.length > 160 ? message.slice(0, 160) + '…' : message)\n : null;\n return {\n ratingID: r.RatingID,\n rating: r.Rating,\n comments: r.Comments ?? null,\n createdAt: r.RatedAt ?? '',\n raterName: r.RaterName ?? null,\n raterEmail: r.RaterEmail ?? null,\n conversationDetailID: r.ConversationDetailID,\n conversationID: r.ConversationID ?? null,\n conversationName: r.ConversationName ?? null,\n messageText: message,\n messageSnippet: snippet,\n messageRole: r.MessageRole ?? null,\n agentID: r.AgentID ?? null,\n agentName: r.AgentName ?? null\n };\n }\n}\n","<div class=\"feedback-container\">\n\n @if (isInitializing) {\n <div class=\"loading-overlay\"><div class=\"spinner\"></div> Loading...</div>\n }\n\n @if (!isInitializing) {\n\n <div class=\"sticky-header\">\n <div class=\"page-header\">\n <div class=\"page-title-area\">\n <div class=\"page-icon\"><i class=\"fa-solid fa-comment-dots\"></i></div>\n <div>\n <h1 class=\"page-title\">Agent Feedback</h1>\n <p class=\"page-subtitle\">User ratings and comments on AI messages</p>\n </div>\n </div>\n <div class=\"page-actions\">\n <button class=\"btn-action\" (click)=\"loadFeedback()\" [disabled]=\"loading\">\n <i class=\"fa-solid fa-arrows-rotate\" [class.fa-spin]=\"loading\"></i> Refresh\n </button>\n </div>\n </div>\n\n @if (error) {\n <div class=\"error-banner\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n {{ error }}\n <button (click)=\"error = null\" aria-label=\"Dismiss error\">×</button>\n </div>\n }\n\n <div class=\"stats-grid\">\n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-total\"><i class=\"fa-solid fa-comment-dots\"></i></div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ stats.total }}</div>\n <div class=\"stat-label\">Total Ratings</div>\n </div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-avg\"><i class=\"fa-solid fa-star\"></i></div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ stats.avgRating }}<span class=\"stat-unit\">/10</span></div>\n <div class=\"stat-label\">Avg Rating</div>\n </div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-positive\"><i class=\"fa-solid fa-thumbs-up\"></i></div>\n <div class=\"stat-content\">\n <div class=\"stat-value rating-high-text\">{{ stats.percentPositive }}%</div>\n <div class=\"stat-label\">Positive (8-10)</div>\n </div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-negative\"><i class=\"fa-solid fa-thumbs-down\"></i></div>\n <div class=\"stat-content\">\n <div class=\"stat-value rating-low-text\">{{ stats.percentNegative }}%</div>\n <div class=\"stat-label\">Negative (1-3)</div>\n </div>\n </div>\n </div>\n\n <div class=\"filter-bar\">\n <div class=\"filter-row\">\n <div class=\"filter-group\">\n <span class=\"filter-label\">Date Range</span>\n <div class=\"btn-group\">\n <button class=\"btn-filter\" [class.active]=\"dateRange === '1d'\" (click)=\"setDateRange('1d')\">1d</button>\n <button class=\"btn-filter\" [class.active]=\"dateRange === '7d'\" (click)=\"setDateRange('7d')\">7d</button>\n <button class=\"btn-filter\" [class.active]=\"dateRange === '30d'\" (click)=\"setDateRange('30d')\">30d</button>\n <button class=\"btn-filter\" [class.active]=\"dateRange === '90d'\" (click)=\"setDateRange('90d')\">90d</button>\n <button class=\"btn-filter\" [class.active]=\"dateRange === 'all'\" (click)=\"setDateRange('all')\">All</button>\n </div>\n </div>\n <div class=\"filter-group\">\n <span class=\"filter-label\">Rating Band</span>\n <div class=\"btn-group\">\n <button class=\"btn-filter\" [class.active]=\"ratingBand === 'all'\" (click)=\"setBand('all')\">All</button>\n <button class=\"btn-filter band-high\" [class.active]=\"ratingBand === 'high'\" (click)=\"setBand('high')\">High 8-10</button>\n <button class=\"btn-filter band-mid\" [class.active]=\"ratingBand === 'mid'\" (click)=\"setBand('mid')\">Mid 4-7</button>\n <button class=\"btn-filter band-low\" [class.active]=\"ratingBand === 'low'\" (click)=\"setBand('low')\">Low 1-3</button>\n </div>\n </div>\n <div class=\"filter-group filter-search\">\n <span class=\"filter-label\">Search</span>\n <input\n type=\"text\"\n class=\"input-search\"\n [(ngModel)]=\"searchTerm\"\n (input)=\"onSearchChange()\"\n placeholder=\"Search comments, message, agent, rater...\" />\n </div>\n </div>\n <div class=\"diagnostic-line\">\n {{ totalRowCount }} {{ totalRowCount === 1 ? 'rating' : 'ratings' }} match the current filters\n </div>\n </div>\n </div>\n\n <div class=\"scrollable-content\">\n @if (loading) {\n <div class=\"loading-overlay\"><div class=\"spinner\"></div> Loading feedback...</div>\n }\n\n @if (!loading) {\n @if (rows.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-comment-slash\"></i>\n <p>No feedback matches the current filters.</p>\n </div>\n } @else {\n <div class=\"feedback-table-wrapper\">\n <table class=\"feedback-table\">\n <thead>\n <tr>\n <th class=\"col-rating\">Rating</th>\n <th class=\"col-comment\">Comments</th>\n <th class=\"col-agent\">Agent</th>\n <th class=\"col-message\">Message</th>\n <th class=\"col-rater\">Rater</th>\n <th class=\"col-when\">When</th>\n </tr>\n </thead>\n <tbody>\n @for (row of rows; track trackByRatingID($index, row)) {\n <tr\n class=\"feedback-row\"\n [class.expanded]=\"selectedRow?.ratingID === row.ratingID\"\n (click)=\"openDrawer(row)\">\n <td class=\"col-rating\">\n <span class=\"rating-badge\" [ngClass]=\"bandClassFor(row.rating)\">\n {{ row.rating }}<small>/10</small>\n </span>\n </td>\n <td class=\"col-comment\">\n @if (row.comments) {\n <div class=\"comment-text clamped\">{{ row.comments }}</div>\n } @else {\n <span class=\"muted\">(no comment)</span>\n }\n </td>\n <td class=\"col-agent\">\n <span class=\"agent-name\">{{ row.agentName || '—' }}</span>\n </td>\n <td class=\"col-message\">\n @if (row.messageSnippet) {\n <span class=\"message-snippet\">{{ row.messageSnippet }}</span>\n } @else {\n <span class=\"muted\">—</span>\n }\n </td>\n <td class=\"col-rater\">\n <div class=\"rater-name\">{{ row.raterName || row.raterEmail || '—' }}</div>\n @if (row.raterEmail && row.raterName) {\n <div class=\"rater-email\">{{ row.raterEmail }}</div>\n }\n </td>\n <td class=\"col-when\">\n <span class=\"when\">{{ row.createdAt | date:'short' }}</span>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n\n <!--\n Bottom bar. When the filtered set spans multiple pages mj-pagination\n renders its own full-width `1-N of M | controls` row. When it fits\n on a single page mj-pagination self-hides, so the footer renders\n a single fallback summary line in its place.\n -->\n <!--\n Bottom bar: mj-pagination on the left (it has its own internal\n `1-N of M | nav controls` layout) + page-size selector hugging the\n right edge. The selector lives outside mj-pagination because the\n shared component doesn't expose a size-change output; the parent\n owns PageSize.\n -->\n <div class=\"pagination-bar\">\n @if (isSinglePage) {\n <span class=\"pagination-summary\">\n {{ rangeStart | number }}-{{ rangeEnd | number }} of {{ totalRowCount | number }}\n {{ totalRowCount === 1 ? 'rating' : 'ratings' }}\n </span>\n } @else {\n <mj-pagination\n class=\"feedback-pagination\"\n [TotalRowCount]=\"totalRowCount\"\n [PageNumber]=\"currentPage\"\n [PageSize]=\"pageSize\"\n [IsLoading]=\"loading\"\n (PageChange)=\"onPageChange($event)\">\n </mj-pagination>\n }\n\n <label class=\"page-size-control\">\n <span class=\"page-size-label\">Rows</span>\n <select\n class=\"page-size-select\"\n [ngModel]=\"pageSize\"\n (ngModelChange)=\"onPageSizeChange($event)\">\n @for (size of pageSizeOptions; track size) {\n <option [ngValue]=\"size\">{{ size }}</option>\n }\n </select>\n </label>\n </div>\n }\n }\n </div>\n }\n\n <!-- ===== Detail slide-out panel ===== -->\n @if (selectedRow) {\n <div class=\"slideout-backdrop\" (click)=\"closeDrawer()\"></div>\n }\n\n <aside class=\"slideout-panel\"\n [class.open]=\"!!selectedRow\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"slideout-title\">\n @if (selectedRow; as r) {\n <div class=\"slideout-header\">\n <div class=\"slideout-title\">\n <i class=\"fa-solid fa-comment-dots\"></i>\n <div class=\"slideout-title-text\">\n <h2 id=\"slideout-title\" class=\"slideout-title-line\">\n Feedback on {{ r.agentName || 'AI message' }}\n </h2>\n <div class=\"slideout-subtitle\">\n <span class=\"rating-badge\" [ngClass]=\"bandClassFor(r.rating)\">\n {{ r.rating }}<small>/10</small>\n </span>\n <span>\n Rated by <strong>{{ r.raterName || r.raterEmail || 'Unknown user' }}</strong>\n · {{ r.createdAt | date:'medium' }}\n </span>\n </div>\n </div>\n </div>\n <button class=\"slideout-close\" (click)=\"closeDrawer()\" title=\"Close (Esc)\" aria-label=\"Close\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <div class=\"slideout-content\">\n <div class=\"slideout-section\">\n <div class=\"section-label\">Reviewer Comment</div>\n @if (r.comments) {\n <div class=\"comment-body\">{{ r.comments }}</div>\n } @else {\n <div class=\"comment-body muted\">(no comment was provided)</div>\n }\n </div>\n\n <div class=\"slideout-section\">\n <div class=\"meta-grid\">\n <div class=\"meta-card\">\n <div class=\"meta-label\">Agent</div>\n <div class=\"meta-value\">{{ r.agentName || '—' }}</div>\n </div>\n <div class=\"meta-card\">\n <div class=\"meta-label\">Conversation</div>\n <div class=\"meta-value\">{{ r.conversationName || '—' }}</div>\n </div>\n <div class=\"meta-card\">\n <div class=\"meta-label\">Message Role</div>\n <div class=\"meta-value\">{{ r.messageRole || '—' }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"slideout-section\">\n <div class=\"message-card\">\n <div class=\"message-card-header\">\n <i class=\"fa-solid fa-message\"></i> Rated Message\n </div>\n <div class=\"message-card-body\">\n @if (r.messageText) {\n {{ r.messageText }}\n } @else {\n <span class=\"muted\">(message text unavailable)</span>\n }\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"slideout-footer\">\n <button mjButton variant=\"flat\" size=\"lg\" (click)=\"closeDrawer()\">Close</button>\n <button mjButton variant=\"primary\" size=\"lg\"\n (click)=\"openConversation()\"\n [disabled]=\"!r.conversationID\"\n [title]=\"r.conversationID ? 'Open the source conversation' : 'No conversation linked'\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i>\n Open Conversation\n </button>\n </div>\n }\n </aside>\n</div>\n"]}
1
+ {"version":3,"file":"conversation-feedback.js","sourceRoot":"","sources":["../../../src/lib/conversation-feedback/conversation-feedback.ts","../../../src/lib/conversation-feedback/conversation-feedback.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, ChangeDetectorRef, HostListener, inject } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { RunQuery } from '@memberjunction/core';\nimport { ApplicationManager } from '@memberjunction/ng-base-application';\n\nexport interface FeedbackRow {\n ratingID: string;\n rating: number;\n comments: string | null;\n createdAt: string;\n raterName: string | null;\n raterEmail: string | null;\n conversationDetailID: string;\n conversationID: string | null;\n conversationName: string | null;\n messageText: string | null;\n messageSnippet: string | null;\n messageRole: string | null;\n agentID: string | null;\n agentName: string | null;\n}\n\nexport type RatingBand = 'all' | 'high' | 'mid' | 'low';\nexport type DateRange = 'all' | '1d' | '7d' | '30d' | '90d';\n\n@Component({\n standalone: false,\n selector: 'mj-conversation-feedback',\n templateUrl: './conversation-feedback.html',\n styleUrls: ['./conversation-feedback.css']\n})\n@RegisterClass(BaseResourceComponent, 'ConversationFeedbackResource')\nexport class ConversationFeedbackResource extends BaseResourceComponent implements OnInit {\n isInitializing = true;\n loading = false;\n statsLoading = false;\n error: string | null = null;\n\n ratingBand: RatingBand = 'all';\n dateRange: DateRange = '7d';\n searchTerm = '';\n\n rows: FeedbackRow[] = [];\n totalRowCount = 0;\n\n pageSize: number = 10;\n currentPage: number = 1;\n readonly pageSizeOptions: number[] = [10, 25, 50, 100];\n\n stats = { total: 0, avgRating: 0, percentPositive: 0, percentNegative: 0 };\n\n selectedRow: FeedbackRow | null = null;\n\n private searchDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n private cdr = inject(ChangeDetectorRef);\n private appManager = inject(ApplicationManager);\n\n async GetResourceDisplayName(): Promise<string> {\n return 'Agent Feedback';\n }\n\n async GetResourceIconClass(): Promise<string> {\n return 'fa-solid fa-comment-dots';\n }\n\n override async ngOnInit(): Promise<void> {\n this.isInitializing = false;\n this.cdr.detectChanges();\n await this.applyFilters();\n this.NotifyLoadComplete();\n }\n\n /** Manual refresh from the page header — same path as a filter change. */\n async loadFeedback(): Promise<void> {\n await this.applyFilters();\n }\n\n setBand(band: RatingBand): void {\n if (this.ratingBand === band) return;\n this.ratingBand = band;\n this.currentPage = 1;\n void this.applyFilters();\n }\n\n setDateRange(range: DateRange): void {\n if (this.dateRange === range) return;\n this.dateRange = range;\n this.currentPage = 1;\n void this.applyFilters();\n }\n\n /**\n * Search input fires on every keystroke; debounce so we don't slam the\n * server while the user is typing. 250ms is enough to feel responsive\n * without firing on intermediate states.\n */\n onSearchChange(): void {\n if (this.searchDebounceTimer) clearTimeout(this.searchDebounceTimer);\n this.searchDebounceTimer = setTimeout(() => {\n this.currentPage = 1;\n void this.applyFilters();\n }, 250);\n }\n\n onPageChange(event: { PageNumber: number; PageSize: number; StartRow: number }): void {\n if (event.PageNumber === this.currentPage) return;\n this.currentPage = event.PageNumber;\n void this.loadRows();\n }\n\n onPageSizeChange(size: number): void {\n const next = Number(size);\n if (!next || next === this.pageSize) return;\n this.pageSize = next;\n this.currentPage = 1;\n void this.loadRows();\n }\n\n openDrawer(row: FeedbackRow): void {\n this.selectedRow = row;\n this.cdr.detectChanges();\n }\n\n closeDrawer(): void {\n this.selectedRow = null;\n this.cdr.detectChanges();\n }\n\n async openConversation(): Promise<void> {\n if (!this.selectedRow?.conversationID) return;\n const conversationID = this.selectedRow.conversationID;\n\n // The Chat app owns the Conversations nav item; the active app (Agent\n // Feedback) does not, so we must target Chat explicitly. Fall back to\n // scanning all apps for a nav item whose DriverClass is the chat resource.\n let appId: string | undefined = this.appManager.GetAppByName('Chat')?.ID;\n let navItemLabel = 'Conversations';\n\n if (!appId) {\n for (const app of this.appManager.GetAllApps()) {\n const navItems = await app.GetNavItems();\n const match = navItems.find(n => (n as any).DriverClass === 'ChatConversationsResource');\n if (match) {\n appId = app.ID;\n navItemLabel = match.Label;\n break;\n }\n }\n }\n\n if (!appId) {\n this.error = 'Could not find a Chat application to open this conversation in.';\n this.cdr.detectChanges();\n return;\n }\n\n this.closeDrawer();\n await this.navigationService.OpenNavItemByName(navItemLabel, { conversationId: conversationID }, appId);\n }\n\n @HostListener('document:keydown.escape')\n onEscape(): void {\n if (this.selectedRow) this.closeDrawer();\n }\n\n bandClassFor(rating: number): string {\n if (rating >= 8) return 'rating-high';\n if (rating >= 4) return 'rating-mid';\n return 'rating-low';\n }\n\n trackByRatingID = (_: number, row: FeedbackRow): string => row.ratingID;\n\n /** 1-based index of the first row on the current page (0 when empty). */\n get rangeStart(): number {\n if (this.totalRowCount === 0) return 0;\n return (this.currentPage - 1) * this.pageSize + 1;\n }\n\n /** 1-based index of the last row on the current page (clamped to total). */\n get rangeEnd(): number {\n return Math.min(this.currentPage * this.pageSize, this.totalRowCount);\n }\n\n /**\n * True when the filtered set fits on a single page — in this case\n * mj-pagination hides itself, so the footer renders a fallback summary\n * line. When false we let mj-pagination own the bar (it has its own\n * `1-N of M` summary on the left + nav controls on the right).\n */\n get isSinglePage(): boolean {\n if (this.totalRowCount <= 0) return false;\n return Math.ceil(this.totalRowCount / this.pageSize) <= 1;\n }\n\n /**\n * Run both the rows-query (paged) and the stats-query (aggregate) against\n * the current filter state. Called when filters change or on initial load.\n */\n private async applyFilters(): Promise<void> {\n await Promise.all([this.loadRows(), this.loadStats()]);\n }\n\n /**\n * Fetch the current page of rows from the server. The mj-pagination\n * footer reads `totalRowCount` to derive the page count.\n */\n private async loadRows(): Promise<void> {\n this.loading = true;\n this.error = null;\n this.cdr.detectChanges();\n\n try {\n const rq = new RunQuery();\n const result = await rq.RunQuery({\n QueryName: 'ListConversationDetailFeedback',\n CategoryPath: '/MJ/Conversations',\n Parameters: this.buildQueryParameters(),\n StartRow: (this.currentPage - 1) * this.pageSize,\n MaxRows: this.pageSize\n });\n\n if (!result.Success) {\n this.error = result.ErrorMessage || 'Failed to load feedback';\n this.rows = [];\n this.totalRowCount = 0;\n return;\n }\n\n this.rows = (result.Results ?? []).map((r: any) => this.mapRow(r));\n this.totalRowCount = result.TotalRowCount ?? this.rows.length;\n } catch (e: any) {\n this.error = e?.message || 'Failed to load feedback';\n this.rows = [];\n this.totalRowCount = 0;\n } finally {\n this.loading = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Aggregate counts over the same filter universe as `loadRows()`. Runs in\n * parallel with the rows query so the stat cards and the table stay in\n * sync after every filter change.\n */\n private async loadStats(): Promise<void> {\n this.statsLoading = true;\n this.cdr.detectChanges();\n\n try {\n const rq = new RunQuery();\n const result = await rq.RunQuery({\n QueryName: 'ListConversationDetailFeedbackStats',\n CategoryPath: '/MJ/Conversations',\n Parameters: this.buildQueryParameters()\n });\n\n const row = (result.Results?.[0] as any) || {};\n const total = Number(row.Total ?? 0);\n const avg = Number(row.AvgRating ?? 0);\n const pos = Number(row.PositiveCount ?? 0);\n const neg = Number(row.NegativeCount ?? 0);\n\n this.stats = {\n total,\n avgRating: total ? Math.round(avg * 10) / 10 : 0,\n percentPositive: total ? Math.round((pos / total) * 100) : 0,\n percentNegative: total ? Math.round((neg / total) * 100) : 0\n };\n } catch (e) {\n // Stats are non-critical — the table is the primary surface. Log and\n // leave the previous stats values in place.\n console.warn('[Feedback] stats query failed', e);\n } finally {\n this.statsLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Build the Nunjucks-bound parameter set passed to both queries. Server-side\n * filtering: emit only the keys that actually have a value so the SQL's\n * `{% if X %}` blocks stay inert when filters are at their default.\n */\n private buildQueryParameters(): Record<string, unknown> {\n const params: {\n MinRating?: number;\n MaxRating?: number;\n StartDate?: string;\n SearchText?: string;\n } = {};\n\n if (this.ratingBand === 'high') {\n params.MinRating = 8;\n } else if (this.ratingBand === 'mid') {\n params.MinRating = 4;\n params.MaxRating = 7;\n } else if (this.ratingBand === 'low') {\n params.MaxRating = 3;\n }\n\n const cutoffIso = this.dateRangeCutoffIso();\n if (cutoffIso) {\n params.StartDate = cutoffIso;\n }\n\n const term = this.searchTerm.trim();\n if (term) {\n params.SearchText = term;\n }\n\n return params;\n }\n\n private dateRangeCutoffIso(): string | null {\n if (this.dateRange === 'all') return null;\n const days = this.dateRange === '1d' ? 1\n : this.dateRange === '7d' ? 7\n : this.dateRange === '30d' ? 30\n : 90;\n const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000);\n return cutoff.toISOString();\n }\n\n private mapRow(r: any): FeedbackRow {\n const message: string | null = r.MessageText ?? null;\n const snippet = message\n ? (message.length > 160 ? message.slice(0, 160) + '…' : message)\n : null;\n return {\n ratingID: r.RatingID,\n rating: r.Rating,\n comments: r.Comments ?? null,\n createdAt: r.RatedAt ?? '',\n raterName: r.RaterName ?? null,\n raterEmail: r.RaterEmail ?? null,\n conversationDetailID: r.ConversationDetailID,\n conversationID: r.ConversationID ?? null,\n conversationName: r.ConversationName ?? null,\n messageText: message,\n messageSnippet: snippet,\n messageRole: r.MessageRole ?? null,\n agentID: r.AgentID ?? null,\n agentName: r.AgentName ?? null\n };\n }\n}\n","<div class=\"feedback-container\">\n\n @if (isInitializing) {\n <div class=\"loading-overlay\"><div class=\"spinner\"></div> Loading...</div>\n }\n\n @if (!isInitializing) {\n\n <div class=\"sticky-header\">\n <div class=\"page-header\">\n <div class=\"page-title-area\">\n <div class=\"page-icon\"><i class=\"fa-solid fa-comment-dots\"></i></div>\n <div>\n <h1 class=\"page-title\">Agent Feedback</h1>\n <p class=\"page-subtitle\">User ratings and comments on AI messages</p>\n </div>\n </div>\n <div class=\"page-actions\">\n <button class=\"btn-action\" (click)=\"loadFeedback()\" [disabled]=\"loading\">\n <i class=\"fa-solid fa-arrows-rotate\" [class.fa-spin]=\"loading\"></i> Refresh\n </button>\n </div>\n </div>\n\n @if (error) {\n <mj-alert Variant=\"error\" class=\"feedback-error-spacing\" Dismissible (Dismissed)=\"error = null\">{{ error }}</mj-alert>\n }\n\n <div class=\"stats-grid\">\n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-total\"><i class=\"fa-solid fa-comment-dots\"></i></div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ stats.total }}</div>\n <div class=\"stat-label\">Total Ratings</div>\n </div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-avg\"><i class=\"fa-solid fa-star\"></i></div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ stats.avgRating }}<span class=\"stat-unit\">/10</span></div>\n <div class=\"stat-label\">Avg Rating</div>\n </div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-positive\"><i class=\"fa-solid fa-thumbs-up\"></i></div>\n <div class=\"stat-content\">\n <div class=\"stat-value rating-high-text\">{{ stats.percentPositive }}%</div>\n <div class=\"stat-label\">Positive (8-10)</div>\n </div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-negative\"><i class=\"fa-solid fa-thumbs-down\"></i></div>\n <div class=\"stat-content\">\n <div class=\"stat-value rating-low-text\">{{ stats.percentNegative }}%</div>\n <div class=\"stat-label\">Negative (1-3)</div>\n </div>\n </div>\n </div>\n\n <div class=\"filter-bar\">\n <div class=\"filter-row\">\n <div class=\"filter-group\">\n <span class=\"filter-label\">Date Range</span>\n <div class=\"btn-group\">\n <button class=\"btn-filter\" [class.active]=\"dateRange === '1d'\" (click)=\"setDateRange('1d')\">1d</button>\n <button class=\"btn-filter\" [class.active]=\"dateRange === '7d'\" (click)=\"setDateRange('7d')\">7d</button>\n <button class=\"btn-filter\" [class.active]=\"dateRange === '30d'\" (click)=\"setDateRange('30d')\">30d</button>\n <button class=\"btn-filter\" [class.active]=\"dateRange === '90d'\" (click)=\"setDateRange('90d')\">90d</button>\n <button class=\"btn-filter\" [class.active]=\"dateRange === 'all'\" (click)=\"setDateRange('all')\">All</button>\n </div>\n </div>\n <div class=\"filter-group\">\n <span class=\"filter-label\">Rating Band</span>\n <div class=\"btn-group\">\n <button class=\"btn-filter\" [class.active]=\"ratingBand === 'all'\" (click)=\"setBand('all')\">All</button>\n <button class=\"btn-filter band-high\" [class.active]=\"ratingBand === 'high'\" (click)=\"setBand('high')\">High 8-10</button>\n <button class=\"btn-filter band-mid\" [class.active]=\"ratingBand === 'mid'\" (click)=\"setBand('mid')\">Mid 4-7</button>\n <button class=\"btn-filter band-low\" [class.active]=\"ratingBand === 'low'\" (click)=\"setBand('low')\">Low 1-3</button>\n </div>\n </div>\n <div class=\"filter-group filter-search\">\n <span class=\"filter-label\">Search</span>\n <input\n type=\"text\"\n class=\"input-search\"\n [(ngModel)]=\"searchTerm\"\n (input)=\"onSearchChange()\"\n placeholder=\"Search comments, message, agent, rater...\" />\n </div>\n </div>\n <div class=\"diagnostic-line\">\n {{ totalRowCount }} {{ totalRowCount === 1 ? 'rating' : 'ratings' }} match the current filters\n </div>\n </div>\n </div>\n\n <div class=\"scrollable-content\">\n @if (loading) {\n <div class=\"loading-overlay\"><div class=\"spinner\"></div> Loading feedback...</div>\n }\n\n @if (!loading) {\n @if (rows.length === 0) {\n <mj-empty-state\n class=\"feedback-empty-state\"\n Variant=\"no-results\"\n Icon=\"fa-solid fa-comment-slash\"\n Title=\"No feedback matches the current filters.\" />\n } @else {\n <div class=\"feedback-table-wrapper\">\n <table class=\"feedback-table\">\n <thead>\n <tr>\n <th class=\"col-rating\">Rating</th>\n <th class=\"col-comment\">Comments</th>\n <th class=\"col-agent\">Agent</th>\n <th class=\"col-message\">Message</th>\n <th class=\"col-rater\">Rater</th>\n <th class=\"col-when\">When</th>\n </tr>\n </thead>\n <tbody>\n @for (row of rows; track trackByRatingID($index, row)) {\n <tr\n class=\"feedback-row\"\n [class.expanded]=\"selectedRow?.ratingID === row.ratingID\"\n (click)=\"openDrawer(row)\">\n <td class=\"col-rating\">\n <span class=\"rating-badge\" [ngClass]=\"bandClassFor(row.rating)\">\n {{ row.rating }}<small>/10</small>\n </span>\n </td>\n <td class=\"col-comment\">\n @if (row.comments) {\n <div class=\"comment-text clamped\">{{ row.comments }}</div>\n } @else {\n <span class=\"muted\">(no comment)</span>\n }\n </td>\n <td class=\"col-agent\">\n <span class=\"agent-name\">{{ row.agentName || '—' }}</span>\n </td>\n <td class=\"col-message\">\n @if (row.messageSnippet) {\n <span class=\"message-snippet\">{{ row.messageSnippet }}</span>\n } @else {\n <span class=\"muted\">—</span>\n }\n </td>\n <td class=\"col-rater\">\n <div class=\"rater-name\">{{ row.raterName || row.raterEmail || '—' }}</div>\n @if (row.raterEmail && row.raterName) {\n <div class=\"rater-email\">{{ row.raterEmail }}</div>\n }\n </td>\n <td class=\"col-when\">\n <span class=\"when\">{{ row.createdAt | date:'short' }}</span>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n\n <!--\n Bottom bar. When the filtered set spans multiple pages mj-pagination\n renders its own full-width `1-N of M | controls` row. When it fits\n on a single page mj-pagination self-hides, so the footer renders\n a single fallback summary line in its place.\n -->\n <!--\n Bottom bar: mj-pagination on the left (it has its own internal\n `1-N of M | nav controls` layout) + page-size selector hugging the\n right edge. The selector lives outside mj-pagination because the\n shared component doesn't expose a size-change output; the parent\n owns PageSize.\n -->\n <div class=\"pagination-bar\">\n @if (isSinglePage) {\n <span class=\"pagination-summary\">\n {{ rangeStart | number }}-{{ rangeEnd | number }} of {{ totalRowCount | number }}\n {{ totalRowCount === 1 ? 'rating' : 'ratings' }}\n </span>\n } @else {\n <mj-pagination\n class=\"feedback-pagination\"\n [TotalRowCount]=\"totalRowCount\"\n [PageNumber]=\"currentPage\"\n [PageSize]=\"pageSize\"\n [IsLoading]=\"loading\"\n (PageChange)=\"onPageChange($event)\">\n </mj-pagination>\n }\n\n <label class=\"page-size-control\">\n <span class=\"page-size-label\">Rows</span>\n <select\n class=\"page-size-select\"\n [ngModel]=\"pageSize\"\n (ngModelChange)=\"onPageSizeChange($event)\">\n @for (size of pageSizeOptions; track size) {\n <option [ngValue]=\"size\">{{ size }}</option>\n }\n </select>\n </label>\n </div>\n }\n }\n </div>\n }\n\n <!-- ===== Detail slide-out panel ===== -->\n @if (selectedRow) {\n <div class=\"slideout-backdrop\" (click)=\"closeDrawer()\"></div>\n }\n\n <aside class=\"slideout-panel\"\n [class.open]=\"!!selectedRow\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"slideout-title\">\n @if (selectedRow; as r) {\n <div class=\"slideout-header\">\n <div class=\"slideout-title\">\n <i class=\"fa-solid fa-comment-dots\"></i>\n <div class=\"slideout-title-text\">\n <h2 id=\"slideout-title\" class=\"slideout-title-line\">\n Feedback on {{ r.agentName || 'AI message' }}\n </h2>\n <div class=\"slideout-subtitle\">\n <span class=\"rating-badge\" [ngClass]=\"bandClassFor(r.rating)\">\n {{ r.rating }}<small>/10</small>\n </span>\n <span>\n Rated by <strong>{{ r.raterName || r.raterEmail || 'Unknown user' }}</strong>\n · {{ r.createdAt | date:'medium' }}\n </span>\n </div>\n </div>\n </div>\n <button class=\"slideout-close\" (click)=\"closeDrawer()\" title=\"Close (Esc)\" aria-label=\"Close\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <div class=\"slideout-content\">\n <div class=\"slideout-section\">\n <div class=\"section-label\">Reviewer Comment</div>\n @if (r.comments) {\n <div class=\"comment-body\">{{ r.comments }}</div>\n } @else {\n <div class=\"comment-body muted\">(no comment was provided)</div>\n }\n </div>\n\n <div class=\"slideout-section\">\n <div class=\"meta-grid\">\n <div class=\"meta-card\">\n <div class=\"meta-label\">Agent</div>\n <div class=\"meta-value\">{{ r.agentName || '—' }}</div>\n </div>\n <div class=\"meta-card\">\n <div class=\"meta-label\">Conversation</div>\n <div class=\"meta-value\">{{ r.conversationName || '—' }}</div>\n </div>\n <div class=\"meta-card\">\n <div class=\"meta-label\">Message Role</div>\n <div class=\"meta-value\">{{ r.messageRole || '—' }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"slideout-section\">\n <div class=\"message-card\">\n <div class=\"message-card-header\">\n <i class=\"fa-solid fa-message\"></i> Rated Message\n </div>\n <div class=\"message-card-body\">\n @if (r.messageText) {\n {{ r.messageText }}\n } @else {\n <span class=\"muted\">(message text unavailable)</span>\n }\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"slideout-footer\">\n <button mjButton variant=\"flat\" size=\"lg\" (click)=\"closeDrawer()\">Close</button>\n <button mjButton variant=\"primary\" size=\"lg\"\n (click)=\"openConversation()\"\n [disabled]=\"!r.conversationID\"\n [title]=\"r.conversationID ? 'Open the source conversation' : 'No conversation linked'\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i>\n Open Conversation\n </button>\n </div>\n }\n </aside>\n</div>\n"]}
@@ -49,23 +49,16 @@ function DashboardPreferencesDialogComponent_Conditional_11_Template(rf, ctx) {
49
49
  i0.ɵɵelementEnd();
50
50
  } }
51
51
  function DashboardPreferencesDialogComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) {
52
- i0.ɵɵelementStart(0, "div", 10);
53
- i0.ɵɵelement(1, "i", 20);
54
- i0.ɵɵtext(2);
55
- i0.ɵɵelementEnd();
52
+ i0.ɵɵelement(0, "mj-empty-state", 10);
56
53
  } if (rf & 2) {
57
54
  const ctx_r0 = i0.ɵɵnextContext();
58
- i0.ɵɵadvance(2);
59
- i0.ɵɵtextInterpolate1(" ", ctx_r0.error, " ");
55
+ i0.ɵɵproperty("Title", ctx_r0.error);
60
56
  } }
61
57
  function DashboardPreferencesDialogComponent_Conditional_13_Conditional_7_Template(rf, ctx) { if (rf & 1) {
62
- i0.ɵɵelementStart(0, "div", 24);
63
- i0.ɵɵelement(1, "i", 29);
64
- i0.ɵɵtext(2, " All dashboards are configured ");
65
- i0.ɵɵelementEnd();
58
+ i0.ɵɵelement(0, "mj-empty-state", 23);
66
59
  } }
67
60
  function DashboardPreferencesDialogComponent_Conditional_13_For_9_Conditional_6_Template(rf, ctx) { if (rf & 1) {
68
- i0.ɵɵelementStart(0, "span", 34);
61
+ i0.ɵɵelementStart(0, "span", 33);
69
62
  i0.ɵɵtext(1);
70
63
  i0.ɵɵelementEnd();
71
64
  } if (rf & 2) {
@@ -75,16 +68,16 @@ function DashboardPreferencesDialogComponent_Conditional_13_For_9_Conditional_6_
75
68
  } }
76
69
  function DashboardPreferencesDialogComponent_Conditional_13_For_9_Template(rf, ctx) { if (rf & 1) {
77
70
  const _r4 = i0.ɵɵgetCurrentView();
78
- i0.ɵɵelementStart(0, "div", 25)(1, "div", 30);
79
- i0.ɵɵelement(2, "i", 31);
80
- i0.ɵɵelementStart(3, "div", 32)(4, "span", 33);
71
+ i0.ɵɵelementStart(0, "div", 24)(1, "div", 29);
72
+ i0.ɵɵelement(2, "i", 30);
73
+ i0.ɵɵelementStart(3, "div", 31)(4, "span", 32);
81
74
  i0.ɵɵtext(5);
82
75
  i0.ɵɵelementEnd();
83
- i0.ɵɵconditionalCreate(6, DashboardPreferencesDialogComponent_Conditional_13_For_9_Conditional_6_Template, 2, 1, "span", 34);
76
+ i0.ɵɵconditionalCreate(6, DashboardPreferencesDialogComponent_Conditional_13_For_9_Conditional_6_Template, 2, 1, "span", 33);
84
77
  i0.ɵɵelementEnd();
85
- i0.ɵɵelementStart(7, "button", 35);
78
+ i0.ɵɵelementStart(7, "button", 34);
86
79
  i0.ɵɵlistener("click", function DashboardPreferencesDialogComponent_Conditional_13_For_9_Template_button_click_7_listener() { const dashboard_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.addDashboard(dashboard_r5)); });
87
- i0.ɵɵelement(8, "i", 36);
80
+ i0.ɵɵelement(8, "i", 35);
88
81
  i0.ɵɵelementEnd()()();
89
82
  } if (rf & 2) {
90
83
  const dashboard_r5 = ctx.$implicit;
@@ -95,13 +88,10 @@ function DashboardPreferencesDialogComponent_Conditional_13_For_9_Template(rf, c
95
88
  i0.ɵɵconditional(dashboard_r5.Description ? 6 : -1);
96
89
  } }
97
90
  function DashboardPreferencesDialogComponent_Conditional_13_Conditional_16_Template(rf, ctx) { if (rf & 1) {
98
- i0.ɵɵelementStart(0, "div", 24);
99
- i0.ɵɵelement(1, "i", 29);
100
- i0.ɵɵtext(2, " No dashboards configured ");
101
- i0.ɵɵelementEnd();
91
+ i0.ɵɵelement(0, "mj-empty-state", 27);
102
92
  } }
103
93
  function DashboardPreferencesDialogComponent_Conditional_13_For_18_Conditional_8_Template(rf, ctx) { if (rf & 1) {
104
- i0.ɵɵelementStart(0, "span", 34);
94
+ i0.ɵɵelementStart(0, "span", 33);
105
95
  i0.ɵɵtext(1);
106
96
  i0.ɵɵelementEnd();
107
97
  } if (rf & 2) {
@@ -111,26 +101,26 @@ function DashboardPreferencesDialogComponent_Conditional_13_For_18_Conditional_8
111
101
  } }
112
102
  function DashboardPreferencesDialogComponent_Conditional_13_For_18_Template(rf, ctx) { if (rf & 1) {
113
103
  const _r6 = i0.ɵɵgetCurrentView();
114
- i0.ɵɵelementStart(0, "div", 28)(1, "div", 30);
115
- i0.ɵɵelement(2, "i", 31);
116
- i0.ɵɵelementStart(3, "span", 37);
104
+ i0.ɵɵelementStart(0, "div", 28)(1, "div", 29);
105
+ i0.ɵɵelement(2, "i", 30);
106
+ i0.ɵɵelementStart(3, "span", 36);
117
107
  i0.ɵɵtext(4);
118
108
  i0.ɵɵelementEnd();
119
- i0.ɵɵelementStart(5, "div", 32)(6, "span", 33);
109
+ i0.ɵɵelementStart(5, "div", 31)(6, "span", 32);
120
110
  i0.ɵɵtext(7);
121
111
  i0.ɵɵelementEnd();
122
- i0.ɵɵconditionalCreate(8, DashboardPreferencesDialogComponent_Conditional_13_For_18_Conditional_8_Template, 2, 1, "span", 34);
112
+ i0.ɵɵconditionalCreate(8, DashboardPreferencesDialogComponent_Conditional_13_For_18_Conditional_8_Template, 2, 1, "span", 33);
123
113
  i0.ɵɵelementEnd();
124
- i0.ɵɵelementStart(9, "button", 38);
114
+ i0.ɵɵelementStart(9, "button", 37);
125
115
  i0.ɵɵlistener("click", function DashboardPreferencesDialogComponent_Conditional_13_For_18_Template_button_click_9_listener() { const dashboard_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.removeDashboard(dashboard_r7)); });
126
116
  i0.ɵɵelement(10, "i", 13);
127
117
  i0.ɵɵelementEnd()()();
128
118
  } if (rf & 2) {
129
119
  const dashboard_r7 = ctx.$implicit;
130
- const ɵ$index_101_r8 = ctx.$index;
120
+ const ɵ$index_92_r8 = ctx.$index;
131
121
  i0.ɵɵproperty("cdkDragData", dashboard_r7);
132
122
  i0.ɵɵadvance(4);
133
- i0.ɵɵtextInterpolate(ɵ$index_101_r8 + 1);
123
+ i0.ɵɵtextInterpolate(ɵ$index_92_r8 + 1);
134
124
  i0.ɵɵadvance(3);
135
125
  i0.ɵɵtextInterpolate(dashboard_r7.Name);
136
126
  i0.ɵɵadvance();
@@ -138,22 +128,22 @@ function DashboardPreferencesDialogComponent_Conditional_13_For_18_Template(rf,
138
128
  } }
139
129
  function DashboardPreferencesDialogComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) {
140
130
  const _r3 = i0.ɵɵgetCurrentView();
141
- i0.ɵɵelementStart(0, "div", 11)(1, "div", 21)(2, "h4");
142
- i0.ɵɵelement(3, "i", 22);
131
+ i0.ɵɵelementStart(0, "div", 11)(1, "div", 20)(2, "h4");
132
+ i0.ɵɵelement(3, "i", 21);
143
133
  i0.ɵɵtext(4, " Available Dashboards");
144
134
  i0.ɵɵelementEnd();
145
- i0.ɵɵelementStart(5, "div", 23, 0);
135
+ i0.ɵɵelementStart(5, "div", 22, 0);
146
136
  i0.ɵɵlistener("cdkDropListDropped", function DashboardPreferencesDialogComponent_Conditional_13_Template_div_cdkDropListDropped_5_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onDrop($event)); });
147
- i0.ɵɵconditionalCreate(7, DashboardPreferencesDialogComponent_Conditional_13_Conditional_7_Template, 3, 0, "div", 24);
148
- i0.ɵɵrepeaterCreate(8, DashboardPreferencesDialogComponent_Conditional_13_For_9_Template, 9, 3, "div", 25, _forTrack0);
137
+ i0.ɵɵconditionalCreate(7, DashboardPreferencesDialogComponent_Conditional_13_Conditional_7_Template, 1, 0, "mj-empty-state", 23);
138
+ i0.ɵɵrepeaterCreate(8, DashboardPreferencesDialogComponent_Conditional_13_For_9_Template, 9, 3, "div", 24, _forTrack0);
149
139
  i0.ɵɵelementEnd()();
150
- i0.ɵɵelementStart(10, "div", 26)(11, "h4");
151
- i0.ɵɵelement(12, "i", 27);
140
+ i0.ɵɵelementStart(10, "div", 25)(11, "h4");
141
+ i0.ɵɵelement(12, "i", 26);
152
142
  i0.ɵɵtext(13, " Configured Dashboards");
153
143
  i0.ɵɵelementEnd();
154
- i0.ɵɵelementStart(14, "div", 23, 1);
144
+ i0.ɵɵelementStart(14, "div", 22, 1);
155
145
  i0.ɵɵlistener("cdkDropListDropped", function DashboardPreferencesDialogComponent_Conditional_13_Template_div_cdkDropListDropped_14_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onDrop($event)); });
156
- i0.ɵɵconditionalCreate(16, DashboardPreferencesDialogComponent_Conditional_13_Conditional_16_Template, 3, 0, "div", 24);
146
+ i0.ɵɵconditionalCreate(16, DashboardPreferencesDialogComponent_Conditional_13_Conditional_16_Template, 1, 0, "mj-empty-state", 27);
157
147
  i0.ɵɵrepeaterCreate(17, DashboardPreferencesDialogComponent_Conditional_13_For_18_Template, 11, 4, "div", 28, _forTrack0);
158
148
  i0.ɵɵelementEnd()()();
159
149
  } if (rf & 2) {
@@ -174,13 +164,13 @@ function DashboardPreferencesDialogComponent_Conditional_13_Template(rf, ctx) {
174
164
  i0.ɵɵrepeater(ctx_r0.configuredDashboards);
175
165
  } }
176
166
  function DashboardPreferencesDialogComponent_Conditional_19_Template(rf, ctx) { if (rf & 1) {
177
- i0.ɵɵelement(0, "mj-loading", 39);
167
+ i0.ɵɵelement(0, "mj-loading", 38);
178
168
  i0.ɵɵtext(1, " Saving... ");
179
169
  } if (rf & 2) {
180
170
  i0.ɵɵproperty("showText", false);
181
171
  } }
182
172
  function DashboardPreferencesDialogComponent_Conditional_20_Template(rf, ctx) { if (rf & 1) {
183
- i0.ɵɵelement(0, "i", 40);
173
+ i0.ɵɵelement(0, "i", 39);
184
174
  i0.ɵɵtext(1, " Save Changes ");
185
175
  } }
186
176
  export class DashboardPreferencesDialogComponent extends BaseAngularComponent {
@@ -515,7 +505,7 @@ export class DashboardPreferencesDialogComponent extends BaseAngularComponent {
515
505
  this.result.emit({ saved: false });
516
506
  }
517
507
  static ɵfac = /*@__PURE__*/ (() => { let ɵDashboardPreferencesDialogComponent_BaseFactory; return function DashboardPreferencesDialogComponent_Factory(__ngFactoryType__) { return (ɵDashboardPreferencesDialogComponent_BaseFactory || (ɵDashboardPreferencesDialogComponent_BaseFactory = i0.ɵɵgetInheritedFactory(DashboardPreferencesDialogComponent)))(__ngFactoryType__ || DashboardPreferencesDialogComponent); }; })();
518
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DashboardPreferencesDialogComponent, selectors: [["mj-dashboard-preferences-dialog"]], inputs: { applicationId: "applicationId", scope: "scope" }, outputs: { result: "result" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 21, vars: 11, consts: [["availableList", "cdkDropList"], ["configuredList", "cdkDropList"], ["Title", "Dashboard Preferences", 3, "Close", "Visible", "Width", "Height", "MinWidth"], [1, "dashboard-preferences-dialog"], [1, "dialog-header"], [1, "fa-solid", "fa-sliders"], [1, "scope-indicator"], [1, "preference-mode-selector"], [1, "dialog-content"], [1, "loading-overlay"], [1, "error-container"], [1, "preferences-panels"], ["type", "button", 1, "btn", "btn-secondary", 3, "click"], [1, "fa-solid", "fa-times"], ["type", "button", 1, "btn", "btn-primary", 3, "click", "disabled"], [1, "fa-solid", "fa-globe"], [1, "fa-solid", "fa-layer-group"], ["type", "radio", "name", "preferenceMode", "value", "personal", 3, "ngModelChange", "change", "ngModel"], ["type", "radio", "name", "preferenceMode", "value", "system", 3, "ngModelChange", "change", "ngModel"], ["text", "Loading preferences...", "size", "large"], [1, "fa-solid", "fa-exclamation-triangle"], [1, "panel", "available-panel"], [1, "fa-solid", "fa-list"], ["cdkDropList", "", 1, "dashboard-list", 3, "cdkDropListDropped", "cdkDropListData", "cdkDropListConnectedTo"], [1, "empty-state"], ["cdkDrag", "", 1, "dashboard-item", "available-item", 3, "cdkDragData"], [1, "panel", "configured-panel"], [1, "fa-solid", "fa-list-ol"], ["cdkDrag", "", 1, "dashboard-item", "configured-item", 3, "cdkDragData"], [1, "fa-solid", "fa-info-circle"], [1, "dashboard-item-content"], [1, "fa-solid", "fa-grip-vertical", "drag-handle"], [1, "dashboard-info"], [1, "dashboard-name"], [1, "dashboard-description"], ["type", "button", "title", "Add to configured dashboards", 1, "add-button", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "order-number"], ["type", "button", "title", "Remove from configured dashboards", 1, "remove-button", 3, "click"], ["size", "small", 3, "showText"], [1, "fa-solid", "fa-check"]], template: function DashboardPreferencesDialogComponent_Template(rf, ctx) { if (rf & 1) {
508
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DashboardPreferencesDialogComponent, selectors: [["mj-dashboard-preferences-dialog"]], inputs: { applicationId: "applicationId", scope: "scope" }, outputs: { result: "result" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 21, vars: 11, consts: [["availableList", "cdkDropList"], ["configuredList", "cdkDropList"], ["Title", "Dashboard Preferences", 3, "Close", "Visible", "Width", "Height", "MinWidth"], [1, "dashboard-preferences-dialog"], [1, "dialog-header"], [1, "fa-solid", "fa-sliders"], [1, "scope-indicator"], [1, "preference-mode-selector"], [1, "dialog-content"], [1, "loading-overlay"], ["Variant", "error", "Size", "compact", "Icon", "fa-solid fa-triangle-exclamation", 3, "Title"], [1, "preferences-panels"], ["type", "button", 1, "btn", "btn-secondary", 3, "click"], [1, "fa-solid", "fa-times"], ["type", "button", 1, "btn", "btn-primary", 3, "click", "disabled"], [1, "fa-solid", "fa-globe"], [1, "fa-solid", "fa-layer-group"], ["type", "radio", "name", "preferenceMode", "value", "personal", 3, "ngModelChange", "change", "ngModel"], ["type", "radio", "name", "preferenceMode", "value", "system", 3, "ngModelChange", "change", "ngModel"], ["text", "Loading preferences...", "size", "large"], [1, "panel", "available-panel"], [1, "fa-solid", "fa-list"], ["cdkDropList", "", 1, "dashboard-list", 3, "cdkDropListDropped", "cdkDropListData", "cdkDropListConnectedTo"], ["Variant", "success", "Size", "compact", "Icon", "fa-solid fa-circle-check", "Title", "All dashboards are configured"], ["cdkDrag", "", 1, "dashboard-item", "available-item", 3, "cdkDragData"], [1, "panel", "configured-panel"], [1, "fa-solid", "fa-list-ol"], ["Size", "compact", "Icon", "fa-solid fa-circle-info", "Title", "No dashboards configured"], ["cdkDrag", "", 1, "dashboard-item", "configured-item", 3, "cdkDragData"], [1, "dashboard-item-content"], [1, "fa-solid", "fa-grip-vertical", "drag-handle"], [1, "dashboard-info"], [1, "dashboard-name"], [1, "dashboard-description"], ["type", "button", "title", "Add to configured dashboards", 1, "add-button", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "order-number"], ["type", "button", "title", "Remove from configured dashboards", 1, "remove-button", 3, "click"], ["size", "small", 3, "showText"], [1, "fa-solid", "fa-check"]], template: function DashboardPreferencesDialogComponent_Template(rf, ctx) { if (rf & 1) {
519
509
  i0.ɵɵelementStart(0, "mj-dialog", 2);
520
510
  i0.ɵɵlistener("Close", function DashboardPreferencesDialogComponent_Template_mj_dialog_Close_0_listener() { return ctx.onCancel(); });
521
511
  i0.ɵɵelementStart(1, "div", 3)(2, "div", 4)(3, "h3");
@@ -529,7 +519,7 @@ export class DashboardPreferencesDialogComponent extends BaseAngularComponent {
529
519
  i0.ɵɵelementEnd();
530
520
  i0.ɵɵelementStart(10, "div", 8);
531
521
  i0.ɵɵconditionalCreate(11, DashboardPreferencesDialogComponent_Conditional_11_Template, 2, 0, "div", 9);
532
- i0.ɵɵconditionalCreate(12, DashboardPreferencesDialogComponent_Conditional_12_Template, 3, 1, "div", 10);
522
+ i0.ɵɵconditionalCreate(12, DashboardPreferencesDialogComponent_Conditional_12_Template, 1, 1, "mj-empty-state", 10);
533
523
  i0.ɵɵconditionalCreate(13, DashboardPreferencesDialogComponent_Conditional_13_Template, 19, 10, "div", 11);
534
524
  i0.ɵɵelementEnd();
535
525
  i0.ɵɵelementStart(14, "mj-dialog-actions")(15, "button", 12);
@@ -557,11 +547,11 @@ export class DashboardPreferencesDialogComponent extends BaseAngularComponent {
557
547
  i0.ɵɵproperty("disabled", !ctx.hasChanges || ctx.saving);
558
548
  i0.ɵɵadvance();
559
549
  i0.ɵɵconditional(ctx.saving ? 19 : 20);
560
- } }, dependencies: [i1.DefaultValueAccessor, i1.RadioControlValueAccessor, i1.NgControlStatus, i1.NgModel, i2.CdkDropList, i2.CdkDrag, i3.LoadingComponent, i4.MJDialogComponent, i4.MJDialogActionsComponent], styles: [".dashboard-preferences-dialog[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.dialog-header[_ngcontent-%COMP%] {\n padding: 20px 24px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.dialog-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.dialog-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 8px;\n color: var(--mj-text-secondary);\n}\n\n.scope-indicator[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.scope-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 6px;\n}\n\n.preference-mode-selector[_ngcontent-%COMP%] {\n margin-top: 12px;\n display: flex;\n gap: 20px;\n}\n\n.preference-mode-selector[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.preference-mode-selector[_ngcontent-%COMP%] input[type=\"radio\"][_ngcontent-%COMP%] {\n margin: 0;\n}\n\n.dialog-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n padding: 20px 24px;\n}\n\n.loading-container[_ngcontent-%COMP%], .error-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 200px;\n flex-direction: column;\n gap: 12px;\n}\n\n.error-container[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.error-container[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n margin-bottom: 8px;\n}\n\n.preferences-panels[_ngcontent-%COMP%] {\n display: flex;\n gap: 20px;\n height: 100%;\n}\n\n.panel[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n\n.panel[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.panel[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 8px;\n color: var(--mj-text-muted);\n}\n\n.dashboard-list[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 8px;\n}\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100px;\n color: var(--mj-text-muted);\n font-style: italic;\n flex-direction: column;\n gap: 8px;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n opacity: 0.5;\n}\n\n.dashboard-item[_ngcontent-%COMP%] {\n margin-bottom: 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n transition: all 0.2s ease;\n cursor: move;\n}\n\n.dashboard-item[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.dashboard-item.cdk-drag-preview[_ngcontent-%COMP%] {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n transform: rotate(2deg);\n}\n\n.dashboard-item.cdk-drag-placeholder[_ngcontent-%COMP%] {\n opacity: 0.3;\n border-style: dashed;\n}\n\n.dashboard-item-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 12px;\n gap: 12px;\n}\n\n.drag-handle[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n cursor: move;\n font-size: 14px;\n}\n\n.order-number[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: var(--mj-brand-primary);\n color: white;\n border-radius: 50%;\n font-size: 12px;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n.dashboard-info[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.dashboard-name[_ngcontent-%COMP%] {\n font-weight: 500;\n color: var(--mj-text-primary);\n font-size: 14px;\n}\n\n.dashboard-description[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n line-height: 1.3;\n}\n\n.add-button[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: var(--mj-status-success);\n border-radius: 4px;\n transition: background-color 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n opacity: 0.7;\n}\n\n.add-button[_ngcontent-%COMP%]:hover {\n background-color: color-mix(in srgb, var(--mj-status-success) 10%, transparent);\n opacity: 1;\n}\n\n.remove-button[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: var(--mj-status-error);\n border-radius: 4px;\n transition: background-color 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n}\n\n.remove-button[_ngcontent-%COMP%]:hover {\n background-color: color-mix(in srgb, var(--mj-status-error) 10%, transparent);\n}\n\n.cdk-drop-list-dragging[_ngcontent-%COMP%] .dashboard-item[_ngcontent-%COMP%]:not(.cdk-drag-placeholder) {\n transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\n}\n\n.dialog-footer[_ngcontent-%COMP%] {\n padding: 16px 24px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n background: var(--mj-bg-surface-card);\n}\n\n.btn[_ngcontent-%COMP%] {\n padding: 8px 16px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n border: 1px solid transparent;\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-color: var(--mj-text-muted);\n color: var(--mj-text-muted);\n}\n\n.btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-text-muted);\n color: white;\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: white;\n border-color: var(--mj-brand-primary);\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n}\n\n\n\n@media (max-width: 768px) {\n .dashboard-preferences-dialog[_ngcontent-%COMP%] {\n width: 95vw;\n max-height: 90vh;\n }\n\n .preferences-panels[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 16px;\n }\n\n .panel[_ngcontent-%COMP%] {\n min-height: 200px;\n }\n\n .dashboard-list[_ngcontent-%COMP%] {\n min-height: 150px;\n }\n}"] });
550
+ } }, dependencies: [i1.DefaultValueAccessor, i1.RadioControlValueAccessor, i1.NgControlStatus, i1.NgModel, i2.CdkDropList, i2.CdkDrag, i3.LoadingComponent, i4.MJDialogComponent, i4.MJDialogActionsComponent, i4.MJEmptyStateComponent], styles: [".dashboard-preferences-dialog[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.dialog-header[_ngcontent-%COMP%] {\n padding: 20px 24px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.dialog-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.dialog-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 8px;\n color: var(--mj-text-secondary);\n}\n\n.scope-indicator[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.scope-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 6px;\n}\n\n.preference-mode-selector[_ngcontent-%COMP%] {\n margin-top: 12px;\n display: flex;\n gap: 20px;\n}\n\n.preference-mode-selector[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.preference-mode-selector[_ngcontent-%COMP%] input[type=\"radio\"][_ngcontent-%COMP%] {\n margin: 0;\n}\n\n.dialog-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n padding: 20px 24px;\n}\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 200px;\n flex-direction: column;\n gap: 12px;\n}\n\n.preferences-panels[_ngcontent-%COMP%] {\n display: flex;\n gap: 20px;\n height: 100%;\n}\n\n.panel[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n\n.panel[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.panel[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n margin-right: 8px;\n color: var(--mj-text-muted);\n}\n\n.dashboard-list[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 8px;\n}\n\n.dashboard-item[_ngcontent-%COMP%] {\n margin-bottom: 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n transition: all 0.2s ease;\n cursor: move;\n}\n\n.dashboard-item[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.dashboard-item.cdk-drag-preview[_ngcontent-%COMP%] {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n transform: rotate(2deg);\n}\n\n.dashboard-item.cdk-drag-placeholder[_ngcontent-%COMP%] {\n opacity: 0.3;\n border-style: dashed;\n}\n\n.dashboard-item-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 12px;\n gap: 12px;\n}\n\n.drag-handle[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n cursor: move;\n font-size: 14px;\n}\n\n.order-number[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: var(--mj-brand-primary);\n color: white;\n border-radius: 50%;\n font-size: 12px;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n.dashboard-info[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.dashboard-name[_ngcontent-%COMP%] {\n font-weight: 500;\n color: var(--mj-text-primary);\n font-size: 14px;\n}\n\n.dashboard-description[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n line-height: 1.3;\n}\n\n.add-button[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: var(--mj-status-success);\n border-radius: 4px;\n transition: background-color 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n opacity: 0.7;\n}\n\n.add-button[_ngcontent-%COMP%]:hover {\n background-color: color-mix(in srgb, var(--mj-status-success) 10%, transparent);\n opacity: 1;\n}\n\n.remove-button[_ngcontent-%COMP%] {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: var(--mj-status-error);\n border-radius: 4px;\n transition: background-color 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n}\n\n.remove-button[_ngcontent-%COMP%]:hover {\n background-color: color-mix(in srgb, var(--mj-status-error) 10%, transparent);\n}\n\n.cdk-drop-list-dragging[_ngcontent-%COMP%] .dashboard-item[_ngcontent-%COMP%]:not(.cdk-drag-placeholder) {\n transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\n}\n\n.dialog-footer[_ngcontent-%COMP%] {\n padding: 16px 24px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n background: var(--mj-bg-surface-card);\n}\n\n.btn[_ngcontent-%COMP%] {\n padding: 8px 16px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n border: 1px solid transparent;\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-color: var(--mj-text-muted);\n color: var(--mj-text-muted);\n}\n\n.btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-text-muted);\n color: white;\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: white;\n border-color: var(--mj-brand-primary);\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n}\n\n\n\n@media (max-width: 768px) {\n .dashboard-preferences-dialog[_ngcontent-%COMP%] {\n width: 95vw;\n max-height: 90vh;\n }\n\n .preferences-panels[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 16px;\n }\n\n .panel[_ngcontent-%COMP%] {\n min-height: 200px;\n }\n\n .dashboard-list[_ngcontent-%COMP%] {\n min-height: 150px;\n }\n}"] });
561
551
  }
562
552
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DashboardPreferencesDialogComponent, [{
563
553
  type: Component,
564
- args: [{ standalone: false, selector: 'mj-dashboard-preferences-dialog', template: "<mj-dialog [Visible]=\"true\" Title=\"Dashboard Preferences\"\n [Width]=\"800\"\n [Height]=\"600\"\n [MinWidth]=\"600\"\n (Close)=\"onCancel()\">\n<div class=\"dashboard-preferences-dialog\">\n <div class=\"dialog-header\">\n <h3><i class=\"fa-solid fa-sliders\"></i> Dashboard Preferences</h3>\n <p class=\"scope-indicator\">\n @if (scope === 'Global') {\n <i class=\"fa-solid fa-globe\"></i> Global Scope\n } @else {\n <i class=\"fa-solid fa-layer-group\"></i> Application: {{ applicationName }}\n }\n </p>\n @if (isSysAdmin && scope === 'Global') {\n <div class=\"preference-mode-selector\">\n <label>\n <input type=\"radio\"\n name=\"preferenceMode\"\n value=\"personal\"\n [(ngModel)]=\"preferenceMode\"\n (change)=\"onPreferenceModeChange()\">\n Personal Preferences\n </label>\n <label>\n <input type=\"radio\"\n name=\"preferenceMode\"\n value=\"system\"\n [(ngModel)]=\"preferenceMode\"\n (change)=\"onPreferenceModeChange()\">\n System Defaults\n </label>\n </div>\n }\n </div>\n\n <div class=\"dialog-content\">\n @if (loading) {\n <div class=\"loading-overlay\">\n <mj-loading text=\"Loading preferences...\" size=\"large\"></mj-loading>\n </div>\n }\n\n @if (error) {\n <div class=\"error-container\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n {{ error }}\n </div>\n }\n\n @if (!loading && !error) {\n <div class=\"preferences-panels\">\n <!-- Available Dashboards Panel -->\n <div class=\"panel available-panel\">\n <h4><i class=\"fa-solid fa-list\"></i> Available Dashboards</h4>\n <div class=\"dashboard-list\"\n cdkDropList\n #availableList=\"cdkDropList\"\n [cdkDropListData]=\"availableDashboards\"\n [cdkDropListConnectedTo]=\"[configuredList]\"\n (cdkDropListDropped)=\"onDrop($event)\">\n\n @if (availableDashboards.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-info-circle\"></i>\n All dashboards are configured\n </div>\n }\n\n @for (dashboard of availableDashboards; track dashboard.ID) {\n <div class=\"dashboard-item available-item\"\n cdkDrag\n [cdkDragData]=\"dashboard\">\n <div class=\"dashboard-item-content\">\n <i class=\"fa-solid fa-grip-vertical drag-handle\"></i>\n <div class=\"dashboard-info\">\n <span class=\"dashboard-name\">{{ dashboard.Name }}</span>\n @if (dashboard.Description) {\n <span class=\"dashboard-description\">{{ dashboard.Description }}</span>\n }\n </div>\n <button type=\"button\"\n class=\"add-button\"\n (click)=\"addDashboard(dashboard)\"\n title=\"Add to configured dashboards\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Configured Dashboards Panel -->\n <div class=\"panel configured-panel\">\n <h4><i class=\"fa-solid fa-list-ol\"></i> Configured Dashboards</h4>\n <div class=\"dashboard-list\"\n cdkDropList\n #configuredList=\"cdkDropList\"\n [cdkDropListData]=\"configuredDashboards\"\n [cdkDropListConnectedTo]=\"[availableList]\"\n (cdkDropListDropped)=\"onDrop($event)\">\n\n @if (configuredDashboards.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-info-circle\"></i>\n No dashboards configured\n </div>\n }\n\n @for (dashboard of configuredDashboards; track dashboard.ID; let i = $index) {\n <div class=\"dashboard-item configured-item\"\n cdkDrag\n [cdkDragData]=\"dashboard\">\n <div class=\"dashboard-item-content\">\n <i class=\"fa-solid fa-grip-vertical drag-handle\"></i>\n <span class=\"order-number\">{{ i + 1 }}</span>\n <div class=\"dashboard-info\">\n <span class=\"dashboard-name\">{{ dashboard.Name }}</span>\n @if (dashboard.Description) {\n <span class=\"dashboard-description\">{{ dashboard.Description }}</span>\n }\n </div>\n <button type=\"button\"\n class=\"remove-button\"\n (click)=\"removeDashboard(dashboard)\"\n title=\"Remove from configured dashboards\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n\n <mj-dialog-actions>\n <button type=\"button\"\n class=\"btn btn-secondary\"\n (click)=\"onCancel()\">\n <i class=\"fa-solid fa-times\"></i> Cancel\n </button>\n <button type=\"button\"\n class=\"btn btn-primary\"\n [disabled]=\"!hasChanges || saving\"\n (click)=\"onSave()\">\n @if (saving) {\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n Saving...\n } @else {\n <i class=\"fa-solid fa-check\"></i> Save Changes\n }\n </button>\n </mj-dialog-actions>\n</div>\n</mj-dialog>\n", styles: [".dashboard-preferences-dialog {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.dialog-header {\n padding: 20px 24px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.dialog-header h3 {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.dialog-header h3 i {\n margin-right: 8px;\n color: var(--mj-text-secondary);\n}\n\n.scope-indicator {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.scope-indicator i {\n margin-right: 6px;\n}\n\n.preference-mode-selector {\n margin-top: 12px;\n display: flex;\n gap: 20px;\n}\n\n.preference-mode-selector label {\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.preference-mode-selector input[type=\"radio\"] {\n margin: 0;\n}\n\n.dialog-content {\n flex: 1;\n overflow: hidden;\n padding: 20px 24px;\n}\n\n.loading-container, .error-container {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 200px;\n flex-direction: column;\n gap: 12px;\n}\n\n.error-container {\n color: var(--mj-status-error);\n}\n\n.error-container i {\n font-size: 24px;\n margin-bottom: 8px;\n}\n\n.preferences-panels {\n display: flex;\n gap: 20px;\n height: 100%;\n}\n\n.panel {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n\n.panel h4 {\n margin: 0;\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.panel h4 i {\n margin-right: 8px;\n color: var(--mj-text-muted);\n}\n\n.dashboard-list {\n flex: 1;\n overflow-y: auto;\n padding: 8px;\n}\n\n.empty-state {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100px;\n color: var(--mj-text-muted);\n font-style: italic;\n flex-direction: column;\n gap: 8px;\n}\n\n.empty-state i {\n font-size: 24px;\n opacity: 0.5;\n}\n\n.dashboard-item {\n margin-bottom: 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n transition: all 0.2s ease;\n cursor: move;\n}\n\n.dashboard-item:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.dashboard-item.cdk-drag-preview {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n transform: rotate(2deg);\n}\n\n.dashboard-item.cdk-drag-placeholder {\n opacity: 0.3;\n border-style: dashed;\n}\n\n.dashboard-item-content {\n display: flex;\n align-items: center;\n padding: 12px;\n gap: 12px;\n}\n\n.drag-handle {\n color: var(--mj-text-disabled);\n cursor: move;\n font-size: 14px;\n}\n\n.order-number {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: var(--mj-brand-primary);\n color: white;\n border-radius: 50%;\n font-size: 12px;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n.dashboard-info {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.dashboard-name {\n font-weight: 500;\n color: var(--mj-text-primary);\n font-size: 14px;\n}\n\n.dashboard-description {\n font-size: 12px;\n color: var(--mj-text-muted);\n line-height: 1.3;\n}\n\n.add-button {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: var(--mj-status-success);\n border-radius: 4px;\n transition: background-color 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n opacity: 0.7;\n}\n\n.add-button:hover {\n background-color: color-mix(in srgb, var(--mj-status-success) 10%, transparent);\n opacity: 1;\n}\n\n.remove-button {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: var(--mj-status-error);\n border-radius: 4px;\n transition: background-color 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n}\n\n.remove-button:hover {\n background-color: color-mix(in srgb, var(--mj-status-error) 10%, transparent);\n}\n\n.cdk-drop-list-dragging .dashboard-item:not(.cdk-drag-placeholder) {\n transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\n}\n\n.dialog-footer {\n padding: 16px 24px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n background: var(--mj-bg-surface-card);\n}\n\n.btn {\n padding: 8px 16px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n border: 1px solid transparent;\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn-secondary {\n background: var(--mj-bg-surface);\n border-color: var(--mj-text-muted);\n color: var(--mj-text-muted);\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: var(--mj-text-muted);\n color: white;\n}\n\n.btn-primary {\n background: var(--mj-brand-primary);\n color: white;\n border-color: var(--mj-brand-primary);\n}\n\n.btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n}\n\n/* Responsive design */\n@media (max-width: 768px) {\n .dashboard-preferences-dialog {\n width: 95vw;\n max-height: 90vh;\n }\n\n .preferences-panels {\n flex-direction: column;\n gap: 16px;\n }\n\n .panel {\n min-height: 200px;\n }\n\n .dashboard-list {\n min-height: 150px;\n }\n}\n"] }]
554
+ args: [{ standalone: false, selector: 'mj-dashboard-preferences-dialog', template: "<mj-dialog [Visible]=\"true\" Title=\"Dashboard Preferences\"\n [Width]=\"800\"\n [Height]=\"600\"\n [MinWidth]=\"600\"\n (Close)=\"onCancel()\">\n<div class=\"dashboard-preferences-dialog\">\n <div class=\"dialog-header\">\n <h3><i class=\"fa-solid fa-sliders\"></i> Dashboard Preferences</h3>\n <p class=\"scope-indicator\">\n @if (scope === 'Global') {\n <i class=\"fa-solid fa-globe\"></i> Global Scope\n } @else {\n <i class=\"fa-solid fa-layer-group\"></i> Application: {{ applicationName }}\n }\n </p>\n @if (isSysAdmin && scope === 'Global') {\n <div class=\"preference-mode-selector\">\n <label>\n <input type=\"radio\"\n name=\"preferenceMode\"\n value=\"personal\"\n [(ngModel)]=\"preferenceMode\"\n (change)=\"onPreferenceModeChange()\">\n Personal Preferences\n </label>\n <label>\n <input type=\"radio\"\n name=\"preferenceMode\"\n value=\"system\"\n [(ngModel)]=\"preferenceMode\"\n (change)=\"onPreferenceModeChange()\">\n System Defaults\n </label>\n </div>\n }\n </div>\n\n <div class=\"dialog-content\">\n @if (loading) {\n <div class=\"loading-overlay\">\n <mj-loading text=\"Loading preferences...\" size=\"large\"></mj-loading>\n </div>\n }\n\n @if (error) {\n <mj-empty-state\n Variant=\"error\"\n Size=\"compact\"\n Icon=\"fa-solid fa-triangle-exclamation\"\n [Title]=\"error\" />\n }\n\n @if (!loading && !error) {\n <div class=\"preferences-panels\">\n <!-- Available Dashboards Panel -->\n <div class=\"panel available-panel\">\n <h4><i class=\"fa-solid fa-list\"></i> Available Dashboards</h4>\n <div class=\"dashboard-list\"\n cdkDropList\n #availableList=\"cdkDropList\"\n [cdkDropListData]=\"availableDashboards\"\n [cdkDropListConnectedTo]=\"[configuredList]\"\n (cdkDropListDropped)=\"onDrop($event)\">\n\n @if (availableDashboards.length === 0) {\n <mj-empty-state\n Variant=\"success\"\n Size=\"compact\"\n Icon=\"fa-solid fa-circle-check\"\n Title=\"All dashboards are configured\" />\n }\n\n @for (dashboard of availableDashboards; track dashboard.ID) {\n <div class=\"dashboard-item available-item\"\n cdkDrag\n [cdkDragData]=\"dashboard\">\n <div class=\"dashboard-item-content\">\n <i class=\"fa-solid fa-grip-vertical drag-handle\"></i>\n <div class=\"dashboard-info\">\n <span class=\"dashboard-name\">{{ dashboard.Name }}</span>\n @if (dashboard.Description) {\n <span class=\"dashboard-description\">{{ dashboard.Description }}</span>\n }\n </div>\n <button type=\"button\"\n class=\"add-button\"\n (click)=\"addDashboard(dashboard)\"\n title=\"Add to configured dashboards\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Configured Dashboards Panel -->\n <div class=\"panel configured-panel\">\n <h4><i class=\"fa-solid fa-list-ol\"></i> Configured Dashboards</h4>\n <div class=\"dashboard-list\"\n cdkDropList\n #configuredList=\"cdkDropList\"\n [cdkDropListData]=\"configuredDashboards\"\n [cdkDropListConnectedTo]=\"[availableList]\"\n (cdkDropListDropped)=\"onDrop($event)\">\n\n @if (configuredDashboards.length === 0) {\n <mj-empty-state\n Size=\"compact\"\n Icon=\"fa-solid fa-circle-info\"\n Title=\"No dashboards configured\" />\n }\n\n @for (dashboard of configuredDashboards; track dashboard.ID; let i = $index) {\n <div class=\"dashboard-item configured-item\"\n cdkDrag\n [cdkDragData]=\"dashboard\">\n <div class=\"dashboard-item-content\">\n <i class=\"fa-solid fa-grip-vertical drag-handle\"></i>\n <span class=\"order-number\">{{ i + 1 }}</span>\n <div class=\"dashboard-info\">\n <span class=\"dashboard-name\">{{ dashboard.Name }}</span>\n @if (dashboard.Description) {\n <span class=\"dashboard-description\">{{ dashboard.Description }}</span>\n }\n </div>\n <button type=\"button\"\n class=\"remove-button\"\n (click)=\"removeDashboard(dashboard)\"\n title=\"Remove from configured dashboards\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n\n <mj-dialog-actions>\n <button type=\"button\"\n class=\"btn btn-secondary\"\n (click)=\"onCancel()\">\n <i class=\"fa-solid fa-times\"></i> Cancel\n </button>\n <button type=\"button\"\n class=\"btn btn-primary\"\n [disabled]=\"!hasChanges || saving\"\n (click)=\"onSave()\">\n @if (saving) {\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n Saving...\n } @else {\n <i class=\"fa-solid fa-check\"></i> Save Changes\n }\n </button>\n </mj-dialog-actions>\n</div>\n</mj-dialog>\n", styles: [".dashboard-preferences-dialog {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.dialog-header {\n padding: 20px 24px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.dialog-header h3 {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.dialog-header h3 i {\n margin-right: 8px;\n color: var(--mj-text-secondary);\n}\n\n.scope-indicator {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.scope-indicator i {\n margin-right: 6px;\n}\n\n.preference-mode-selector {\n margin-top: 12px;\n display: flex;\n gap: 20px;\n}\n\n.preference-mode-selector label {\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.preference-mode-selector input[type=\"radio\"] {\n margin: 0;\n}\n\n.dialog-content {\n flex: 1;\n overflow: hidden;\n padding: 20px 24px;\n}\n\n.loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 200px;\n flex-direction: column;\n gap: 12px;\n}\n\n.preferences-panels {\n display: flex;\n gap: 20px;\n height: 100%;\n}\n\n.panel {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n\n.panel h4 {\n margin: 0;\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.panel h4 i {\n margin-right: 8px;\n color: var(--mj-text-muted);\n}\n\n.dashboard-list {\n flex: 1;\n overflow-y: auto;\n padding: 8px;\n}\n\n.dashboard-item {\n margin-bottom: 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n transition: all 0.2s ease;\n cursor: move;\n}\n\n.dashboard-item:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.dashboard-item.cdk-drag-preview {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n transform: rotate(2deg);\n}\n\n.dashboard-item.cdk-drag-placeholder {\n opacity: 0.3;\n border-style: dashed;\n}\n\n.dashboard-item-content {\n display: flex;\n align-items: center;\n padding: 12px;\n gap: 12px;\n}\n\n.drag-handle {\n color: var(--mj-text-disabled);\n cursor: move;\n font-size: 14px;\n}\n\n.order-number {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: var(--mj-brand-primary);\n color: white;\n border-radius: 50%;\n font-size: 12px;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n.dashboard-info {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.dashboard-name {\n font-weight: 500;\n color: var(--mj-text-primary);\n font-size: 14px;\n}\n\n.dashboard-description {\n font-size: 12px;\n color: var(--mj-text-muted);\n line-height: 1.3;\n}\n\n.add-button {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: var(--mj-status-success);\n border-radius: 4px;\n transition: background-color 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n opacity: 0.7;\n}\n\n.add-button:hover {\n background-color: color-mix(in srgb, var(--mj-status-success) 10%, transparent);\n opacity: 1;\n}\n\n.remove-button {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: var(--mj-status-error);\n border-radius: 4px;\n transition: background-color 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n}\n\n.remove-button:hover {\n background-color: color-mix(in srgb, var(--mj-status-error) 10%, transparent);\n}\n\n.cdk-drop-list-dragging .dashboard-item:not(.cdk-drag-placeholder) {\n transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);\n}\n\n.dialog-footer {\n padding: 16px 24px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n background: var(--mj-bg-surface-card);\n}\n\n.btn {\n padding: 8px 16px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n border: 1px solid transparent;\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn-secondary {\n background: var(--mj-bg-surface);\n border-color: var(--mj-text-muted);\n color: var(--mj-text-muted);\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: var(--mj-text-muted);\n color: white;\n}\n\n.btn-primary {\n background: var(--mj-brand-primary);\n color: white;\n border-color: var(--mj-brand-primary);\n}\n\n.btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n}\n\n/* Responsive design */\n@media (max-width: 768px) {\n .dashboard-preferences-dialog {\n width: 95vw;\n max-height: 90vh;\n }\n\n .preferences-panels {\n flex-direction: column;\n gap: 16px;\n }\n\n .panel {\n min-height: 200px;\n }\n\n .dashboard-list {\n min-height: 150px;\n }\n}\n"] }]
565
555
  }], null, { applicationId: [{
566
556
  type: Input
567
557
  }], scope: [{