@memberjunction/ng-tasks 5.4.1 → 5.5.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.
@@ -1,4 +1,4 @@
1
1
 
2
- > @memberjunction/ng-tasks@5.4.1 build
2
+ > @memberjunction/ng-tasks@5.5.0 build
3
3
  > ngc
4
4
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @memberjunction/ng-tasks
2
2
 
3
+ ## 5.5.0
4
+
5
+ ### Patch Changes
6
+
7
+ - df2457c: no migration, just small code changes
8
+ - Updated dependencies [2b1d842]
9
+ - Updated dependencies [a1648c5]
10
+ - Updated dependencies [ee9f788]
11
+ - Updated dependencies [df2457c]
12
+ - @memberjunction/core@5.5.0
13
+ - @memberjunction/core-entities@5.5.0
14
+ - @memberjunction/ai-engine-base@5.5.0
15
+ - @memberjunction/ai-core-plus@5.5.0
16
+
3
17
  ## 5.4.1
4
18
 
5
19
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"gantt-task-viewer.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/gantt-task-viewer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAa,SAAS,EAAgB,MAAM,eAAe,CAAC;AAEjJ,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;;AAIrF;;GAEG;AACH,qBA8Ga,wBAAyB,YAAW,SAAS,EAAE,aAAa,EAAE,SAAS;IACzE,KAAK,EAAE,YAAY,EAAE,CAAM;IAC3B,gBAAgB,EAAE,sBAAsB,EAAE,CAAM;IAChD,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,WAAW,6BAAoC;IAC/C,gBAAgB;oBAAkC,MAAM;kBAAY,MAAM;OAAM;IAE1C,cAAc,EAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IAErF,YAAY,EAAE,YAAY,GAAG,IAAI,CAAQ;IACzC,gBAAgB,EAAE,MAAM,CAAO;IAEtC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,gBAAgB,CAAK;IAE7B,eAAe;IAWf,WAAW;IAgBX,WAAW;IAOX,OAAO,CAAC,SAAS;IAgFjB,OAAO,CAAC,eAAe;IAgCvB,OAAO,CAAC,oBAAoB;IA6J5B,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,mBAAmB;IAOpB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI;IAIhD,gBAAgB,IAAI,IAAI;IAIxB,kBAAkB,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAIzE,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAQ3C,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAWrC,UAAU,IAAI,IAAI;IAYlB,OAAO,CAAC,sBAAsB;yCA3XnB,wBAAwB;2CAAxB,wBAAwB;CA0ZpC"}
1
+ {"version":3,"file":"gantt-task-viewer.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/gantt-task-viewer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAa,SAAS,EAAgB,MAAM,eAAe,CAAC;AAEjJ,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;;AAKrF;;GAEG;AACH,qBA8Ga,wBAAyB,YAAW,SAAS,EAAE,aAAa,EAAE,SAAS;IACzE,KAAK,EAAE,YAAY,EAAE,CAAM;IAC3B,gBAAgB,EAAE,sBAAsB,EAAE,CAAM;IAChD,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,WAAW,6BAAoC;IAC/C,gBAAgB;oBAAkC,MAAM;kBAAY,MAAM;OAAM;IAE1C,cAAc,EAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IAErF,YAAY,EAAE,YAAY,GAAG,IAAI,CAAQ;IACzC,gBAAgB,EAAE,MAAM,CAAO;IAEtC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,gBAAgB,CAAK;IAE7B,eAAe;IAWf,WAAW;IAgBX,WAAW;IAOX,OAAO,CAAC,SAAS;IAgFjB,OAAO,CAAC,eAAe;IAgCvB,OAAO,CAAC,oBAAoB;IA6J5B,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,mBAAmB;IAOpB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI;IAIhD,gBAAgB,IAAI,IAAI;IAIxB,kBAAkB,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAIzE,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAQ3C,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAWrC,UAAU,IAAI,IAAI;IAYlB,OAAO,CAAC,sBAAsB;yCA3XnB,wBAAwB;2CAAxB,wBAAwB;CA0ZpC"}
@@ -1,6 +1,7 @@
1
1
  import { Component, Input, Output, EventEmitter, ViewChild, HostListener } from '@angular/core';
2
2
  import { gantt } from 'dhtmlx-gantt';
3
3
  import { TaskDetailPanelComponent } from './task-detail-panel.component';
4
+ import { UUIDsEqual } from '@memberjunction/global';
4
5
  import * as i0 from "@angular/core";
5
6
  const _c0 = ["ganttContainer"];
6
7
  function GanttTaskViewerComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
@@ -131,7 +132,7 @@ export class GanttTaskViewerComponent {
131
132
  this.ganttInitialized = true;
132
133
  // Attach click event
133
134
  gantt.attachEvent('onTaskClick', (id) => {
134
- const originalTask = this.tasks.find(t => t.ID === id);
135
+ const originalTask = this.tasks.find(t => UUIDsEqual(t.ID, id));
135
136
  if (originalTask) {
136
137
  this.selectedTask = originalTask;
137
138
  this.taskClicked.emit(originalTask);
@@ -379,7 +380,7 @@ export class GanttTaskViewerComponent {
379
380
  if (rootTask) {
380
381
  gantt.selectTask(rootTask.id);
381
382
  // Trigger task click event to open detail panel
382
- const originalTask = this.tasks.find(t => t.ID === rootTask.id);
383
+ const originalTask = this.tasks.find(t => UUIDsEqual(t.ID, rootTask.id));
383
384
  if (originalTask) {
384
385
  this.selectedTask = originalTask;
385
386
  this.taskClicked.emit(originalTask);
@@ -463,5 +464,5 @@ export class GanttTaskViewerComponent {
463
464
  type: HostListener,
464
465
  args: ['document:mouseup']
465
466
  }] }); })();
466
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(GanttTaskViewerComponent, { className: "GanttTaskViewerComponent", filePath: "src/lib/components/gantt-task-viewer.component.ts", lineNumber: 120 }); })();
467
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(GanttTaskViewerComponent, { className: "GanttTaskViewerComponent", filePath: "src/lib/components/gantt-task-viewer.component.ts", lineNumber: 121 }); })();
467
468
  //# sourceMappingURL=gantt-task-viewer.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gantt-task-viewer.component.js","sourceRoot":"","sources":["../../../src/lib/components/gantt-task-viewer.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnChanges, AfterViewInit, ElementRef, ViewChild, OnDestroy, HostListener } from '@angular/core';\n\nimport { MJTaskEntity, MJTaskDependencyEntity } from '@memberjunction/core-entities';\nimport { gantt } from 'dhtmlx-gantt';\nimport { TaskDetailPanelComponent } from './task-detail-panel.component';\n\n/**\n * Gantt chart view for tasks using DHTMLX Gantt\n */\n@Component({\n selector: 'mj-gantt-task-viewer',\n standalone: true,\n imports: [TaskDetailPanelComponent],\n template: `\n <div class=\"gantt-task-viewer\">\n @if (!tasks || tasks.length === 0) {\n <div class=\"no-tasks\">\n <i class=\"fas fa-chart-gantt\"></i>\n <p>No tasks to display in Gantt view</p>\n </div>\n }\n \n @if (tasks && tasks.length > 0) {\n <div class=\"gantt-layout\">\n <div #ganttContainer class=\"gantt-container\"></div>\n @if (selectedTask) {\n <div class=\"gantt-resizer\"\n (mousedown)=\"startResize($event)\"></div>\n }\n @if (selectedTask) {\n <div class=\"task-detail-panel\" [style.width.px]=\"detailPanelWidth\">\n <mj-task-detail-panel\n [task]=\"selectedTask\"\n [agentRunId]=\"getAgentRunId(selectedTask)\"\n (closePanel)=\"closeDetailPanel()\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\">\n </mj-task-detail-panel>\n </div>\n }\n </div>\n }\n </div>\n `,\n styles: [`\n .gantt-task-viewer {\n height: 100%;\n background: white;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .gantt-layout {\n display: flex;\n height: 600px;\n position: relative;\n }\n\n .gantt-container {\n flex: 1;\n min-width: 400px;\n height: 100%;\n position: relative;\n }\n\n .gantt-resizer {\n width: 4px;\n background: #E5E7EB;\n cursor: col-resize;\n flex-shrink: 0;\n transition: background 0.2s;\n }\n\n .gantt-resizer:hover {\n background: #3B82F6;\n }\n\n .task-detail-panel {\n min-width: 300px;\n max-width: 600px;\n height: 100%;\n border-left: 1px solid #E5E7EB;\n flex-shrink: 0;\n }\n\n /* Override DHTMLX Gantt default styles */\n :host ::ng-deep .gantt_container {\n font-family: inherit;\n font-size: 13px;\n }\n\n :host ::ng-deep .gantt_grid_scale,\n :host ::ng-deep .gantt_task_scale {\n background: #F9FAFB;\n border-bottom: 2px solid #E5E7EB;\n }\n\n :host ::ng-deep .gantt_task .gantt_task_content {\n font-weight: 500;\n }\n\n .no-tasks {\n text-align: center;\n padding: 80px 20px;\n color: #9CA3AF;\n }\n\n .no-tasks i {\n font-size: 64px;\n opacity: 0.3;\n margin-bottom: 16px;\n }\n\n .no-tasks p {\n margin: 0;\n font-size: 14px;\n }\n `]\n})\nexport class GanttTaskViewerComponent implements OnChanges, AfterViewInit, OnDestroy {\n @Input() tasks: MJTaskEntity[] = [];\n @Input() taskDependencies: MJTaskDependencyEntity[] = [];\n @Input() agentRunMap?: Map<string, string>; // Maps TaskID -> AgentRunID\n @Output() taskClicked = new EventEmitter<MJTaskEntity>();\n @Output() openEntityRecord = new EventEmitter<{ entityName: string; recordId: string }>();\n\n @ViewChild('ganttContainer', { static: false }) ganttContainer!: ElementRef<HTMLDivElement>;\n\n public selectedTask: MJTaskEntity | null = null;\n public detailPanelWidth: number = 400;\n\n private ganttInitialized = false;\n private isResizing = false;\n private resizeStartX = 0;\n private resizeStartWidth = 0;\n\n ngAfterViewInit() {\n console.log('🔧 ngAfterViewInit called', {\n taskCount: this.tasks?.length || 0,\n hasContainer: !!this.ganttContainer\n });\n\n if (this.tasks && this.tasks.length > 0 && this.ganttContainer) {\n this.initGantt();\n }\n }\n\n ngOnChanges() {\n console.log('🔄 ngOnChanges called', {\n initialized: this.ganttInitialized,\n hasContainer: !!this.ganttContainer,\n taskCount: this.tasks?.length || 0\n });\n\n if (this.ganttInitialized && this.ganttContainer) {\n this.updateGanttData();\n } else if (!this.ganttInitialized && this.ganttContainer && this.tasks && this.tasks.length > 0) {\n // Initialize if we have container and tasks but haven't initialized yet\n console.log('🎨 Late initialization - gantt not initialized but container and tasks available');\n this.initGantt();\n }\n }\n\n ngOnDestroy() {\n if (this.ganttInitialized) {\n gantt.clearAll();\n this.ganttInitialized = false;\n }\n }\n\n private initGantt(): void {\n try {\n console.log('🎨 Initializing DHTMLX Gantt');\n\n // IMPORTANT: Clear any previous configuration\n gantt.clearAll();\n\n // Configure Gantt layout and appearance\n gantt.config.date_format = '%Y-%m-%d %H:%i';\n gantt.config.scale_unit = 'day';\n gantt.config.date_scale = '%d %M';\n gantt.config.subscales = [];\n gantt.config.show_progress = true;\n gantt.config.show_links = true;\n gantt.config.auto_types = true;\n gantt.config.readonly = true; // Read-only for now\n gantt.config.fit_tasks = true; // Auto-fit timeline to tasks\n\n // Disable auto-scheduling - we calculate dates ourselves based on dependencies\n gantt.config.auto_scheduling = false;\n\n // Grid configuration\n gantt.config.grid_width = 350;\n gantt.config.row_height = 36;\n gantt.config.scale_height = 0; // Hide date scale - dates are just for positioning\n\n // Layout configuration - ensure timeline is visible\n gantt.config.layout = {\n css: \"gantt_container\",\n rows: [\n {\n cols: [\n { view: \"grid\", group: \"grids\", scrollY: \"scrollVer\" },\n { resizer: true, width: 1 },\n { view: \"timeline\", scrollX: \"scrollHor\", scrollY: \"scrollVer\" },\n { view: \"scrollbar\", id: \"scrollVer\", group: \"vertical\" }\n ]\n },\n { view: \"scrollbar\", id: \"scrollHor\", group: \"horizontal\" }\n ]\n };\n\n // Column configuration - only show task names, hide dates\n gantt.config.columns = [\n { name: 'text', label: 'Task name', tree: true, width: '*' }\n ];\n\n // Initialize Gantt in the container\n gantt.init(this.ganttContainer.nativeElement);\n this.ganttInitialized = true;\n\n // Attach click event\n gantt.attachEvent('onTaskClick', (id: string) => {\n const originalTask = this.tasks.find(t => t.ID === id);\n if (originalTask) {\n this.selectedTask = originalTask;\n this.taskClicked.emit(originalTask);\n }\n return true;\n });\n\n // Load data\n this.updateGanttData();\n\n // Force resize after data load to ensure proper rendering\n setTimeout(() => {\n gantt.setSizes();\n }, 0);\n\n // Expand and select after render completes\n setTimeout(() => {\n this.expandAllAndSelectRoot();\n }, 100);\n\n console.log('✅ DHTMLX Gantt initialized successfully');\n } catch (error) {\n console.error('❌ Error initializing Gantt:', error);\n }\n }\n\n private updateGanttData(): void {\n if (!this.ganttInitialized) return;\n\n try {\n console.log('📊 Updating Gantt data with', this.tasks.length, 'tasks');\n\n const ganttData = this.convertToGanttFormat(this.tasks);\n gantt.clearAll();\n gantt.parse(ganttData);\n\n // Log final parsed data for debugging\n console.log('📋 Gantt data after parse:', {\n tasks: gantt.getTaskByTime(),\n links: gantt.getLinks()\n });\n\n // Force resize after data update\n setTimeout(() => {\n gantt.setSizes();\n }, 0);\n\n // Expand and select after render completes\n setTimeout(() => {\n this.expandAllAndSelectRoot();\n }, 100);\n\n console.log('✅ Gantt data updated');\n } catch (error) {\n console.error('❌ Error updating Gantt data:', error);\n }\n }\n\n private convertToGanttFormat(tasks: MJTaskEntity[]): { data: any[], links: any[] } {\n const data: any[] = [];\n const links: any[] = [];\n\n console.log('🔍 Converting tasks:', tasks);\n console.log('🔗 Task dependencies:', this.taskDependencies);\n\n // Build a map of task ID to task for quick lookup\n const taskMap = new Map<string, MJTaskEntity>();\n tasks.forEach(t => taskMap.set(t.ID, t));\n\n // Build dependency map: taskId -> array of tasks it depends on\n const dependencyMap = new Map<string, string[]>();\n this.taskDependencies.forEach(dep => {\n if (!dependencyMap.has(dep.TaskID)) {\n dependencyMap.set(dep.TaskID, []);\n }\n dependencyMap.get(dep.TaskID)!.push(dep.DependsOnTaskID);\n });\n\n // Calculate start dates based on dependencies\n const taskStartDates = new Map<string, Date>();\n const baseDate = new Date();\n baseDate.setHours(0, 0, 0, 0);\n\n // Recursive function to calculate start date for a task\n const calculateStartDate = (taskId: string, visited = new Set<string>()): Date => {\n // Prevent circular dependencies\n if (visited.has(taskId)) {\n return new Date(baseDate);\n }\n visited.add(taskId);\n\n // If already calculated, return it\n if (taskStartDates.has(taskId)) {\n return taskStartDates.get(taskId)!;\n }\n\n const task = taskMap.get(taskId);\n if (!task) return new Date(baseDate);\n\n const dependencies = dependencyMap.get(taskId) || [];\n\n if (dependencies.length === 0) {\n // No dependencies - use base date or task's actual start date\n const startDate = task.StartedAt ? new Date(task.StartedAt) : new Date(baseDate);\n taskStartDates.set(taskId, startDate);\n return startDate;\n }\n\n // Has dependencies - start after the latest dependency ends\n let latestEnd = new Date(baseDate);\n for (const depId of dependencies) {\n const depTask = taskMap.get(depId);\n if (depTask) {\n const depStart = calculateStartDate(depId, new Set(visited));\n const depDuration = this.calculateDuration(depTask);\n const depEnd = new Date(depStart);\n depEnd.setDate(depEnd.getDate() + depDuration);\n\n if (depEnd > latestEnd) {\n latestEnd = depEnd;\n }\n }\n }\n\n taskStartDates.set(taskId, latestEnd);\n return latestEnd;\n };\n\n // Calculate start dates for all tasks\n tasks.forEach(task => calculateStartDate(task.ID));\n\n // Calculate min/max dates for timeline display range\n let minDate: Date | null = null;\n let maxDate: Date | null = null;\n\n tasks.forEach(task => {\n const startDate = taskStartDates.get(task.ID);\n if (startDate) {\n const duration = this.calculateDuration(task);\n const endDate = new Date(startDate);\n endDate.setDate(endDate.getDate() + duration);\n\n if (!minDate || startDate < minDate) {\n minDate = startDate;\n }\n if (!maxDate || endDate > maxDate) {\n maxDate = endDate;\n }\n }\n });\n\n // Add 1 day padding before and after\n if (minDate) {\n const paddedStart = new Date(minDate);\n paddedStart.setDate(paddedStart.getDate() - 1);\n gantt.config.start_date = paddedStart;\n }\n if (maxDate) {\n const paddedEnd = new Date(maxDate);\n paddedEnd.setDate(paddedEnd.getDate() + 1);\n gantt.config.end_date = paddedEnd;\n }\n\n // Now create Gantt tasks with calculated dates\n tasks.forEach((task) => {\n console.log('📝 Processing task:', {\n ID: task.ID,\n Name: task.Name,\n ParentID: task.ParentID\n });\n\n // Calculate progress (0-1 scale for DHTMLX)\n let progress = (task.PercentComplete || 0) / 100;\n if (task.Status === 'Complete') {\n progress = 1;\n }\n\n const duration = this.calculateDuration(task);\n const startDate = taskStartDates.get(task.ID) || new Date(baseDate);\n\n const ganttTask: any = {\n id: task.ID,\n text: task.Name || 'Untitled Task',\n start_date: this.formatDateForDHTMLX(startDate),\n duration: duration,\n progress: progress\n };\n\n // Add parent relationship for tree structure (not dependency)\n if (task.ParentID) {\n ganttTask.parent = task.ParentID;\n } else {\n // Root tasks need parent: 0\n ganttTask.parent = 0;\n }\n\n console.log('✅ Created Gantt task:', ganttTask);\n data.push(ganttTask);\n });\n\n // Create links from MJTaskDependencyEntity records\n this.taskDependencies.forEach((dep, index) => {\n links.push({\n id: dep.ID || `link_${index}`,\n source: dep.DependsOnTaskID, // The task being depended on\n target: dep.TaskID, // The task that depends on it\n type: '0' // finish-to-start (DHTMLX type 0)\n });\n console.log(`🔗 Created link: ${dep.DependsOnTaskID} -> ${dep.TaskID}`);\n });\n\n console.log('📊 Final DHTMLX format:', { data, links });\n return { data, links };\n }\n\n private calculateDuration(task: MJTaskEntity): number {\n if (task.StartedAt && task.DueAt) {\n const startDate = new Date(task.StartedAt);\n const endDate = new Date(task.DueAt);\n return Math.max(1, Math.ceil((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24)));\n }\n return 1; // Default to 1 day\n }\n\n private formatDateForDHTMLX(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n return `${year}-${month}-${day} 00:00`;\n }\n\n public getAgentRunId(task: MJTaskEntity): string | null {\n return this.agentRunMap?.get(task.ID) || null;\n }\n\n public closeDetailPanel(): void {\n this.selectedTask = null;\n }\n\n public onOpenEntityRecord(event: { entityName: string; recordId: string }): void {\n this.openEntityRecord.emit(event);\n }\n\n public startResize(event: MouseEvent): void {\n this.isResizing = true;\n this.resizeStartX = event.clientX;\n this.resizeStartWidth = this.detailPanelWidth;\n event.preventDefault();\n }\n\n @HostListener('document:mousemove', ['$event'])\n handleResize(event: MouseEvent): void {\n if (!this.isResizing) return;\n\n const delta = this.resizeStartX - event.clientX;\n const newWidth = this.resizeStartWidth + delta;\n\n // Constrain width between min and max\n this.detailPanelWidth = Math.max(300, Math.min(600, newWidth));\n }\n\n @HostListener('document:mouseup')\n stopResize(): void {\n if (this.isResizing) {\n this.isResizing = false;\n // Resize gantt chart after panel resize completes\n setTimeout(() => {\n if (this.ganttInitialized) {\n gantt.setSizes();\n }\n }, 0);\n }\n }\n\n private expandAllAndSelectRoot(): void {\n try {\n // Expand all tasks\n gantt.eachTask((task: any) => {\n gantt.open(task.id);\n });\n\n // Find and select the root task (task with parent = 0)\n let rootTask: any = null;\n gantt.eachTask((task: any) => {\n if (task.parent === 0 || task.parent === '0') {\n rootTask = task;\n return false; // Stop iteration\n }\n });\n\n if (rootTask) {\n gantt.selectTask(rootTask.id);\n // Trigger task click event to open detail panel\n const originalTask = this.tasks.find(t => t.ID === rootTask.id);\n if (originalTask) {\n this.selectedTask = originalTask;\n this.taskClicked.emit(originalTask);\n }\n }\n\n console.log('✅ Expanded all tasks and selected root:', rootTask?.id);\n } catch (error) {\n console.error('❌ Error expanding/selecting tasks:', error);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"gantt-task-viewer.component.js","sourceRoot":"","sources":["../../../src/lib/components/gantt-task-viewer.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnChanges, AfterViewInit, ElementRef, ViewChild, OnDestroy, HostListener } from '@angular/core';\n\nimport { MJTaskEntity, MJTaskDependencyEntity } from '@memberjunction/core-entities';\nimport { gantt } from 'dhtmlx-gantt';\nimport { TaskDetailPanelComponent } from './task-detail-panel.component';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n/**\n * Gantt chart view for tasks using DHTMLX Gantt\n */\n@Component({\n selector: 'mj-gantt-task-viewer',\n standalone: true,\n imports: [TaskDetailPanelComponent],\n template: `\n <div class=\"gantt-task-viewer\">\n @if (!tasks || tasks.length === 0) {\n <div class=\"no-tasks\">\n <i class=\"fas fa-chart-gantt\"></i>\n <p>No tasks to display in Gantt view</p>\n </div>\n }\n \n @if (tasks && tasks.length > 0) {\n <div class=\"gantt-layout\">\n <div #ganttContainer class=\"gantt-container\"></div>\n @if (selectedTask) {\n <div class=\"gantt-resizer\"\n (mousedown)=\"startResize($event)\"></div>\n }\n @if (selectedTask) {\n <div class=\"task-detail-panel\" [style.width.px]=\"detailPanelWidth\">\n <mj-task-detail-panel\n [task]=\"selectedTask\"\n [agentRunId]=\"getAgentRunId(selectedTask)\"\n (closePanel)=\"closeDetailPanel()\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\">\n </mj-task-detail-panel>\n </div>\n }\n </div>\n }\n </div>\n `,\n styles: [`\n .gantt-task-viewer {\n height: 100%;\n background: white;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .gantt-layout {\n display: flex;\n height: 600px;\n position: relative;\n }\n\n .gantt-container {\n flex: 1;\n min-width: 400px;\n height: 100%;\n position: relative;\n }\n\n .gantt-resizer {\n width: 4px;\n background: #E5E7EB;\n cursor: col-resize;\n flex-shrink: 0;\n transition: background 0.2s;\n }\n\n .gantt-resizer:hover {\n background: #3B82F6;\n }\n\n .task-detail-panel {\n min-width: 300px;\n max-width: 600px;\n height: 100%;\n border-left: 1px solid #E5E7EB;\n flex-shrink: 0;\n }\n\n /* Override DHTMLX Gantt default styles */\n :host ::ng-deep .gantt_container {\n font-family: inherit;\n font-size: 13px;\n }\n\n :host ::ng-deep .gantt_grid_scale,\n :host ::ng-deep .gantt_task_scale {\n background: #F9FAFB;\n border-bottom: 2px solid #E5E7EB;\n }\n\n :host ::ng-deep .gantt_task .gantt_task_content {\n font-weight: 500;\n }\n\n .no-tasks {\n text-align: center;\n padding: 80px 20px;\n color: #9CA3AF;\n }\n\n .no-tasks i {\n font-size: 64px;\n opacity: 0.3;\n margin-bottom: 16px;\n }\n\n .no-tasks p {\n margin: 0;\n font-size: 14px;\n }\n `]\n})\nexport class GanttTaskViewerComponent implements OnChanges, AfterViewInit, OnDestroy {\n @Input() tasks: MJTaskEntity[] = [];\n @Input() taskDependencies: MJTaskDependencyEntity[] = [];\n @Input() agentRunMap?: Map<string, string>; // Maps TaskID -> AgentRunID\n @Output() taskClicked = new EventEmitter<MJTaskEntity>();\n @Output() openEntityRecord = new EventEmitter<{ entityName: string; recordId: string }>();\n\n @ViewChild('ganttContainer', { static: false }) ganttContainer!: ElementRef<HTMLDivElement>;\n\n public selectedTask: MJTaskEntity | null = null;\n public detailPanelWidth: number = 400;\n\n private ganttInitialized = false;\n private isResizing = false;\n private resizeStartX = 0;\n private resizeStartWidth = 0;\n\n ngAfterViewInit() {\n console.log('🔧 ngAfterViewInit called', {\n taskCount: this.tasks?.length || 0,\n hasContainer: !!this.ganttContainer\n });\n\n if (this.tasks && this.tasks.length > 0 && this.ganttContainer) {\n this.initGantt();\n }\n }\n\n ngOnChanges() {\n console.log('🔄 ngOnChanges called', {\n initialized: this.ganttInitialized,\n hasContainer: !!this.ganttContainer,\n taskCount: this.tasks?.length || 0\n });\n\n if (this.ganttInitialized && this.ganttContainer) {\n this.updateGanttData();\n } else if (!this.ganttInitialized && this.ganttContainer && this.tasks && this.tasks.length > 0) {\n // Initialize if we have container and tasks but haven't initialized yet\n console.log('🎨 Late initialization - gantt not initialized but container and tasks available');\n this.initGantt();\n }\n }\n\n ngOnDestroy() {\n if (this.ganttInitialized) {\n gantt.clearAll();\n this.ganttInitialized = false;\n }\n }\n\n private initGantt(): void {\n try {\n console.log('🎨 Initializing DHTMLX Gantt');\n\n // IMPORTANT: Clear any previous configuration\n gantt.clearAll();\n\n // Configure Gantt layout and appearance\n gantt.config.date_format = '%Y-%m-%d %H:%i';\n gantt.config.scale_unit = 'day';\n gantt.config.date_scale = '%d %M';\n gantt.config.subscales = [];\n gantt.config.show_progress = true;\n gantt.config.show_links = true;\n gantt.config.auto_types = true;\n gantt.config.readonly = true; // Read-only for now\n gantt.config.fit_tasks = true; // Auto-fit timeline to tasks\n\n // Disable auto-scheduling - we calculate dates ourselves based on dependencies\n gantt.config.auto_scheduling = false;\n\n // Grid configuration\n gantt.config.grid_width = 350;\n gantt.config.row_height = 36;\n gantt.config.scale_height = 0; // Hide date scale - dates are just for positioning\n\n // Layout configuration - ensure timeline is visible\n gantt.config.layout = {\n css: \"gantt_container\",\n rows: [\n {\n cols: [\n { view: \"grid\", group: \"grids\", scrollY: \"scrollVer\" },\n { resizer: true, width: 1 },\n { view: \"timeline\", scrollX: \"scrollHor\", scrollY: \"scrollVer\" },\n { view: \"scrollbar\", id: \"scrollVer\", group: \"vertical\" }\n ]\n },\n { view: \"scrollbar\", id: \"scrollHor\", group: \"horizontal\" }\n ]\n };\n\n // Column configuration - only show task names, hide dates\n gantt.config.columns = [\n { name: 'text', label: 'Task name', tree: true, width: '*' }\n ];\n\n // Initialize Gantt in the container\n gantt.init(this.ganttContainer.nativeElement);\n this.ganttInitialized = true;\n\n // Attach click event\n gantt.attachEvent('onTaskClick', (id: string) => {\n const originalTask = this.tasks.find(t => UUIDsEqual(t.ID, id));\n if (originalTask) {\n this.selectedTask = originalTask;\n this.taskClicked.emit(originalTask);\n }\n return true;\n });\n\n // Load data\n this.updateGanttData();\n\n // Force resize after data load to ensure proper rendering\n setTimeout(() => {\n gantt.setSizes();\n }, 0);\n\n // Expand and select after render completes\n setTimeout(() => {\n this.expandAllAndSelectRoot();\n }, 100);\n\n console.log('✅ DHTMLX Gantt initialized successfully');\n } catch (error) {\n console.error('❌ Error initializing Gantt:', error);\n }\n }\n\n private updateGanttData(): void {\n if (!this.ganttInitialized) return;\n\n try {\n console.log('📊 Updating Gantt data with', this.tasks.length, 'tasks');\n\n const ganttData = this.convertToGanttFormat(this.tasks);\n gantt.clearAll();\n gantt.parse(ganttData);\n\n // Log final parsed data for debugging\n console.log('📋 Gantt data after parse:', {\n tasks: gantt.getTaskByTime(),\n links: gantt.getLinks()\n });\n\n // Force resize after data update\n setTimeout(() => {\n gantt.setSizes();\n }, 0);\n\n // Expand and select after render completes\n setTimeout(() => {\n this.expandAllAndSelectRoot();\n }, 100);\n\n console.log('✅ Gantt data updated');\n } catch (error) {\n console.error('❌ Error updating Gantt data:', error);\n }\n }\n\n private convertToGanttFormat(tasks: MJTaskEntity[]): { data: any[], links: any[] } {\n const data: any[] = [];\n const links: any[] = [];\n\n console.log('🔍 Converting tasks:', tasks);\n console.log('🔗 Task dependencies:', this.taskDependencies);\n\n // Build a map of task ID to task for quick lookup\n const taskMap = new Map<string, MJTaskEntity>();\n tasks.forEach(t => taskMap.set(t.ID, t));\n\n // Build dependency map: taskId -> array of tasks it depends on\n const dependencyMap = new Map<string, string[]>();\n this.taskDependencies.forEach(dep => {\n if (!dependencyMap.has(dep.TaskID)) {\n dependencyMap.set(dep.TaskID, []);\n }\n dependencyMap.get(dep.TaskID)!.push(dep.DependsOnTaskID);\n });\n\n // Calculate start dates based on dependencies\n const taskStartDates = new Map<string, Date>();\n const baseDate = new Date();\n baseDate.setHours(0, 0, 0, 0);\n\n // Recursive function to calculate start date for a task\n const calculateStartDate = (taskId: string, visited = new Set<string>()): Date => {\n // Prevent circular dependencies\n if (visited.has(taskId)) {\n return new Date(baseDate);\n }\n visited.add(taskId);\n\n // If already calculated, return it\n if (taskStartDates.has(taskId)) {\n return taskStartDates.get(taskId)!;\n }\n\n const task = taskMap.get(taskId);\n if (!task) return new Date(baseDate);\n\n const dependencies = dependencyMap.get(taskId) || [];\n\n if (dependencies.length === 0) {\n // No dependencies - use base date or task's actual start date\n const startDate = task.StartedAt ? new Date(task.StartedAt) : new Date(baseDate);\n taskStartDates.set(taskId, startDate);\n return startDate;\n }\n\n // Has dependencies - start after the latest dependency ends\n let latestEnd = new Date(baseDate);\n for (const depId of dependencies) {\n const depTask = taskMap.get(depId);\n if (depTask) {\n const depStart = calculateStartDate(depId, new Set(visited));\n const depDuration = this.calculateDuration(depTask);\n const depEnd = new Date(depStart);\n depEnd.setDate(depEnd.getDate() + depDuration);\n\n if (depEnd > latestEnd) {\n latestEnd = depEnd;\n }\n }\n }\n\n taskStartDates.set(taskId, latestEnd);\n return latestEnd;\n };\n\n // Calculate start dates for all tasks\n tasks.forEach(task => calculateStartDate(task.ID));\n\n // Calculate min/max dates for timeline display range\n let minDate: Date | null = null;\n let maxDate: Date | null = null;\n\n tasks.forEach(task => {\n const startDate = taskStartDates.get(task.ID);\n if (startDate) {\n const duration = this.calculateDuration(task);\n const endDate = new Date(startDate);\n endDate.setDate(endDate.getDate() + duration);\n\n if (!minDate || startDate < minDate) {\n minDate = startDate;\n }\n if (!maxDate || endDate > maxDate) {\n maxDate = endDate;\n }\n }\n });\n\n // Add 1 day padding before and after\n if (minDate) {\n const paddedStart = new Date(minDate);\n paddedStart.setDate(paddedStart.getDate() - 1);\n gantt.config.start_date = paddedStart;\n }\n if (maxDate) {\n const paddedEnd = new Date(maxDate);\n paddedEnd.setDate(paddedEnd.getDate() + 1);\n gantt.config.end_date = paddedEnd;\n }\n\n // Now create Gantt tasks with calculated dates\n tasks.forEach((task) => {\n console.log('📝 Processing task:', {\n ID: task.ID,\n Name: task.Name,\n ParentID: task.ParentID\n });\n\n // Calculate progress (0-1 scale for DHTMLX)\n let progress = (task.PercentComplete || 0) / 100;\n if (task.Status === 'Complete') {\n progress = 1;\n }\n\n const duration = this.calculateDuration(task);\n const startDate = taskStartDates.get(task.ID) || new Date(baseDate);\n\n const ganttTask: any = {\n id: task.ID,\n text: task.Name || 'Untitled Task',\n start_date: this.formatDateForDHTMLX(startDate),\n duration: duration,\n progress: progress\n };\n\n // Add parent relationship for tree structure (not dependency)\n if (task.ParentID) {\n ganttTask.parent = task.ParentID;\n } else {\n // Root tasks need parent: 0\n ganttTask.parent = 0;\n }\n\n console.log('✅ Created Gantt task:', ganttTask);\n data.push(ganttTask);\n });\n\n // Create links from MJTaskDependencyEntity records\n this.taskDependencies.forEach((dep, index) => {\n links.push({\n id: dep.ID || `link_${index}`,\n source: dep.DependsOnTaskID, // The task being depended on\n target: dep.TaskID, // The task that depends on it\n type: '0' // finish-to-start (DHTMLX type 0)\n });\n console.log(`🔗 Created link: ${dep.DependsOnTaskID} -> ${dep.TaskID}`);\n });\n\n console.log('📊 Final DHTMLX format:', { data, links });\n return { data, links };\n }\n\n private calculateDuration(task: MJTaskEntity): number {\n if (task.StartedAt && task.DueAt) {\n const startDate = new Date(task.StartedAt);\n const endDate = new Date(task.DueAt);\n return Math.max(1, Math.ceil((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24)));\n }\n return 1; // Default to 1 day\n }\n\n private formatDateForDHTMLX(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n return `${year}-${month}-${day} 00:00`;\n }\n\n public getAgentRunId(task: MJTaskEntity): string | null {\n return this.agentRunMap?.get(task.ID) || null;\n }\n\n public closeDetailPanel(): void {\n this.selectedTask = null;\n }\n\n public onOpenEntityRecord(event: { entityName: string; recordId: string }): void {\n this.openEntityRecord.emit(event);\n }\n\n public startResize(event: MouseEvent): void {\n this.isResizing = true;\n this.resizeStartX = event.clientX;\n this.resizeStartWidth = this.detailPanelWidth;\n event.preventDefault();\n }\n\n @HostListener('document:mousemove', ['$event'])\n handleResize(event: MouseEvent): void {\n if (!this.isResizing) return;\n\n const delta = this.resizeStartX - event.clientX;\n const newWidth = this.resizeStartWidth + delta;\n\n // Constrain width between min and max\n this.detailPanelWidth = Math.max(300, Math.min(600, newWidth));\n }\n\n @HostListener('document:mouseup')\n stopResize(): void {\n if (this.isResizing) {\n this.isResizing = false;\n // Resize gantt chart after panel resize completes\n setTimeout(() => {\n if (this.ganttInitialized) {\n gantt.setSizes();\n }\n }, 0);\n }\n }\n\n private expandAllAndSelectRoot(): void {\n try {\n // Expand all tasks\n gantt.eachTask((task: any) => {\n gantt.open(task.id);\n });\n\n // Find and select the root task (task with parent = 0)\n let rootTask: any = null;\n gantt.eachTask((task: any) => {\n if (task.parent === 0 || task.parent === '0') {\n rootTask = task;\n return false; // Stop iteration\n }\n });\n\n if (rootTask) {\n gantt.selectTask(rootTask.id);\n // Trigger task click event to open detail panel\n const originalTask = this.tasks.find(t => UUIDsEqual(t.ID, rootTask.id));\n if (originalTask) {\n this.selectedTask = originalTask;\n this.taskClicked.emit(originalTask);\n }\n }\n\n console.log('✅ Expanded all tasks and selected root:', rootTask?.id);\n } catch (error) {\n console.error('❌ Error expanding/selecting tasks:', error);\n }\n }\n}\n"]}
@@ -13,6 +13,7 @@ export declare class SimpleTaskViewerComponent implements OnChanges {
13
13
  recordId: string;
14
14
  }>;
15
15
  selectedTask: MJTaskEntity | null;
16
+ IsTaskSelected(task: MJTaskEntity): boolean;
16
17
  detailPanelWidth: number;
17
18
  private isResizing;
18
19
  private resizeStartX;
@@ -1 +1 @@
1
- {"version":3,"file":"simple-task-viewer.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/simple-task-viewer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,SAAS,EAAgB,MAAM,eAAe,CAAC;AAEhG,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;;AAG7D;;GAEG;AACH,qBAgSa,yBAA0B,YAAW,SAAS;IAChD,KAAK,EAAE,YAAY,EAAE,CAAM;IAC3B,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,WAAW,6BAAoC;IAC/C,gBAAgB;oBAAkC,MAAM;kBAAY,MAAM;OAAM;IAEnF,YAAY,EAAE,YAAY,GAAG,IAAI,CAAQ;IACzC,gBAAgB,EAAE,MAAM,CAAO;IAEtC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,gBAAgB,CAAK;IAE7B,WAAW;IAIJ,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IAKrC,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI;IAIhD,gBAAgB,IAAI,IAAI;IAIxB,kBAAkB,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAIzE,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAQ3C,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAWrC,UAAU,IAAI,IAAI;IAIX,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAWrC,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM;yCApEjC,yBAAyB;2CAAzB,yBAAyB;CAyErC"}
1
+ {"version":3,"file":"simple-task-viewer.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/simple-task-viewer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,SAAS,EAAgB,MAAM,eAAe,CAAC;AAEhG,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;;AAI7D;;GAEG;AACH,qBAgSa,yBAA0B,YAAW,SAAS;IAChD,KAAK,EAAE,YAAY,EAAE,CAAM;IAC3B,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,WAAW,6BAAoC;IAC/C,gBAAgB;oBAAkC,MAAM;kBAAY,MAAM;OAAM;IAEnF,YAAY,EAAE,YAAY,GAAG,IAAI,CAAQ;IAEzC,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO;IAG3C,gBAAgB,EAAE,MAAM,CAAO;IAEtC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,gBAAgB,CAAK;IAE7B,WAAW;IAIJ,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IAKrC,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI;IAIhD,gBAAgB,IAAI,IAAI;IAIxB,kBAAkB,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAIzE,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAQ3C,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAWrC,UAAU,IAAI,IAAI;IAIX,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAWrC,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM;yCAxEjC,yBAAyB;2CAAzB,yBAAyB;CA6ErC"}
@@ -1,6 +1,7 @@
1
1
  import { Component, Input, Output, EventEmitter, HostListener } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { TaskDetailPanelComponent } from './task-detail-panel.component';
4
+ import { UUIDsEqual } from '@memberjunction/global';
4
5
  import * as i0 from "@angular/core";
5
6
  import * as i1 from "@angular/common";
6
7
  function SimpleTaskViewerComponent_For_4_Conditional_8_Template(rf, ctx) { if (rf & 1) {
@@ -62,7 +63,7 @@ function SimpleTaskViewerComponent_For_4_Template(rf, ctx) { if (rf & 1) {
62
63
  } if (rf & 2) {
63
64
  const task_r2 = ctx.$implicit;
64
65
  const ctx_r2 = i0.ɵɵnextContext();
65
- i0.ɵɵclassProp("completed", task_r2.Status === "Complete")("selected", (ctx_r2.selectedTask == null ? null : ctx_r2.selectedTask.ID) === task_r2.ID);
66
+ i0.ɵɵclassProp("completed", task_r2.Status === "Complete")("selected", ctx_r2.IsTaskSelected(task_r2));
66
67
  i0.ɵɵadvance();
67
68
  i0.ɵɵclassProp("complete", task_r2.Status === "Complete");
68
69
  i0.ɵɵadvance();
@@ -113,6 +114,9 @@ export class SimpleTaskViewerComponent {
113
114
  taskClicked = new EventEmitter();
114
115
  openEntityRecord = new EventEmitter();
115
116
  selectedTask = null;
117
+ IsTaskSelected(task) {
118
+ return UUIDsEqual(this.selectedTask?.ID, task.ID);
119
+ }
116
120
  detailPanelWidth = 400;
117
121
  isResizing = false;
118
122
  resizeStartX = 0;
@@ -200,7 +204,7 @@ export class SimpleTaskViewerComponent {
200
204
  <div
201
205
  class="task-item"
202
206
  [class.completed]="task.Status === 'Complete'"
203
- [class.selected]="selectedTask?.ID === task.ID"
207
+ [class.selected]="IsTaskSelected(task)"
204
208
  (click)="onTaskClick(task)">
205
209
  <!-- Status Icon -->
206
210
  <div class="status-icon" [class.complete]="task.Status === 'Complete'">
@@ -288,5 +292,5 @@ export class SimpleTaskViewerComponent {
288
292
  type: HostListener,
289
293
  args: ['document:mouseup']
290
294
  }] }); })();
291
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SimpleTaskViewerComponent, { className: "SimpleTaskViewerComponent", filePath: "src/lib/components/simple-task-viewer.component.ts", lineNumber: 297 }); })();
295
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SimpleTaskViewerComponent, { className: "SimpleTaskViewerComponent", filePath: "src/lib/components/simple-task-viewer.component.ts", lineNumber: 298 }); })();
292
296
  //# sourceMappingURL=simple-task-viewer.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"simple-task-viewer.component.js","sourceRoot":"","sources":["../../../src/lib/components/simple-task-viewer.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAa,YAAY,EAAE,MAAM,eAAe,CAAC;AAChG,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;;;;IA8BjD,wBAA4C;;;IAM5C,AADF,+BAAmC,cACC;IAChC,0BAEoD;IACtD,iBAAM;IACN,gCAAoC;IAAA,YAA2B;IACjE,AADiE,iBAAO,EAClE;;;IAJA,eAAsC;IAAtC,qDAAsC;IACxC,yDAA6C;IAEX,eAA2B;IAA3B,uDAA2B;;;IAMjE,gCAAuB;IACrB,wBAA+B;IAC/B,YACF;IAAA,iBAAO;;;;IADL,eACF;IADE,iEACF;;;IAGA,gCAA0B;IACxB,wBAA2B;IAC3B,YACF;IAAA,iBAAO;;;IADL,eACF;IADE,6CACF;;;;IA1CV,8BAI8B;IAA5B,4MAAS,2BAAiB,KAAC;IAE3B,8BAAuE;IACrE,uBAA0D;IAC5D,iBAAM;IAKA,AADF,AADF,AADF,+BAA0B,cACC,cACK,eACmD;IAC3E,YACA;IAAA,gGAAkC;IAGpC,iBAAO;IAEP,kGAAoC;IAUtC,iBAAM;IACN,iCAAwB;IACtB,qGAAkB;IAMlB,qGAAiB;IASzB,AADE,AADE,AADE,iBAAO,EACH,EACF,EACF;;;;IA5CJ,AADA,0DAA8C,0FACC;IAGtB,cAA6C;IAA7C,yDAA6C;IACrD,cAAsC;IAAtC,8DAAsC;IAMxB,eAAmD;IAAnD,+DAAmD;IAC1E,cACA;IADA,6CACA;IAAA,cAEC;IAFD,wDAEC;IAGH,cASC;IATD,0DASC;IAGD,eAKC;IALD,yCAKC;IACD,cAKC;IALD,wCAKC;;;IAQT,8BAAsB;IACpB,wBAA4B;IAC5B,yBAAG;IAAA,mCAAmB;IACxB,AADwB,iBAAI,EACtB;;;;IAKR,+BACkC;IAAlC,wMAAa,0BAAmB,KAAC;IAAC,iBAAM;;;;IAKtC,AADF,+BAAmE,+BAKf;IAAhD,AADA,qNAAc,yBAAkB,KAAC,0NACb,iCAA0B,KAAC;IAEnD,AADE,iBAAuB,EACnB;;;IAPyB,sDAAmC;IAE9D,cAAqB;IACrB,AADA,0CAAqB,yDACqB;;AA/ExD;;GAEG;AAiSH,MAAM,OAAO,yBAAyB;IAC3B,KAAK,GAAmB,EAAE,CAAC;IAC3B,WAAW,CAAuB,CAAC,4BAA4B;IAC9D,WAAW,GAAG,IAAI,YAAY,EAAgB,CAAC;IAC/C,gBAAgB,GAAG,IAAI,YAAY,EAA4C,CAAC;IAEnF,YAAY,GAAwB,IAAI,CAAC;IACzC,gBAAgB,GAAW,GAAG,CAAC;IAE9B,UAAU,GAAG,KAAK,CAAC;IACnB,YAAY,GAAG,CAAC,CAAC;IACjB,gBAAgB,GAAG,CAAC,CAAC;IAE7B,WAAW;QACT,2BAA2B;IAC7B,CAAC;IAEM,WAAW,CAAC,IAAkB;QACnC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAEM,aAAa,CAAC,IAAkB;QACrC,OAAO,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC;IAChD,CAAC;IAEM,gBAAgB;QACrB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;IAC3B,CAAC;IAEM,kBAAkB,CAAC,KAA+C;QACvE,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAEM,WAAW,CAAC,KAAiB;QAClC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC;QAClC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;QAC9C,KAAK,CAAC,cAAc,EAAE,CAAC;IACzB,CAAC;IAGD,YAAY,CAAC,KAAiB;QAC5B,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO;QAE7B,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC;QAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;QAE/C,sCAAsC;QACtC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;IACjE,CAAC;IAGD,UAAU;QACR,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;IAC1B,CAAC;IAEM,aAAa,CAAC,MAAc;QACjC,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,UAAU,CAAC,CAAC,OAAO,iBAAiB,CAAC;YAC1C,KAAK,aAAa,CAAC,CAAC,OAAO,YAAY,CAAC;YACxC,KAAK,SAAS,CAAC,CAAC,OAAO,UAAU,CAAC;YAClC,KAAK,SAAS,CAAC,CAAC,OAAO,QAAQ,CAAC;YAChC,KAAK,QAAQ,CAAC,CAAC,OAAO,iBAAiB,CAAC;YACxC,OAAO,CAAC,CAAC,OAAO,WAAW,CAAC;QAC9B,CAAC;IACH,CAAC;IAEM,UAAU,CAAC,IAAiB;QACjC,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,OAAO,CAAC,CAAC,kBAAkB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IAC5F,CAAC;mHAxEU,yBAAyB;6DAAzB,yBAAyB;YAAzB,4GAAA,wBAAoB,0BAAK,qFAAzB,gBAAY,0BAAa;;YAzR9B,AADF,AADF,8BAAgC,aACL,aACmC;YACxD,gHAiDC;YAED,2FAAoC;YAMtC,iBAAM;YAEN,2FAAoB;YAKpB,2FAAoB;YAWxB,AADE,iBAAM,EACF;;YA5EqB,eAAkC;YAAlC,+CAAkC;YACvD,cAiDC;YAjDD,wBAiDC;YAED,eAKC;YALD,+DAKC;YAGH,cAGC;YAHD,2CAGC;YAED,cASC;YATD,2CASC;4BA9EG,YAAY,cAAE,wBAAwB;;iFA6RrC,yBAAyB;cAhSrC,SAAS;2BACE,uBAAuB,cACrB,IAAI,WACP,CAAC,YAAY,EAAE,wBAAwB,CAAC,YACvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAgFP;;kBA6MF,KAAK;;kBACL,KAAK;;kBACL,MAAM;;kBACN,MAAM;;kBAqCN,YAAY;mBAAC,oBAAoB,EAAE,CAAC,QAAQ,CAAC;;kBAW7C,YAAY;mBAAC,kBAAkB;;kFApDrB,yBAAyB","sourcesContent":["import { Component, Input, Output, EventEmitter, OnChanges, HostListener } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { MJTaskEntity } from '@memberjunction/core-entities';\nimport { TaskDetailPanelComponent } from './task-detail-panel.component';\n\n/**\n * Simple list view for tasks\n */\n@Component({\n selector: 'mj-simple-task-viewer',\n standalone: true,\n imports: [CommonModule, TaskDetailPanelComponent],\n template: `\n <div class=\"simple-task-viewer\">\n <div class=\"list-layout\">\n <div class=\"task-list\" [class.with-detail]=\"selectedTask\">\n @for (task of tasks; track task) {\n <div\n class=\"task-item\"\n [class.completed]=\"task.Status === 'Complete'\"\n [class.selected]=\"selectedTask?.ID === task.ID\"\n (click)=\"onTaskClick(task)\">\n <!-- Status Icon -->\n <div class=\"status-icon\" [class.complete]=\"task.Status === 'Complete'\">\n <i class=\"fas\" [ngClass]=\"getStatusIcon(task.Status)\"></i>\n </div>\n <!-- Task Content -->\n <div class=\"task-content\">\n <div class=\"task-header\">\n <div class=\"task-title-row\">\n <span class=\"task-title\" [class.completed-text]=\"task.Status === 'Complete'\">\n {{ task.Name }}\n @if (task.Status === 'Complete') {\n <i class=\"fas fa-check completed-check\"></i>\n }\n </span>\n <!-- Compact progress indicator for all tasks -->\n @if (task.PercentComplete != null) {\n <div class=\"task-progress-compact\">\n <div class=\"progress-bar-compact\">\n <div class=\"progress-fill-compact\"\n [style.width.%]=\"task.PercentComplete\"\n [class.complete]=\"task.Status === 'Complete'\"></div>\n </div>\n <span class=\"progress-text-compact\">{{ task.PercentComplete }}%</span>\n </div>\n }\n </div>\n <span class=\"task-meta\">\n @if (task.DueAt) {\n <span class=\"due-date\">\n <i class=\"far fa-calendar\"></i>\n {{ formatDate(task.DueAt) }}\n </span>\n }\n @if (task.User) {\n <span class=\"assigned-to\">\n <i class=\"far fa-user\"></i>\n {{ task.User }}\n </span>\n }\n </span>\n </div>\n </div>\n </div>\n }\n \n @if (!tasks || tasks.length === 0) {\n <div class=\"no-tasks\">\n <i class=\"fas fa-tasks\"></i>\n <p>No tasks to display</p>\n </div>\n }\n </div>\n \n @if (selectedTask) {\n <div class=\"list-resizer\"\n (mousedown)=\"startResize($event)\"></div>\n }\n \n @if (selectedTask) {\n <div class=\"task-detail-panel\" [style.width.px]=\"detailPanelWidth\">\n <mj-task-detail-panel\n [task]=\"selectedTask\"\n [agentRunId]=\"getAgentRunId(selectedTask)\"\n (closePanel)=\"closeDetailPanel()\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\">\n </mj-task-detail-panel>\n </div>\n }\n </div>\n </div>\n `,\n styles: [`\n .simple-task-viewer {\n height: 100%;\n background: #FAFAFA;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .list-layout {\n display: flex;\n height: 100%;\n position: relative;\n }\n\n .task-list {\n flex: 1;\n min-width: 400px;\n padding: 16px;\n overflow-y: auto;\n }\n\n .task-list.with-detail {\n border-right: 1px solid #E5E7EB;\n }\n\n .list-resizer {\n width: 4px;\n background: #E5E7EB;\n cursor: col-resize;\n flex-shrink: 0;\n transition: background 0.2s;\n }\n\n .list-resizer:hover {\n background: #3B82F6;\n }\n\n .task-detail-panel {\n min-width: 300px;\n max-width: 600px;\n height: 100%;\n flex-shrink: 0;\n }\n\n .task-item {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 16px;\n background: white;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n margin-bottom: 8px;\n transition: all 0.2s;\n cursor: pointer;\n }\n\n .task-item:hover {\n border-color: #3B82F6;\n box-shadow: 0 2px 8px rgba(59, 130, 246, 0.1);\n transform: translateY(-1px);\n }\n\n .task-item.selected {\n border-color: #3B82F6;\n background: #EFF6FF;\n box-shadow: 0 2px 8px rgba(59, 130, 246, 0.15);\n }\n\n .task-item.completed {\n background: #F9FAFB;\n border-color: #D1D5DB;\n }\n\n .status-icon {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #FEF3C7;\n color: #F59E0B;\n flex-shrink: 0;\n }\n\n .status-icon.complete {\n background: #D1FAE5;\n color: #10B981;\n }\n\n .task-content {\n flex: 1;\n min-width: 0;\n }\n\n .task-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 12px;\n margin-bottom: 6px;\n }\n\n .task-title-row {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 0;\n }\n\n .task-title {\n font-weight: 600;\n color: #111827;\n font-size: 14px;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .task-title.completed-text {\n color: #6B7280;\n text-decoration: line-through;\n text-decoration-thickness: 1.5px;\n }\n\n .completed-check {\n color: #10B981;\n font-size: 12px;\n }\n\n .task-meta {\n display: flex;\n gap: 12px;\n font-size: 12px;\n color: #6B7280;\n white-space: nowrap;\n }\n\n .task-meta i {\n margin-right: 4px;\n }\n\n .task-description {\n font-size: 13px;\n color: #6B7280;\n margin-bottom: 8px;\n line-height: 1.5;\n }\n\n .task-progress-compact {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-shrink: 0;\n }\n\n .progress-bar-compact {\n width: 80px;\n height: 4px;\n background: #E5E7EB;\n border-radius: 2px;\n overflow: hidden;\n }\n\n .progress-fill-compact {\n height: 100%;\n background: #3B82F6;\n transition: width 0.3s ease;\n }\n\n .progress-fill-compact.complete {\n background: #10B981;\n }\n\n .progress-text-compact {\n font-size: 10px;\n font-weight: 600;\n color: #6B7280;\n min-width: 30px;\n text-align: right;\n }\n\n .no-tasks {\n text-align: center;\n padding: 60px 20px;\n color: #9CA3AF;\n }\n\n .no-tasks i {\n font-size: 48px;\n opacity: 0.3;\n margin-bottom: 12px;\n }\n\n .no-tasks p {\n margin: 0;\n font-size: 14px;\n }\n `]\n})\nexport class SimpleTaskViewerComponent implements OnChanges {\n @Input() tasks: MJTaskEntity[] = [];\n @Input() agentRunMap?: Map<string, string>; // Maps TaskID -> AgentRunID\n @Output() taskClicked = new EventEmitter<MJTaskEntity>();\n @Output() openEntityRecord = new EventEmitter<{ entityName: string; recordId: string }>();\n\n public selectedTask: MJTaskEntity | null = null;\n public detailPanelWidth: number = 400;\n\n private isResizing = false;\n private resizeStartX = 0;\n private resizeStartWidth = 0;\n\n ngOnChanges() {\n // Tasks are already loaded\n }\n\n public onTaskClick(task: MJTaskEntity): void {\n this.selectedTask = task;\n this.taskClicked.emit(task);\n }\n\n public getAgentRunId(task: MJTaskEntity): string | null {\n return this.agentRunMap?.get(task.ID) || null;\n }\n\n public closeDetailPanel(): void {\n this.selectedTask = null;\n }\n\n public onOpenEntityRecord(event: { entityName: string; recordId: string }): void {\n this.openEntityRecord.emit(event);\n }\n\n public startResize(event: MouseEvent): void {\n this.isResizing = true;\n this.resizeStartX = event.clientX;\n this.resizeStartWidth = this.detailPanelWidth;\n event.preventDefault();\n }\n\n @HostListener('document:mousemove', ['$event'])\n handleResize(event: MouseEvent): void {\n if (!this.isResizing) return;\n\n const delta = this.resizeStartX - event.clientX;\n const newWidth = this.resizeStartWidth + delta;\n\n // Constrain width between min and max\n this.detailPanelWidth = Math.max(300, Math.min(600, newWidth));\n }\n\n @HostListener('document:mouseup')\n stopResize(): void {\n this.isResizing = false;\n }\n\n public getStatusIcon(status: string): string {\n switch (status) {\n case 'Complete': return 'fa-check-circle';\n case 'In Progress': return 'fa-spinner';\n case 'Pending': return 'fa-clock';\n case 'Blocked': return 'fa-ban';\n case 'Failed': return 'fa-times-circle';\n default: return 'fa-circle';\n }\n }\n\n public formatDate(date: Date | null): string {\n if (!date) return '';\n const d = new Date(date);\n return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });\n }\n}\n"]}
1
+ {"version":3,"file":"simple-task-viewer.component.js","sourceRoot":"","sources":["../../../src/lib/components/simple-task-viewer.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnChanges, HostListener } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { MJTaskEntity } from '@memberjunction/core-entities';\nimport { TaskDetailPanelComponent } from './task-detail-panel.component';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n/**\n * Simple list view for tasks\n */\n@Component({\n selector: 'mj-simple-task-viewer',\n standalone: true,\n imports: [CommonModule, TaskDetailPanelComponent],\n template: `\n <div class=\"simple-task-viewer\">\n <div class=\"list-layout\">\n <div class=\"task-list\" [class.with-detail]=\"selectedTask\">\n @for (task of tasks; track task) {\n <div\n class=\"task-item\"\n [class.completed]=\"task.Status === 'Complete'\"\n [class.selected]=\"IsTaskSelected(task)\"\n (click)=\"onTaskClick(task)\">\n <!-- Status Icon -->\n <div class=\"status-icon\" [class.complete]=\"task.Status === 'Complete'\">\n <i class=\"fas\" [ngClass]=\"getStatusIcon(task.Status)\"></i>\n </div>\n <!-- Task Content -->\n <div class=\"task-content\">\n <div class=\"task-header\">\n <div class=\"task-title-row\">\n <span class=\"task-title\" [class.completed-text]=\"task.Status === 'Complete'\">\n {{ task.Name }}\n @if (task.Status === 'Complete') {\n <i class=\"fas fa-check completed-check\"></i>\n }\n </span>\n <!-- Compact progress indicator for all tasks -->\n @if (task.PercentComplete != null) {\n <div class=\"task-progress-compact\">\n <div class=\"progress-bar-compact\">\n <div class=\"progress-fill-compact\"\n [style.width.%]=\"task.PercentComplete\"\n [class.complete]=\"task.Status === 'Complete'\"></div>\n </div>\n <span class=\"progress-text-compact\">{{ task.PercentComplete }}%</span>\n </div>\n }\n </div>\n <span class=\"task-meta\">\n @if (task.DueAt) {\n <span class=\"due-date\">\n <i class=\"far fa-calendar\"></i>\n {{ formatDate(task.DueAt) }}\n </span>\n }\n @if (task.User) {\n <span class=\"assigned-to\">\n <i class=\"far fa-user\"></i>\n {{ task.User }}\n </span>\n }\n </span>\n </div>\n </div>\n </div>\n }\n \n @if (!tasks || tasks.length === 0) {\n <div class=\"no-tasks\">\n <i class=\"fas fa-tasks\"></i>\n <p>No tasks to display</p>\n </div>\n }\n </div>\n \n @if (selectedTask) {\n <div class=\"list-resizer\"\n (mousedown)=\"startResize($event)\"></div>\n }\n \n @if (selectedTask) {\n <div class=\"task-detail-panel\" [style.width.px]=\"detailPanelWidth\">\n <mj-task-detail-panel\n [task]=\"selectedTask\"\n [agentRunId]=\"getAgentRunId(selectedTask)\"\n (closePanel)=\"closeDetailPanel()\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\">\n </mj-task-detail-panel>\n </div>\n }\n </div>\n </div>\n `,\n styles: [`\n .simple-task-viewer {\n height: 100%;\n background: #FAFAFA;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .list-layout {\n display: flex;\n height: 100%;\n position: relative;\n }\n\n .task-list {\n flex: 1;\n min-width: 400px;\n padding: 16px;\n overflow-y: auto;\n }\n\n .task-list.with-detail {\n border-right: 1px solid #E5E7EB;\n }\n\n .list-resizer {\n width: 4px;\n background: #E5E7EB;\n cursor: col-resize;\n flex-shrink: 0;\n transition: background 0.2s;\n }\n\n .list-resizer:hover {\n background: #3B82F6;\n }\n\n .task-detail-panel {\n min-width: 300px;\n max-width: 600px;\n height: 100%;\n flex-shrink: 0;\n }\n\n .task-item {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 16px;\n background: white;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n margin-bottom: 8px;\n transition: all 0.2s;\n cursor: pointer;\n }\n\n .task-item:hover {\n border-color: #3B82F6;\n box-shadow: 0 2px 8px rgba(59, 130, 246, 0.1);\n transform: translateY(-1px);\n }\n\n .task-item.selected {\n border-color: #3B82F6;\n background: #EFF6FF;\n box-shadow: 0 2px 8px rgba(59, 130, 246, 0.15);\n }\n\n .task-item.completed {\n background: #F9FAFB;\n border-color: #D1D5DB;\n }\n\n .status-icon {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #FEF3C7;\n color: #F59E0B;\n flex-shrink: 0;\n }\n\n .status-icon.complete {\n background: #D1FAE5;\n color: #10B981;\n }\n\n .task-content {\n flex: 1;\n min-width: 0;\n }\n\n .task-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 12px;\n margin-bottom: 6px;\n }\n\n .task-title-row {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 0;\n }\n\n .task-title {\n font-weight: 600;\n color: #111827;\n font-size: 14px;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .task-title.completed-text {\n color: #6B7280;\n text-decoration: line-through;\n text-decoration-thickness: 1.5px;\n }\n\n .completed-check {\n color: #10B981;\n font-size: 12px;\n }\n\n .task-meta {\n display: flex;\n gap: 12px;\n font-size: 12px;\n color: #6B7280;\n white-space: nowrap;\n }\n\n .task-meta i {\n margin-right: 4px;\n }\n\n .task-description {\n font-size: 13px;\n color: #6B7280;\n margin-bottom: 8px;\n line-height: 1.5;\n }\n\n .task-progress-compact {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-shrink: 0;\n }\n\n .progress-bar-compact {\n width: 80px;\n height: 4px;\n background: #E5E7EB;\n border-radius: 2px;\n overflow: hidden;\n }\n\n .progress-fill-compact {\n height: 100%;\n background: #3B82F6;\n transition: width 0.3s ease;\n }\n\n .progress-fill-compact.complete {\n background: #10B981;\n }\n\n .progress-text-compact {\n font-size: 10px;\n font-weight: 600;\n color: #6B7280;\n min-width: 30px;\n text-align: right;\n }\n\n .no-tasks {\n text-align: center;\n padding: 60px 20px;\n color: #9CA3AF;\n }\n\n .no-tasks i {\n font-size: 48px;\n opacity: 0.3;\n margin-bottom: 12px;\n }\n\n .no-tasks p {\n margin: 0;\n font-size: 14px;\n }\n `]\n})\nexport class SimpleTaskViewerComponent implements OnChanges {\n @Input() tasks: MJTaskEntity[] = [];\n @Input() agentRunMap?: Map<string, string>; // Maps TaskID -> AgentRunID\n @Output() taskClicked = new EventEmitter<MJTaskEntity>();\n @Output() openEntityRecord = new EventEmitter<{ entityName: string; recordId: string }>();\n\n public selectedTask: MJTaskEntity | null = null;\n\n public IsTaskSelected(task: MJTaskEntity): boolean {\n return UUIDsEqual(this.selectedTask?.ID, task.ID);\n }\n public detailPanelWidth: number = 400;\n\n private isResizing = false;\n private resizeStartX = 0;\n private resizeStartWidth = 0;\n\n ngOnChanges() {\n // Tasks are already loaded\n }\n\n public onTaskClick(task: MJTaskEntity): void {\n this.selectedTask = task;\n this.taskClicked.emit(task);\n }\n\n public getAgentRunId(task: MJTaskEntity): string | null {\n return this.agentRunMap?.get(task.ID) || null;\n }\n\n public closeDetailPanel(): void {\n this.selectedTask = null;\n }\n\n public onOpenEntityRecord(event: { entityName: string; recordId: string }): void {\n this.openEntityRecord.emit(event);\n }\n\n public startResize(event: MouseEvent): void {\n this.isResizing = true;\n this.resizeStartX = event.clientX;\n this.resizeStartWidth = this.detailPanelWidth;\n event.preventDefault();\n }\n\n @HostListener('document:mousemove', ['$event'])\n handleResize(event: MouseEvent): void {\n if (!this.isResizing) return;\n\n const delta = this.resizeStartX - event.clientX;\n const newWidth = this.resizeStartWidth + delta;\n\n // Constrain width between min and max\n this.detailPanelWidth = Math.max(300, Math.min(600, newWidth));\n }\n\n @HostListener('document:mouseup')\n stopResize(): void {\n this.isResizing = false;\n }\n\n public getStatusIcon(status: string): string {\n switch (status) {\n case 'Complete': return 'fa-check-circle';\n case 'In Progress': return 'fa-spinner';\n case 'Pending': return 'fa-clock';\n case 'Blocked': return 'fa-ban';\n case 'Failed': return 'fa-times-circle';\n default: return 'fa-circle';\n }\n }\n\n public formatDate(date: Date | null): string {\n if (!date) return '';\n const d = new Date(date);\n return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"task-detail-panel.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/task-detail-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1F,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;;AAEvE;;;GAGG;AACH,qBA8Pa,wBAAyB,YAAW,MAAM,EAAE,SAAS;IACvD,IAAI,EAAG,YAAY,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IAChC,UAAU,qBAA4B;IACtC,gBAAgB;oBAAkC,MAAM;kBAAY,MAAM;OAAM;IAEnF,KAAK,EAAE,uBAAuB,GAAG,IAAI,CAAQ;IAEpD,QAAQ,IAAI,IAAI;IAIhB,WAAW,IAAI,IAAI;IAInB,OAAO,CAAC,aAAa;IAWd,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM;IAYzC,SAAS,IAAI,IAAI;IASjB,YAAY,IAAI,IAAI;yCAhDhB,wBAAwB;2CAAxB,wBAAwB;CAwDpC"}
1
+ {"version":3,"file":"task-detail-panel.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/task-detail-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1F,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;;AAGvE;;;GAGG;AACH,qBA8Pa,wBAAyB,YAAW,MAAM,EAAE,SAAS;IACvD,IAAI,EAAG,YAAY,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IAChC,UAAU,qBAA4B;IACtC,gBAAgB;oBAAkC,MAAM;kBAAY,MAAM;OAAM;IAEnF,KAAK,EAAE,uBAAuB,GAAG,IAAI,CAAQ;IAEpD,QAAQ,IAAI,IAAI;IAIhB,WAAW,IAAI,IAAI;IAInB,OAAO,CAAC,aAAa;IAWd,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM;IAYzC,SAAS,IAAI,IAAI;IASjB,YAAY,IAAI,IAAI;yCAhDhB,wBAAwB;2CAAxB,wBAAwB;CAwDpC"}
@@ -1,5 +1,6 @@
1
1
  import { Component, Input, Output, EventEmitter } from '@angular/core';
2
2
  import { AIEngineBase } from '@memberjunction/ai-engine-base';
3
+ import { UUIDsEqual } from '@memberjunction/global';
3
4
  import * as i0 from "@angular/core";
4
5
  function TaskDetailPanelComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
5
6
  i0.ɵɵdomElementStart(0, "div", 5)(1, "label");
@@ -134,7 +135,7 @@ export class TaskDetailPanelComponent {
134
135
  }
135
136
  // Get agent from AIEngineBase
136
137
  const agents = AIEngineBase.Instance.Agents;
137
- this.agent = agents.find((a) => a.ID === this.task.AgentID) || null;
138
+ this.agent = agents.find((a) => UUIDsEqual(a.ID, this.task.AgentID)) || null;
138
139
  }
139
140
  formatDateTime(date) {
140
141
  if (!date)
@@ -310,5 +311,5 @@ export class TaskDetailPanelComponent {
310
311
  }], openEntityRecord: [{
311
312
  type: Output
312
313
  }] }); })();
313
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TaskDetailPanelComponent, { className: "TaskDetailPanelComponent", filePath: "src/lib/components/task-detail-panel.component.ts", lineNumber: 265 }); })();
314
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TaskDetailPanelComponent, { className: "TaskDetailPanelComponent", filePath: "src/lib/components/task-detail-panel.component.ts", lineNumber: 266 }); })();
314
315
  //# sourceMappingURL=task-detail-panel.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"task-detail-panel.component.js","sourceRoot":"","sources":["../../../src/lib/components/task-detail-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAqB,MAAM,eAAe,CAAC;AAG1F,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;;;IAuBlD,AADF,iCAA0B,YACjB;IAAA,2BAAW;IAAA,oBAAQ;IAC1B,4BAAG;IAAA,YAAsB;IAC3B,AAD2B,oBAAI,EACzB;;;IADD,eAAsB;IAAtB,6CAAsB;;;IAWzB,AADF,iCAA0B,YACjB;IAAA,wBAAQ;IAAA,oBAAQ;IAErB,AADF,iCAA6B,aACM;IAC/B,4BAA+E;IACjF,oBAAM;IACN,+BAAM;IAAA,YAA2B;IAErC,AADE,AADmC,oBAAO,EACpC,EACF;;;IAJkC,eAAsC;IAAtC,yDAAsC;IAEpE,eAA2B;IAA3B,2DAA2B;;;IAOnC,AADF,iCAA0B,YACjB;IAAA,uBAAO;IAAA,oBAAQ;IACtB,4BAAG;IAAA,YAAoC;IACzC,AADyC,oBAAI,EACvC;;;IADD,eAAoC;IAApC,kEAAoC;;;IAMvC,AADF,iCAA0B,YACjB;IAAA,mBAAG;IAAA,oBAAQ;IAClB,4BAAG;IAAA,YAAgC;IACrC,AADqC,oBAAI,EACnC;;;IADD,eAAgC;IAAhC,8DAAgC;;;IAMnC,AADF,iCAA0B,YACjB;IAAA,yBAAS;IAAA,oBAAQ;IACxB,4BAAG;IAAA,YAAsC;IAC3C,AAD2C,oBAAI,EACzC;;;IADD,eAAsC;IAAtC,oEAAsC;;;IAMzC,AADF,iCAA0B,YACjB;IAAA,6BAAa;IAAA,oBAAQ;IAC5B,4BAAG;IAAA,YAAe;IACpB,AADoB,oBAAI,EAClB;;;IADD,eAAe;IAAf,sCAAe;;;;IAOlB,AADF,iCAA0B,YACjB;IAAA,qBAAK;IAAA,oBAAQ;IACpB,iCAA8C;IAAtB,6LAAS,kBAAW,KAAC;IAC3C,2BAA0D;IAC1D,mCAAyB;IAAA,YAAgB;IAAA,oBAAO;IAChD,2BAAkD;IAEtD,AADE,oBAAM,EACF;;;IAJC,eAA+B;IAA/B,kCAA+B;IACT,eAAgB;IAAhB,uCAAgB;;;;IAS3C,AADF,iCAA0B,YACjB;IAAA,yBAAS;IAAA,oBAAQ;IACxB,kCAAqD;IAAzB,6LAAS,qBAAc,KAAC;IAClD,+BAAM;IAAA,gCAAgB;IAAA,oBAAO;IAC7B,2BAAkD;IAEtD,AADE,oBAAM,EACF;;AA1FhB;;;GAGG;AA+PH,MAAM,OAAO,wBAAwB;IAC1B,IAAI,CAAgB;IACpB,UAAU,GAAkB,IAAI,CAAC;IAChC,UAAU,GAAG,IAAI,YAAY,EAAQ,CAAC;IACtC,gBAAgB,GAAG,IAAI,YAAY,EAA4C,CAAC;IAEnF,KAAK,GAAmC,IAAI,CAAC;IAEpD,QAAQ;QACN,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAED,WAAW;QACT,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAEO,aAAa;QACnB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAClB,OAAO;QACT,CAAC;QAED,8BAA8B;QAC9B,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC5C,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAA0B,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;IAC/F,CAAC;IAEM,cAAc,CAAC,IAAiB;QACrC,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,OAAO,CAAC,CAAC,kBAAkB,CAAC,OAAO,EAAE;YACnC,KAAK,EAAE,OAAO;YACd,GAAG,EAAE,SAAS;YACd,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,SAAS;SAClB,CAAC,CAAC;IACL,CAAC;IAEM,SAAS;QACd,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACtB,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;gBACzB,UAAU,EAAE,eAAe;gBAC3B,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO;aAC5B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAEM,YAAY;QACjB,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;gBACzB,UAAU,EAAE,mBAAmB;gBAC/B,QAAQ,EAAE,IAAI,CAAC,UAAU;aAC1B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;kHAvDU,wBAAwB;6DAAxB,wBAAwB;YAvP7B,AADF,AADF,iCAA+B,aACF,SACrB;YAAA,YAAe;YAAA,oBAAK;YACxB,oCAA6D;YAA5B,wGAAS,qBAAiB,IAAC;YAC1D,0BAA4B;YAEhC,AADE,oBAAS,EACL;YAEN,iCAA4B;YAC1B,0FAAwB;YAQtB,AADF,iCAA0B,YACjB;YAAA,uBAAM;YAAA,oBAAQ;YACrB,6BAAG;YAAA,aAAiB;YACtB,AADsB,oBAAI,EACpB;YAEN,4FAAoC;YAYpC,4FAAsB;YAOtB,4FAAkB;YAOlB,4FAAwB;YAOxB,4FAAiB;YAQjB,4FAAa;YAYb,4FAAkB;YAUtB,AADE,oBAAM,EACF;;YAlFE,eAAe;YAAf,mCAAe;YAOnB,eAKC;YALD,+CAKC;YAII,eAAiB;YAAjB,qCAAiB;YAGtB,cAUC;YAVD,4DAUC;YAED,cAKC;YALD,8CAKC;YAED,cAKC;YALD,0CAKC;YAED,cAKC;YALD,gDAKC;YAED,cAKC;YALD,yCAKC;YAGD,cASC;YATD,qCASC;YAGD,cAQC;YARD,0CAQC;;;iFAuKI,wBAAwB;cA9PpC,SAAS;2BACE,sBAAsB,cACpB,IAAI,WACP,EAAE,YACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsFP;;kBAqKF,KAAK;;kBACL,KAAK;;kBACL,MAAM;;kBACN,MAAM;;kFAJI,wBAAwB","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, OnChanges } from '@angular/core';\n\nimport { MJTaskEntity } from '@memberjunction/core-entities';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { MJAIAgentEntityExtended } from '@memberjunction/ai-core-plus';\n\n/**\n * Task detail panel showing task information, agent details, and agent run\n * Reusable across list and Gantt views\n */\n@Component({\n selector: 'mj-task-detail-panel',\n standalone: true,\n imports: [],\n template: `\n <div class=\"task-detail-panel\">\n <div class=\"detail-header\">\n <h3>{{ task.Name }}</h3>\n <button class=\"close-detail-btn\" (click)=\"closePanel.emit()\">\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n \n <div class=\"detail-content\">\n @if (task.Description) {\n <div class=\"detail-field\">\n <label>Description</label>\n <p>{{ task.Description }}</p>\n </div>\n }\n \n <div class=\"detail-field\">\n <label>Status</label>\n <p>{{ task.Status }}</p>\n </div>\n \n @if (task.PercentComplete != null) {\n <div class=\"detail-field\">\n <label>Progress</label>\n <div class=\"detail-progress\">\n <div class=\"progress-bar-detail\">\n <div class=\"progress-fill-detail\" [style.width.%]=\"task.PercentComplete\"></div>\n </div>\n <span>{{ task.PercentComplete }}%</span>\n </div>\n </div>\n }\n \n @if (task.StartedAt) {\n <div class=\"detail-field\">\n <label>Started</label>\n <p>{{ formatDateTime(task.StartedAt) }}</p>\n </div>\n }\n \n @if (task.DueAt) {\n <div class=\"detail-field\">\n <label>Due</label>\n <p>{{ formatDateTime(task.DueAt) }}</p>\n </div>\n }\n \n @if (task.CompletedAt) {\n <div class=\"detail-field\">\n <label>Completed</label>\n <p>{{ formatDateTime(task.CompletedAt) }}</p>\n </div>\n }\n \n @if (task.User) {\n <div class=\"detail-field\">\n <label>Assigned User</label>\n <p>{{ task.User }}</p>\n </div>\n }\n \n <!-- Agent Information -->\n @if (agent) {\n <div class=\"detail-field\">\n <label>Agent</label>\n <div class=\"agent-info\" (click)=\"openAgent()\">\n <i [class]=\"'fas fa-' + ('robot')\" class=\"agent-icon\"></i>\n <span class=\"agent-name\">{{ agent.Name }}</span>\n <i class=\"fas fa-external-link-alt link-icon\"></i>\n </div>\n </div>\n }\n \n <!-- Agent Run Information -->\n @if (agentRunId) {\n <div class=\"detail-field\">\n <label>Agent Run</label>\n <div class=\"agent-run-link\" (click)=\"openAgentRun()\">\n <span>View Run Details</span>\n <i class=\"fas fa-external-link-alt link-icon\"></i>\n </div>\n </div>\n }\n </div>\n </div>\n `,\n styles: [`\n .task-detail-panel {\n width: 100%;\n height: calc(100% - 45px);\n background: white;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .detail-header {\n padding: 20px;\n border-bottom: 1px solid #E5E7EB;\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n background: #F9FAFB;\n flex-shrink: 0;\n }\n\n .detail-header h3 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: #111827;\n flex: 1;\n padding-right: 12px;\n }\n\n .close-detail-btn {\n background: none;\n border: none;\n color: #6B7280;\n cursor: pointer;\n padding: 4px;\n width: 28px;\n height: 28px;\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n }\n\n .close-detail-btn:hover {\n background: #E5E7EB;\n color: #111827;\n }\n\n .detail-content {\n padding: 20px;\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n }\n\n .detail-field {\n margin-bottom: 20px;\n }\n\n .detail-field:last-child {\n margin-bottom: 0;\n }\n\n .detail-field label {\n display: block;\n font-size: 12px;\n font-weight: 600;\n color: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 6px;\n }\n\n .detail-field p {\n margin: 0;\n font-size: 14px;\n color: #111827;\n line-height: 1.5;\n }\n\n .detail-progress {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .progress-bar-detail {\n flex: 1;\n height: 8px;\n background: #E5E7EB;\n border-radius: 4px;\n overflow: hidden;\n }\n\n .progress-fill-detail {\n height: calc(100% - 69px);\n background: #3B82F6;\n transition: width 0.3s ease;\n }\n\n .detail-progress span {\n font-size: 13px;\n font-weight: 600;\n color: #6B7280;\n min-width: 40px;\n }\n\n .agent-info {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n background: #F3F4F6;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .agent-info:hover {\n background: #E5E7EB;\n }\n\n .agent-icon {\n font-size: 18px;\n color: #3B82F6;\n }\n\n .agent-name {\n flex: 1;\n font-size: 14px;\n font-weight: 500;\n color: #111827;\n }\n\n .link-icon {\n font-size: 12px;\n color: #6B7280;\n }\n\n .agent-run-link {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n background: #F3F4F6;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .agent-run-link:hover {\n background: #E5E7EB;\n }\n\n .agent-run-link span {\n flex: 1;\n font-size: 14px;\n font-weight: 500;\n color: #111827;\n }\n `]\n})\nexport class TaskDetailPanelComponent implements OnInit, OnChanges {\n @Input() task!: MJTaskEntity;\n @Input() agentRunId: string | null = null;\n @Output() closePanel = new EventEmitter<void>();\n @Output() openEntityRecord = new EventEmitter<{ entityName: string; recordId: string }>();\n\n public agent: MJAIAgentEntityExtended | null = null;\n\n ngOnInit(): void {\n this.loadAgentInfo();\n }\n\n ngOnChanges(): void {\n this.loadAgentInfo();\n }\n\n private loadAgentInfo(): void {\n if (!this.task?.AgentID) {\n this.agent = null;\n return;\n }\n\n // Get agent from AIEngineBase\n const agents = AIEngineBase.Instance.Agents;\n this.agent = agents.find((a: MJAIAgentEntityExtended) => a.ID === this.task.AgentID) || null;\n }\n\n public formatDateTime(date: Date | null): string {\n if (!date) return '';\n const d = new Date(date);\n return d.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n hour: '2-digit',\n minute: '2-digit'\n });\n }\n\n public openAgent(): void {\n if (this.task.AgentID) {\n this.openEntityRecord.emit({\n entityName: 'MJ: AI Agents',\n recordId: this.task.AgentID\n });\n }\n }\n\n public openAgentRun(): void {\n if (this.agentRunId) {\n this.openEntityRecord.emit({\n entityName: 'MJ: AI Agent Runs',\n recordId: this.agentRunId\n });\n }\n }\n}\n"]}
1
+ {"version":3,"file":"task-detail-panel.component.js","sourceRoot":"","sources":["../../../src/lib/components/task-detail-panel.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, OnChanges } from '@angular/core';\n\nimport { MJTaskEntity } from '@memberjunction/core-entities';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { MJAIAgentEntityExtended } from '@memberjunction/ai-core-plus';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n/**\n * Task detail panel showing task information, agent details, and agent run\n * Reusable across list and Gantt views\n */\n@Component({\n selector: 'mj-task-detail-panel',\n standalone: true,\n imports: [],\n template: `\n <div class=\"task-detail-panel\">\n <div class=\"detail-header\">\n <h3>{{ task.Name }}</h3>\n <button class=\"close-detail-btn\" (click)=\"closePanel.emit()\">\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n \n <div class=\"detail-content\">\n @if (task.Description) {\n <div class=\"detail-field\">\n <label>Description</label>\n <p>{{ task.Description }}</p>\n </div>\n }\n \n <div class=\"detail-field\">\n <label>Status</label>\n <p>{{ task.Status }}</p>\n </div>\n \n @if (task.PercentComplete != null) {\n <div class=\"detail-field\">\n <label>Progress</label>\n <div class=\"detail-progress\">\n <div class=\"progress-bar-detail\">\n <div class=\"progress-fill-detail\" [style.width.%]=\"task.PercentComplete\"></div>\n </div>\n <span>{{ task.PercentComplete }}%</span>\n </div>\n </div>\n }\n \n @if (task.StartedAt) {\n <div class=\"detail-field\">\n <label>Started</label>\n <p>{{ formatDateTime(task.StartedAt) }}</p>\n </div>\n }\n \n @if (task.DueAt) {\n <div class=\"detail-field\">\n <label>Due</label>\n <p>{{ formatDateTime(task.DueAt) }}</p>\n </div>\n }\n \n @if (task.CompletedAt) {\n <div class=\"detail-field\">\n <label>Completed</label>\n <p>{{ formatDateTime(task.CompletedAt) }}</p>\n </div>\n }\n \n @if (task.User) {\n <div class=\"detail-field\">\n <label>Assigned User</label>\n <p>{{ task.User }}</p>\n </div>\n }\n \n <!-- Agent Information -->\n @if (agent) {\n <div class=\"detail-field\">\n <label>Agent</label>\n <div class=\"agent-info\" (click)=\"openAgent()\">\n <i [class]=\"'fas fa-' + ('robot')\" class=\"agent-icon\"></i>\n <span class=\"agent-name\">{{ agent.Name }}</span>\n <i class=\"fas fa-external-link-alt link-icon\"></i>\n </div>\n </div>\n }\n \n <!-- Agent Run Information -->\n @if (agentRunId) {\n <div class=\"detail-field\">\n <label>Agent Run</label>\n <div class=\"agent-run-link\" (click)=\"openAgentRun()\">\n <span>View Run Details</span>\n <i class=\"fas fa-external-link-alt link-icon\"></i>\n </div>\n </div>\n }\n </div>\n </div>\n `,\n styles: [`\n .task-detail-panel {\n width: 100%;\n height: calc(100% - 45px);\n background: white;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .detail-header {\n padding: 20px;\n border-bottom: 1px solid #E5E7EB;\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n background: #F9FAFB;\n flex-shrink: 0;\n }\n\n .detail-header h3 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: #111827;\n flex: 1;\n padding-right: 12px;\n }\n\n .close-detail-btn {\n background: none;\n border: none;\n color: #6B7280;\n cursor: pointer;\n padding: 4px;\n width: 28px;\n height: 28px;\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n }\n\n .close-detail-btn:hover {\n background: #E5E7EB;\n color: #111827;\n }\n\n .detail-content {\n padding: 20px;\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n }\n\n .detail-field {\n margin-bottom: 20px;\n }\n\n .detail-field:last-child {\n margin-bottom: 0;\n }\n\n .detail-field label {\n display: block;\n font-size: 12px;\n font-weight: 600;\n color: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 6px;\n }\n\n .detail-field p {\n margin: 0;\n font-size: 14px;\n color: #111827;\n line-height: 1.5;\n }\n\n .detail-progress {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .progress-bar-detail {\n flex: 1;\n height: 8px;\n background: #E5E7EB;\n border-radius: 4px;\n overflow: hidden;\n }\n\n .progress-fill-detail {\n height: calc(100% - 69px);\n background: #3B82F6;\n transition: width 0.3s ease;\n }\n\n .detail-progress span {\n font-size: 13px;\n font-weight: 600;\n color: #6B7280;\n min-width: 40px;\n }\n\n .agent-info {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n background: #F3F4F6;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .agent-info:hover {\n background: #E5E7EB;\n }\n\n .agent-icon {\n font-size: 18px;\n color: #3B82F6;\n }\n\n .agent-name {\n flex: 1;\n font-size: 14px;\n font-weight: 500;\n color: #111827;\n }\n\n .link-icon {\n font-size: 12px;\n color: #6B7280;\n }\n\n .agent-run-link {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n background: #F3F4F6;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .agent-run-link:hover {\n background: #E5E7EB;\n }\n\n .agent-run-link span {\n flex: 1;\n font-size: 14px;\n font-weight: 500;\n color: #111827;\n }\n `]\n})\nexport class TaskDetailPanelComponent implements OnInit, OnChanges {\n @Input() task!: MJTaskEntity;\n @Input() agentRunId: string | null = null;\n @Output() closePanel = new EventEmitter<void>();\n @Output() openEntityRecord = new EventEmitter<{ entityName: string; recordId: string }>();\n\n public agent: MJAIAgentEntityExtended | null = null;\n\n ngOnInit(): void {\n this.loadAgentInfo();\n }\n\n ngOnChanges(): void {\n this.loadAgentInfo();\n }\n\n private loadAgentInfo(): void {\n if (!this.task?.AgentID) {\n this.agent = null;\n return;\n }\n\n // Get agent from AIEngineBase\n const agents = AIEngineBase.Instance.Agents;\n this.agent = agents.find((a: MJAIAgentEntityExtended) => UUIDsEqual(a.ID, this.task.AgentID)) || null;\n }\n\n public formatDateTime(date: Date | null): string {\n if (!date) return '';\n const d = new Date(date);\n return d.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n hour: '2-digit',\n minute: '2-digit'\n });\n }\n\n public openAgent(): void {\n if (this.task.AgentID) {\n this.openEntityRecord.emit({\n entityName: 'MJ: AI Agents',\n recordId: this.task.AgentID\n });\n }\n }\n\n public openAgentRun(): void {\n if (this.agentRunId) {\n this.openEntityRecord.emit({\n entityName: 'MJ: AI Agent Runs',\n recordId: this.agentRunId\n });\n }\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-tasks",
3
- "version": "5.4.1",
3
+ "version": "5.5.0",
4
4
  "description": "MemberJunction: Angular components for task visualization and management with Gantt chart support",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -15,10 +15,10 @@
15
15
  "@angular/common": "21.1.3",
16
16
  "@angular/core": "21.1.3",
17
17
  "@angular/platform-browser": "21.1.3",
18
- "@memberjunction/core": "5.4.1",
19
- "@memberjunction/core-entities": "5.4.1",
20
- "@memberjunction/ai-core-plus": "5.4.1",
21
- "@memberjunction/ai-engine-base": "5.4.1",
18
+ "@memberjunction/core": "5.5.0",
19
+ "@memberjunction/core-entities": "5.5.0",
20
+ "@memberjunction/ai-core-plus": "5.5.0",
21
+ "@memberjunction/ai-engine-base": "5.5.0",
22
22
  "dhtmlx-gantt": "^9.1.1",
23
23
  "rxjs": "^7.8.2"
24
24
  },
@@ -3,6 +3,7 @@ import { Component, Input, Output, EventEmitter, OnChanges, AfterViewInit, Eleme
3
3
  import { MJTaskEntity, MJTaskDependencyEntity } from '@memberjunction/core-entities';
4
4
  import { gantt } from 'dhtmlx-gantt';
5
5
  import { TaskDetailPanelComponent } from './task-detail-panel.component';
6
+ import { UUIDsEqual } from '@memberjunction/global';
6
7
 
7
8
  /**
8
9
  * Gantt chart view for tasks using DHTMLX Gantt
@@ -221,7 +222,7 @@ export class GanttTaskViewerComponent implements OnChanges, AfterViewInit, OnDes
221
222
 
222
223
  // Attach click event
223
224
  gantt.attachEvent('onTaskClick', (id: string) => {
224
- const originalTask = this.tasks.find(t => t.ID === id);
225
+ const originalTask = this.tasks.find(t => UUIDsEqual(t.ID, id));
225
226
  if (originalTask) {
226
227
  this.selectedTask = originalTask;
227
228
  this.taskClicked.emit(originalTask);
@@ -515,7 +516,7 @@ export class GanttTaskViewerComponent implements OnChanges, AfterViewInit, OnDes
515
516
  if (rootTask) {
516
517
  gantt.selectTask(rootTask.id);
517
518
  // Trigger task click event to open detail panel
518
- const originalTask = this.tasks.find(t => t.ID === rootTask.id);
519
+ const originalTask = this.tasks.find(t => UUIDsEqual(t.ID, rootTask.id));
519
520
  if (originalTask) {
520
521
  this.selectedTask = originalTask;
521
522
  this.taskClicked.emit(originalTask);
@@ -2,6 +2,7 @@ import { Component, Input, Output, EventEmitter, OnChanges, HostListener } from
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { MJTaskEntity } from '@memberjunction/core-entities';
4
4
  import { TaskDetailPanelComponent } from './task-detail-panel.component';
5
+ import { UUIDsEqual } from '@memberjunction/global';
5
6
 
6
7
  /**
7
8
  * Simple list view for tasks
@@ -18,7 +19,7 @@ import { TaskDetailPanelComponent } from './task-detail-panel.component';
18
19
  <div
19
20
  class="task-item"
20
21
  [class.completed]="task.Status === 'Complete'"
21
- [class.selected]="selectedTask?.ID === task.ID"
22
+ [class.selected]="IsTaskSelected(task)"
22
23
  (click)="onTaskClick(task)">
23
24
  <!-- Status Icon -->
24
25
  <div class="status-icon" [class.complete]="task.Status === 'Complete'">
@@ -301,6 +302,10 @@ export class SimpleTaskViewerComponent implements OnChanges {
301
302
  @Output() openEntityRecord = new EventEmitter<{ entityName: string; recordId: string }>();
302
303
 
303
304
  public selectedTask: MJTaskEntity | null = null;
305
+
306
+ public IsTaskSelected(task: MJTaskEntity): boolean {
307
+ return UUIDsEqual(this.selectedTask?.ID, task.ID);
308
+ }
304
309
  public detailPanelWidth: number = 400;
305
310
 
306
311
  private isResizing = false;
@@ -3,6 +3,7 @@ import { Component, Input, Output, EventEmitter, OnInit, OnChanges } from '@angu
3
3
  import { MJTaskEntity } from '@memberjunction/core-entities';
4
4
  import { AIEngineBase } from '@memberjunction/ai-engine-base';
5
5
  import { MJAIAgentEntityExtended } from '@memberjunction/ai-core-plus';
6
+ import { UUIDsEqual } from '@memberjunction/global';
6
7
 
7
8
  /**
8
9
  * Task detail panel showing task information, agent details, and agent run
@@ -286,7 +287,7 @@ export class TaskDetailPanelComponent implements OnInit, OnChanges {
286
287
 
287
288
  // Get agent from AIEngineBase
288
289
  const agents = AIEngineBase.Instance.Agents;
289
- this.agent = agents.find((a: MJAIAgentEntityExtended) => a.ID === this.task.AgentID) || null;
290
+ this.agent = agents.find((a: MJAIAgentEntityExtended) => UUIDsEqual(a.ID, this.task.AgentID)) || null;
290
291
  }
291
292
 
292
293
  public formatDateTime(date: Date | null): string {