@memberjunction/ng-conversations 5.4.0 → 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.
Files changed (69) hide show
  1. package/dist/lib/components/agent/agent-process-panel.component.d.ts.map +1 -1
  2. package/dist/lib/components/agent/agent-process-panel.component.js +3 -2
  3. package/dist/lib/components/agent/agent-process-panel.component.js.map +1 -1
  4. package/dist/lib/components/collection/artifact-collection-picker-modal.component.d.ts.map +1 -1
  5. package/dist/lib/components/collection/artifact-collection-picker-modal.component.js +10 -9
  6. package/dist/lib/components/collection/artifact-collection-picker-modal.component.js.map +1 -1
  7. package/dist/lib/components/collection/artifact-create-modal.component.d.ts.map +1 -1
  8. package/dist/lib/components/collection/artifact-create-modal.component.js +3 -2
  9. package/dist/lib/components/collection/artifact-create-modal.component.js.map +1 -1
  10. package/dist/lib/components/collection/collection-form-modal.component.d.ts.map +1 -1
  11. package/dist/lib/components/collection/collection-form-modal.component.js +4 -3
  12. package/dist/lib/components/collection/collection-form-modal.component.js.map +1 -1
  13. package/dist/lib/components/collection/collection-share-modal.component.d.ts.map +1 -1
  14. package/dist/lib/components/collection/collection-share-modal.component.js +5 -4
  15. package/dist/lib/components/collection/collection-share-modal.component.js.map +1 -1
  16. package/dist/lib/components/collection/collection-tree.component.d.ts +2 -0
  17. package/dist/lib/components/collection/collection-tree.component.d.ts.map +1 -1
  18. package/dist/lib/components/collection/collection-tree.component.js +24 -17
  19. package/dist/lib/components/collection/collection-tree.component.js.map +1 -1
  20. package/dist/lib/components/collection/collections-full-view.component.d.ts +1 -0
  21. package/dist/lib/components/collection/collections-full-view.component.d.ts.map +1 -1
  22. package/dist/lib/components/collection/collections-full-view.component.js +14 -10
  23. package/dist/lib/components/collection/collections-full-view.component.js.map +1 -1
  24. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +21 -7
  25. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  26. package/dist/lib/components/conversation/conversation-chat-area.component.js +44 -14
  27. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  28. package/dist/lib/components/conversation/conversation-list.component.d.ts +3 -0
  29. package/dist/lib/components/conversation/conversation-list.component.d.ts.map +1 -1
  30. package/dist/lib/components/conversation/conversation-list.component.js +21 -11
  31. package/dist/lib/components/conversation/conversation-list.component.js.map +1 -1
  32. package/dist/lib/components/mention/mention-editor.component.d.ts.map +1 -1
  33. package/dist/lib/components/mention/mention-editor.component.js +4 -3
  34. package/dist/lib/components/mention/mention-editor.component.js.map +1 -1
  35. package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -1
  36. package/dist/lib/components/message/conversation-message-rating.component.js +3 -2
  37. package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -1
  38. package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
  39. package/dist/lib/components/message/message-input.component.js +21 -7
  40. package/dist/lib/components/message/message-input.component.js.map +1 -1
  41. package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
  42. package/dist/lib/components/message/message-item.component.js +7 -6
  43. package/dist/lib/components/message/message-item.component.js.map +1 -1
  44. package/dist/lib/components/project/project-selector.component.d.ts.map +1 -1
  45. package/dist/lib/components/project/project-selector.component.js +3 -2
  46. package/dist/lib/components/project/project-selector.component.js.map +1 -1
  47. package/dist/lib/components/task/tasks-full-view.component.d.ts.map +1 -1
  48. package/dist/lib/components/task/tasks-full-view.component.js +4 -3
  49. package/dist/lib/components/task/tasks-full-view.component.js.map +1 -1
  50. package/dist/lib/services/agent-state.service.d.ts +4 -0
  51. package/dist/lib/services/agent-state.service.d.ts.map +1 -1
  52. package/dist/lib/services/agent-state.service.js +15 -6
  53. package/dist/lib/services/agent-state.service.js.map +1 -1
  54. package/dist/lib/services/artifact-permission.service.d.ts.map +1 -1
  55. package/dist/lib/services/artifact-permission.service.js +3 -2
  56. package/dist/lib/services/artifact-permission.service.js.map +1 -1
  57. package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
  58. package/dist/lib/services/conversation-agent.service.js +5 -4
  59. package/dist/lib/services/conversation-agent.service.js.map +1 -1
  60. package/dist/lib/services/conversation-attachment.service.d.ts.map +1 -1
  61. package/dist/lib/services/conversation-attachment.service.js +2 -1
  62. package/dist/lib/services/conversation-attachment.service.js.map +1 -1
  63. package/dist/lib/services/conversation-data.service.d.ts.map +1 -1
  64. package/dist/lib/services/conversation-data.service.js +7 -6
  65. package/dist/lib/services/conversation-data.service.js.map +1 -1
  66. package/dist/lib/services/data-cache.service.d.ts.map +1 -1
  67. package/dist/lib/services/data-cache.service.js +9 -8
  68. package/dist/lib/services/data-cache.service.js.map +1 -1
  69. package/package.json +17 -17
@@ -1,6 +1,7 @@
1
1
  import { Component, Input, Output, EventEmitter } from '@angular/core';
2
2
  import { RunView, Metadata } from '@memberjunction/core';
3
3
  import { ProjectFormModalComponent } from './project-form-modal.component';
4
+ import { UUIDsEqual } from '@memberjunction/global';
4
5
  import * as i0 from "@angular/core";
5
6
  import * as i1 from "../../services/dialog.service";
6
7
  import * as i2 from "@progress/kendo-angular-dialog";
@@ -114,7 +115,7 @@ export class ProjectSelectorComponent {
114
115
  return projectWithStats;
115
116
  });
116
117
  if (this.selectedProjectId) {
117
- this.selectedProject = this.projectsWithStats.find(p => p.ID === this.selectedProjectId) || null;
118
+ this.selectedProject = this.projectsWithStats.find(p => UUIDsEqual(p.ID, this.selectedProjectId)) || null;
118
119
  }
119
120
  }
120
121
  }
@@ -313,5 +314,5 @@ export class ProjectSelectorComponent {
313
314
  }], projectDeleted: [{
314
315
  type: Output
315
316
  }] }); })();
316
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ProjectSelectorComponent, { className: "ProjectSelectorComponent", filePath: "src/lib/components/project/project-selector.component.ts", lineNumber: 120 }); })();
317
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ProjectSelectorComponent, { className: "ProjectSelectorComponent", filePath: "src/lib/components/project/project-selector.component.ts", lineNumber: 121 }); })();
317
318
  //# sourceMappingURL=project-selector.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"project-selector.component.js","sourceRoot":"","sources":["../../../../src/lib/components/project/project-selector.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, ViewContainerRef } from '@angular/core';\nimport { MJProjectEntity, MJConversationEntity } from '@memberjunction/core-entities';\nimport { UserInfo, RunView, Metadata } from '@memberjunction/core';\nimport { DialogService as KendoDialogService } from '@progress/kendo-angular-dialog';\nimport { DialogService } from '../../services/dialog.service';\nimport { ProjectFormModalComponent } from './project-form-modal.component';\n\nexport interface ProjectWithStats extends MJProjectEntity {\n conversationCount?: number;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-project-selector',\n template: `\n <div class=\"project-selector\">\n <kendo-dropdownlist\n [data]=\"projectsWithStats\"\n [value]=\"selectedProject\"\n [textField]=\"'Name'\"\n [valueField]=\"'ID'\"\n [disabled]=\"disabled\"\n (valueChange)=\"onProjectChange($event)\">\n <ng-template kendoDropDownListItemTemplate let-dataItem>\n <div class=\"project-item\">\n <i class=\"fa-solid {{ dataItem.Icon || 'fa-folder' }}\"\n [style.color]=\"dataItem.Color || '#0076B6'\"></i>\n <div class=\"project-info\">\n <span class=\"project-name\">{{ dataItem.Name }}</span>\n @if (showStats && dataItem.conversationCount != null) {\n <span class=\"project-stats\">{{ dataItem.conversationCount }} conversations</span>\n }\n </div>\n </div>\n </ng-template>\n <ng-template kendoDropDownListValueTemplate let-dataItem>\n <div class=\"project-item\">\n <i class=\"fa-solid {{ dataItem.Icon || 'fa-folder' }}\"\n [style.color]=\"dataItem.Color || '#0076B6'\"></i>\n <span>{{ dataItem.Name }}</span>\n </div>\n </ng-template>\n </kendo-dropdownlist>\n\n <div class=\"project-actions\">\n @if (selectedProject) {\n <button\n kendoButton\n [icon]=\"'edit'\"\n [disabled]=\"disabled\"\n (click)=\"onEditProject()\"\n title=\"Edit Project\"\n class=\"btn-icon\">\n </button>\n <button\n kendoButton\n [icon]=\"'trash'\"\n [disabled]=\"disabled\"\n (click)=\"onDeleteProject()\"\n title=\"Delete Project\"\n class=\"btn-icon btn-danger\">\n </button>\n }\n <button\n kendoButton\n [icon]=\"'plus'\"\n [disabled]=\"disabled\"\n (click)=\"onCreateProject()\"\n title=\"Create New Project\"\n [themeColor]=\"'primary'\"\n class=\"btn-icon\">\n </button>\n </div>\n </div>\n `,\n styles: [`\n .project-selector {\n display: flex;\n gap: 8px;\n align-items: center;\n }\n .project-selector kendo-dropdownlist {\n flex: 1;\n min-width: 200px;\n }\n .project-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 0;\n }\n .project-info {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n .project-name {\n font-weight: 500;\n color: #333;\n }\n .project-stats {\n font-size: 12px;\n color: #666;\n }\n .project-actions {\n display: flex;\n gap: 4px;\n }\n .btn-icon {\n min-width: auto;\n padding: 6px 8px;\n }\n .btn-danger:hover:not(:disabled) {\n background-color: #F44336;\n border-color: #F44336;\n color: white;\n }\n `]\n})\nexport class ProjectSelectorComponent implements OnInit {\n @Input() environmentId!: string;\n @Input() currentUser!: UserInfo;\n @Input() selectedProjectId: string | null = null;\n @Input() disabled: boolean = false;\n @Input() showStats: boolean = true;\n\n @Output() projectSelected = new EventEmitter<MJProjectEntity | null>();\n @Output() projectCreated = new EventEmitter<MJProjectEntity>();\n @Output() projectUpdated = new EventEmitter<MJProjectEntity>();\n @Output() projectDeleted = new EventEmitter<string>();\n\n public projectsWithStats: ProjectWithStats[] = [];\n public selectedProject: MJProjectEntity | null = null;\n\n constructor(\n private dialogService: DialogService,\n private kendoDialogService: KendoDialogService,\n private viewContainerRef: ViewContainerRef\n ) {}\n\n ngOnInit() {\n this.loadProjects();\n }\n\n private async loadProjects(): Promise<void> {\n try {\n const rv = new RunView();\n\n // Load projects and conversation counts in parallel\n const [projectsResult, conversationsResult] = await rv.RunViews([\n {\n EntityName: 'MJ: Projects',\n ExtraFilter: `EnvironmentID='${this.environmentId}' AND IsArchived=0`,\n OrderBy: 'Name ASC',\n ResultType: 'entity_object'\n },\n {\n EntityName: 'MJ: Conversations',\n ExtraFilter: `EnvironmentID='${this.environmentId}'`,\n ResultType: 'entity_object'\n }\n ], this.currentUser);\n\n if (projectsResult.Success && conversationsResult.Success) {\n const projects = projectsResult.Results as MJProjectEntity[] || [];\n const conversations = conversationsResult.Results as MJConversationEntity[] || [];\n\n // Calculate conversation counts per project\n const conversationCounts = this.calculateConversationCounts(conversations);\n\n // Merge projects with stats\n this.projectsWithStats = projects.map(p => {\n const projectWithStats = p as ProjectWithStats;\n projectWithStats.conversationCount = conversationCounts.get(p.ID) || 0;\n return projectWithStats;\n });\n\n if (this.selectedProjectId) {\n this.selectedProject = this.projectsWithStats.find(p => p.ID === this.selectedProjectId) || null;\n }\n }\n } catch (error) {\n console.error('Error loading projects:', error);\n }\n }\n\n private calculateConversationCounts(conversations: MJConversationEntity[]): Map<string, number> {\n const counts = new Map<string, number>();\n\n for (const conv of conversations) {\n if (conv.ProjectID) {\n counts.set(conv.ProjectID, (counts.get(conv.ProjectID) || 0) + 1);\n }\n }\n\n return counts;\n }\n\n onProjectChange(project: MJProjectEntity | null): void {\n this.selectedProject = project;\n this.projectSelected.emit(project);\n }\n\n onCreateProject(): void {\n const dialogRef = this.kendoDialogService.open({\n content: ProjectFormModalComponent,\n width: 600,\n minWidth: 400\n });\n\n const modalInstance = dialogRef.content.instance as ProjectFormModalComponent;\n modalInstance.dialogRef = dialogRef;\n modalInstance.environmentId = this.environmentId;\n modalInstance.currentUser = this.currentUser;\n\n modalInstance.projectSaved.subscribe(async (project: MJProjectEntity) => {\n this.projectCreated.emit(project);\n await this.loadProjects();\n this.selectedProject = project;\n this.projectSelected.emit(project);\n });\n }\n\n onEditProject(): void {\n if (!this.selectedProject) return;\n\n const dialogRef = this.kendoDialogService.open({\n content: ProjectFormModalComponent,\n width: 600,\n minWidth: 400\n });\n\n const modalInstance = dialogRef.content.instance as ProjectFormModalComponent;\n modalInstance.dialogRef = dialogRef;\n modalInstance.project = this.selectedProject;\n modalInstance.environmentId = this.environmentId;\n modalInstance.currentUser = this.currentUser;\n\n modalInstance.projectSaved.subscribe(async (project: MJProjectEntity) => {\n this.projectUpdated.emit(project);\n await this.loadProjects();\n this.selectedProject = project;\n this.projectSelected.emit(project);\n });\n }\n\n async onDeleteProject(): Promise<void> {\n if (!this.selectedProject) return;\n\n const projectName = this.selectedProject.Name;\n const projectId = this.selectedProject.ID;\n const conversationCount = (this.selectedProject as ProjectWithStats).conversationCount || 0;\n\n let message = `Are you sure you want to delete the project \"${projectName}\"?`;\n if (conversationCount > 0) {\n message += `\\n\\nThis project has ${conversationCount} conversation(s). The conversations will not be deleted, but will be unassigned from this project.`;\n }\n\n const confirmed = await this.dialogService.confirm({\n title: 'Delete Project',\n message: message,\n okText: 'Delete',\n cancelText: 'Cancel',\n dangerous: true\n });\n\n if (!confirmed) return;\n\n try {\n const md = new Metadata();\n const project = await md.GetEntityObject<MJProjectEntity>('MJ: Projects', this.currentUser);\n await project.Load(projectId);\n\n const deleted = await project.Delete();\n if (deleted) {\n this.projectDeleted.emit(projectId);\n await this.loadProjects();\n this.selectedProject = null;\n this.projectSelected.emit(null);\n } else {\n throw new Error('Delete operation returned false');\n }\n } catch (error) {\n console.error('Error deleting project:', error);\n await this.dialogService.alert('Error', 'Failed to delete project. Please try again.');\n }\n }\n}"]}
1
+ {"version":3,"file":"project-selector.component.js","sourceRoot":"","sources":["../../../../src/lib/components/project/project-selector.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, ViewContainerRef } from '@angular/core';\nimport { MJProjectEntity, MJConversationEntity } from '@memberjunction/core-entities';\nimport { UserInfo, RunView, Metadata } from '@memberjunction/core';\nimport { DialogService as KendoDialogService } from '@progress/kendo-angular-dialog';\nimport { DialogService } from '../../services/dialog.service';\nimport { ProjectFormModalComponent } from './project-form-modal.component';\nimport { UUIDsEqual } from '@memberjunction/global';\n\nexport interface ProjectWithStats extends MJProjectEntity {\n conversationCount?: number;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-project-selector',\n template: `\n <div class=\"project-selector\">\n <kendo-dropdownlist\n [data]=\"projectsWithStats\"\n [value]=\"selectedProject\"\n [textField]=\"'Name'\"\n [valueField]=\"'ID'\"\n [disabled]=\"disabled\"\n (valueChange)=\"onProjectChange($event)\">\n <ng-template kendoDropDownListItemTemplate let-dataItem>\n <div class=\"project-item\">\n <i class=\"fa-solid {{ dataItem.Icon || 'fa-folder' }}\"\n [style.color]=\"dataItem.Color || '#0076B6'\"></i>\n <div class=\"project-info\">\n <span class=\"project-name\">{{ dataItem.Name }}</span>\n @if (showStats && dataItem.conversationCount != null) {\n <span class=\"project-stats\">{{ dataItem.conversationCount }} conversations</span>\n }\n </div>\n </div>\n </ng-template>\n <ng-template kendoDropDownListValueTemplate let-dataItem>\n <div class=\"project-item\">\n <i class=\"fa-solid {{ dataItem.Icon || 'fa-folder' }}\"\n [style.color]=\"dataItem.Color || '#0076B6'\"></i>\n <span>{{ dataItem.Name }}</span>\n </div>\n </ng-template>\n </kendo-dropdownlist>\n\n <div class=\"project-actions\">\n @if (selectedProject) {\n <button\n kendoButton\n [icon]=\"'edit'\"\n [disabled]=\"disabled\"\n (click)=\"onEditProject()\"\n title=\"Edit Project\"\n class=\"btn-icon\">\n </button>\n <button\n kendoButton\n [icon]=\"'trash'\"\n [disabled]=\"disabled\"\n (click)=\"onDeleteProject()\"\n title=\"Delete Project\"\n class=\"btn-icon btn-danger\">\n </button>\n }\n <button\n kendoButton\n [icon]=\"'plus'\"\n [disabled]=\"disabled\"\n (click)=\"onCreateProject()\"\n title=\"Create New Project\"\n [themeColor]=\"'primary'\"\n class=\"btn-icon\">\n </button>\n </div>\n </div>\n `,\n styles: [`\n .project-selector {\n display: flex;\n gap: 8px;\n align-items: center;\n }\n .project-selector kendo-dropdownlist {\n flex: 1;\n min-width: 200px;\n }\n .project-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 0;\n }\n .project-info {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n .project-name {\n font-weight: 500;\n color: #333;\n }\n .project-stats {\n font-size: 12px;\n color: #666;\n }\n .project-actions {\n display: flex;\n gap: 4px;\n }\n .btn-icon {\n min-width: auto;\n padding: 6px 8px;\n }\n .btn-danger:hover:not(:disabled) {\n background-color: #F44336;\n border-color: #F44336;\n color: white;\n }\n `]\n})\nexport class ProjectSelectorComponent implements OnInit {\n @Input() environmentId!: string;\n @Input() currentUser!: UserInfo;\n @Input() selectedProjectId: string | null = null;\n @Input() disabled: boolean = false;\n @Input() showStats: boolean = true;\n\n @Output() projectSelected = new EventEmitter<MJProjectEntity | null>();\n @Output() projectCreated = new EventEmitter<MJProjectEntity>();\n @Output() projectUpdated = new EventEmitter<MJProjectEntity>();\n @Output() projectDeleted = new EventEmitter<string>();\n\n public projectsWithStats: ProjectWithStats[] = [];\n public selectedProject: MJProjectEntity | null = null;\n\n constructor(\n private dialogService: DialogService,\n private kendoDialogService: KendoDialogService,\n private viewContainerRef: ViewContainerRef\n ) {}\n\n ngOnInit() {\n this.loadProjects();\n }\n\n private async loadProjects(): Promise<void> {\n try {\n const rv = new RunView();\n\n // Load projects and conversation counts in parallel\n const [projectsResult, conversationsResult] = await rv.RunViews([\n {\n EntityName: 'MJ: Projects',\n ExtraFilter: `EnvironmentID='${this.environmentId}' AND IsArchived=0`,\n OrderBy: 'Name ASC',\n ResultType: 'entity_object'\n },\n {\n EntityName: 'MJ: Conversations',\n ExtraFilter: `EnvironmentID='${this.environmentId}'`,\n ResultType: 'entity_object'\n }\n ], this.currentUser);\n\n if (projectsResult.Success && conversationsResult.Success) {\n const projects = projectsResult.Results as MJProjectEntity[] || [];\n const conversations = conversationsResult.Results as MJConversationEntity[] || [];\n\n // Calculate conversation counts per project\n const conversationCounts = this.calculateConversationCounts(conversations);\n\n // Merge projects with stats\n this.projectsWithStats = projects.map(p => {\n const projectWithStats = p as ProjectWithStats;\n projectWithStats.conversationCount = conversationCounts.get(p.ID) || 0;\n return projectWithStats;\n });\n\n if (this.selectedProjectId) {\n this.selectedProject = this.projectsWithStats.find(p => UUIDsEqual(p.ID, this.selectedProjectId)) || null;\n }\n }\n } catch (error) {\n console.error('Error loading projects:', error);\n }\n }\n\n private calculateConversationCounts(conversations: MJConversationEntity[]): Map<string, number> {\n const counts = new Map<string, number>();\n\n for (const conv of conversations) {\n if (conv.ProjectID) {\n counts.set(conv.ProjectID, (counts.get(conv.ProjectID) || 0) + 1);\n }\n }\n\n return counts;\n }\n\n onProjectChange(project: MJProjectEntity | null): void {\n this.selectedProject = project;\n this.projectSelected.emit(project);\n }\n\n onCreateProject(): void {\n const dialogRef = this.kendoDialogService.open({\n content: ProjectFormModalComponent,\n width: 600,\n minWidth: 400\n });\n\n const modalInstance = dialogRef.content.instance as ProjectFormModalComponent;\n modalInstance.dialogRef = dialogRef;\n modalInstance.environmentId = this.environmentId;\n modalInstance.currentUser = this.currentUser;\n\n modalInstance.projectSaved.subscribe(async (project: MJProjectEntity) => {\n this.projectCreated.emit(project);\n await this.loadProjects();\n this.selectedProject = project;\n this.projectSelected.emit(project);\n });\n }\n\n onEditProject(): void {\n if (!this.selectedProject) return;\n\n const dialogRef = this.kendoDialogService.open({\n content: ProjectFormModalComponent,\n width: 600,\n minWidth: 400\n });\n\n const modalInstance = dialogRef.content.instance as ProjectFormModalComponent;\n modalInstance.dialogRef = dialogRef;\n modalInstance.project = this.selectedProject;\n modalInstance.environmentId = this.environmentId;\n modalInstance.currentUser = this.currentUser;\n\n modalInstance.projectSaved.subscribe(async (project: MJProjectEntity) => {\n this.projectUpdated.emit(project);\n await this.loadProjects();\n this.selectedProject = project;\n this.projectSelected.emit(project);\n });\n }\n\n async onDeleteProject(): Promise<void> {\n if (!this.selectedProject) return;\n\n const projectName = this.selectedProject.Name;\n const projectId = this.selectedProject.ID;\n const conversationCount = (this.selectedProject as ProjectWithStats).conversationCount || 0;\n\n let message = `Are you sure you want to delete the project \"${projectName}\"?`;\n if (conversationCount > 0) {\n message += `\\n\\nThis project has ${conversationCount} conversation(s). The conversations will not be deleted, but will be unassigned from this project.`;\n }\n\n const confirmed = await this.dialogService.confirm({\n title: 'Delete Project',\n message: message,\n okText: 'Delete',\n cancelText: 'Cancel',\n dangerous: true\n });\n\n if (!confirmed) return;\n\n try {\n const md = new Metadata();\n const project = await md.GetEntityObject<MJProjectEntity>('MJ: Projects', this.currentUser);\n await project.Load(projectId);\n\n const deleted = await project.Delete();\n if (deleted) {\n this.projectDeleted.emit(projectId);\n await this.loadProjects();\n this.selectedProject = null;\n this.projectSelected.emit(null);\n } else {\n throw new Error('Delete operation returned false');\n }\n } catch (error) {\n console.error('Error deleting project:', error);\n await this.dialogService.alert('Error', 'Failed to delete project. Please try again.');\n }\n }\n}"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tasks-full-view.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/task/tasks-full-view.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEzG,OAAO,EAAE,QAAQ,EAAW,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAsB,MAAM,+BAA+B,CAAC;;AAIzG;;;;GAIG;AACH,qBA2Ha,sBAAuB,YAAW,MAAM,EAAE,SAAS;IACrD,aAAa,EAAG,MAAM,CAAC;IACvB,WAAW,EAAG,QAAQ,CAAC;IACvB,UAAU,EAAE,MAAM,CAAS;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB;oBAAkC,MAAM;kBAAY,MAAM;OAAM;IAChF,YAAY,8BAAqC;IAEpD,QAAQ,EAAE,YAAY,EAAE,CAAM;IAC9B,aAAa,EAAE,YAAY,EAAE,CAAM;IACnC,QAAQ,EAAE,YAAY,EAAE,CAAM;IAC9B,kBAAkB,EAAE,YAAY,EAAE,CAAM;IACxC,gBAAgB,EAAE,sBAAsB,EAAE,CAAM;IAChD,WAAW,sBAA6B;IACxC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAQ;IACzC,mBAAmB,EAAE,OAAO,CAAS;IACrC,SAAS,EAAE,OAAO,CAAS;IAClC,OAAO,CAAC,kBAAkB,CAAkB;IAE5C,QAAQ;IAIR,WAAW,CAAC,OAAO,EAAE,aAAa;IAerB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IA4D1B,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;YAY7C,iBAAiB;YAgDjB,oBAAoB;YAkCpB,aAAa;IA0EpB,cAAc,IAAI,IAAI;IAYtB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAK3C,kBAAkB,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAKzE,cAAc,IAAI,MAAM;IAMxB,wBAAwB,IAAI,MAAM;yCAtS9B,sBAAsB;2CAAtB,sBAAsB;CA8SlC"}
1
+ {"version":3,"file":"tasks-full-view.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/task/tasks-full-view.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEzG,OAAO,EAAE,QAAQ,EAAW,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAsB,MAAM,+BAA+B,CAAC;;AAKzG;;;;GAIG;AACH,qBA2Ha,sBAAuB,YAAW,MAAM,EAAE,SAAS;IACrD,aAAa,EAAG,MAAM,CAAC;IACvB,WAAW,EAAG,QAAQ,CAAC;IACvB,UAAU,EAAE,MAAM,CAAS;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB;oBAAkC,MAAM;kBAAY,MAAM;OAAM;IAChF,YAAY,8BAAqC;IAEpD,QAAQ,EAAE,YAAY,EAAE,CAAM;IAC9B,aAAa,EAAE,YAAY,EAAE,CAAM;IACnC,QAAQ,EAAE,YAAY,EAAE,CAAM;IAC9B,kBAAkB,EAAE,YAAY,EAAE,CAAM;IACxC,gBAAgB,EAAE,sBAAsB,EAAE,CAAM;IAChD,WAAW,sBAA6B;IACxC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAQ;IACzC,mBAAmB,EAAE,OAAO,CAAS;IACrC,SAAS,EAAE,OAAO,CAAS;IAClC,OAAO,CAAC,kBAAkB,CAAkB;IAE5C,QAAQ;IAIR,WAAW,CAAC,OAAO,EAAE,aAAa;IAerB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IA4D1B,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;YAY7C,iBAAiB;YAgDjB,oBAAoB;YAkCpB,aAAa;IA0EpB,cAAc,IAAI,IAAI;IAYtB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAK3C,kBAAkB,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAKzE,cAAc,IAAI,MAAM;IAMxB,wBAAwB,IAAI,MAAM;yCAtS9B,sBAAsB;2CAAtB,sBAAsB;CA8SlC"}
@@ -2,6 +2,7 @@ import { Component, Input, Output, EventEmitter } from '@angular/core';
2
2
  import { RunView } from '@memberjunction/core';
3
3
  import { TaskComponent } from '@memberjunction/ng-tasks';
4
4
  import { AIEngineBase } from '@memberjunction/ai-engine-base';
5
+ import { UUIDsEqual } from '@memberjunction/global';
5
6
  import * as i0 from "@angular/core";
6
7
  function TasksFullViewComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
7
8
  const _r1 = i0.ɵɵgetCurrentView();
@@ -69,7 +70,7 @@ export class TasksFullViewComponent {
69
70
  }
70
71
  // Auto-drill into task if activeTaskId changes
71
72
  if (changes['activeTaskId'] && this.activeTaskId) {
72
- const task = this.allTasks.find(t => t.ID === this.activeTaskId);
73
+ const task = this.allTasks.find(t => UUIDsEqual(t.ID, this.activeTaskId));
73
74
  if (task) {
74
75
  this.onTaskClick(task);
75
76
  }
@@ -155,7 +156,7 @@ export class TasksFullViewComponent {
155
156
  if (hierarchyResult.Success) {
156
157
  const allHierarchy = hierarchyResult.Results || [];
157
158
  // For list view: Filter out the clicked task itself - only show its children/descendants
158
- this.subTasks = allHierarchy.filter(t => t.ID !== task.ID);
159
+ this.subTasks = allHierarchy.filter(t => !UUIDsEqual(t.ID, task.ID));
159
160
  // For Gantt view: Include the parent task so hierarchy works correctly
160
161
  this.subTasksWithParent = allHierarchy;
161
162
  console.log(`📋 Loaded ${this.subTasks.length} tasks in hierarchy for root ${rootId}`);
@@ -370,5 +371,5 @@ export class TasksFullViewComponent {
370
371
  }], taskSelected: [{
371
372
  type: Output
372
373
  }] }); })();
373
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TasksFullViewComponent, { className: "TasksFullViewComponent", filePath: "src/lib/components/task/tasks-full-view.component.ts", lineNumber: 136 }); })();
374
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TasksFullViewComponent, { className: "TasksFullViewComponent", filePath: "src/lib/components/task/tasks-full-view.component.ts", lineNumber: 137 }); })();
374
375
  //# sourceMappingURL=tasks-full-view.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tasks-full-view.component.js","sourceRoot":"","sources":["../../../../src/lib/components/task/tasks-full-view.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges } from '@angular/core';\n\nimport { UserInfo, RunView } from '@memberjunction/core';\nimport { MJTaskEntity, MJTaskDependencyEntity, MJAIAgentRunEntity } from '@memberjunction/core-entities';\nimport { TaskComponent } from '@memberjunction/ng-tasks';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\n\n/**\n * Full-page tasks view with task list and Gantt chart\n * Generic component that displays tasks based on provided filter\n * Supports drilling into individual tasks to see sub-tasks\n */\n@Component({\n selector: 'mj-tasks-full-view',\n standalone: true,\n imports: [TaskComponent],\n template: `\n <div class=\"tasks-full-view\">\n @if (!selectedTask) {\n <!-- Task List View -->\n <mj-task\n [tasks]=\"filteredTasks\"\n [title]=\"'Tasks'\"\n [description]=\"getDescription()\"\n [showHeader]=\"true\"\n [showViewToggle]=\"false\"\n [viewMode]=\"'simple'\"\n (taskClicked)=\"onTaskClick($event)\">\n </mj-task>\n } @else {\n <!-- Task Detail View with Sub-tasks -->\n <div class=\"task-detail-view\" [class.swoosh-in]=\"showDetailAnimation\">\n <!-- Breadcrumb -->\n <div class=\"breadcrumb-nav\">\n <button class=\"breadcrumb-back\" (click)=\"backToTaskList()\">\n <i class=\"fas fa-arrow-left\"></i>\n <span>Back to Tasks</span>\n </button>\n <div class=\"breadcrumb-divider\">/</div>\n <span class=\"breadcrumb-current\">{{ selectedTask.Name }}</span>\n </div>\n\n <!-- Task Details & Sub-tasks with Gantt Toggle -->\n <mj-task\n [tasks]=\"subTasks\"\n [ganttTasks]=\"subTasksWithParent\"\n [taskDependencies]=\"taskDependencies\"\n [agentRunMap]=\"agentRunMap\"\n [title]=\"selectedTask.Name\"\n [description]=\"getTaskDetailDescription()\"\n [showHeader]=\"true\"\n [showViewToggle]=\"true\"\n [viewMode]=\"'gantt'\"\n (taskClicked)=\"onSubTaskClick($event)\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\">\n </mj-task>\n </div>\n }\n </div>\n `,\n styles: [`\n .tasks-full-view {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: #F9FAFB;\n }\n\n .task-detail-view {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: white;\n }\n\n .swoosh-in {\n animation: swooshIn 0.3s ease-out;\n }\n\n @keyframes swooshIn {\n from {\n opacity: 0;\n transform: translateX(50px);\n }\n to {\n opacity: 1;\n transform: translateX(0);\n }\n }\n\n .breadcrumb-nav {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px 24px;\n background: white;\n border-bottom: 1px solid #E5E7EB;\n }\n\n .breadcrumb-back {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: transparent;\n border: 1px solid #D1D5DB;\n border-radius: 6px;\n color: #374151;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .breadcrumb-back:hover {\n background: #F3F4F6;\n border-color: #9CA3AF;\n }\n\n .breadcrumb-back i {\n font-size: 12px;\n }\n\n .breadcrumb-divider {\n color: #9CA3AF;\n font-size: 14px;\n }\n\n .breadcrumb-current {\n font-size: 14px;\n font-weight: 600;\n color: #111827;\n }\n `]\n})\nexport class TasksFullViewComponent implements OnInit, OnChanges {\n @Input() environmentId!: string;\n @Input() currentUser!: UserInfo;\n @Input() baseFilter: string = '1=1'; // SQL filter for tasks (default: show all)\n @Input() activeTaskId?: string; // Task ID to auto-select and drill into\n @Output() openEntityRecord = new EventEmitter<{ entityName: string; recordId: string }>();\n @Output() taskSelected = new EventEmitter<string | null>(); // Emits task ID when drill-down occurs, null when returning to list\n\n public allTasks: MJTaskEntity[] = [];\n public filteredTasks: MJTaskEntity[] = [];\n public subTasks: MJTaskEntity[] = [];\n public subTasksWithParent: MJTaskEntity[] = []; // Includes parent for Gantt hierarchy\n public taskDependencies: MJTaskDependencyEntity[] = []; // Dependencies for Gantt links\n public agentRunMap = new Map<string, string>(); // Maps TaskID -> AgentRunID\n public selectedTask: MJTaskEntity | null = null;\n public showDetailAnimation: boolean = false;\n public isLoading: boolean = false;\n private aiEngineConfigured: boolean = false;\n\n ngOnInit() {\n this.loadTasks();\n }\n\n ngOnChanges(changes: SimpleChanges) {\n // Reload tasks if baseFilter changes\n if (changes['baseFilter'] && !changes['baseFilter'].firstChange) {\n this.loadTasks();\n }\n\n // Auto-drill into task if activeTaskId changes\n if (changes['activeTaskId'] && this.activeTaskId) {\n const task = this.allTasks.find(t => t.ID === this.activeTaskId);\n if (task) {\n this.onTaskClick(task);\n }\n }\n }\n\n public async loadTasks(): Promise<void> {\n this.isLoading = true;\n\n try {\n // Configure AIEngineBase on first load (false = don't force refresh)\n if (!this.aiEngineConfigured) {\n await AIEngineBase.Instance.Config(false);\n this.aiEngineConfigured = true;\n }\n\n const rv = new RunView();\n\n console.log('📝 Tasks filter SQL:', this.baseFilter);\n\n // Load all tasks with the provided filter\n const tasksResult = await rv.RunView<MJTaskEntity>(\n {\n EntityName: 'MJ: Tasks',\n ExtraFilter: this.baseFilter,\n OrderBy: '__mj_CreatedAt DESC',\n MaxRows: 1000,\n ResultType: 'entity_object'\n },\n this.currentUser\n );\n\n console.log('📊 Tasks query result:', {\n success: tasksResult.Success,\n resultCount: tasksResult.Results?.length || 0,\n errorMessage: tasksResult.ErrorMessage\n });\n\n if (tasksResult.Success) {\n this.allTasks = tasksResult.Results || [];\n this.filteredTasks = this.allTasks;\n console.log(`📋 Loaded ${this.allTasks.length} tasks`);\n if (this.allTasks.length === 0) {\n console.log('💡 No tasks found with current filter');\n } else {\n console.log('✅ Sample task:', {\n id: this.allTasks[0].ID,\n name: this.allTasks[0].Name,\n status: this.allTasks[0].Status,\n conversationDetailID: this.allTasks[0].ConversationDetailID\n });\n }\n } else {\n console.error('❌ Failed to load tasks:', tasksResult.ErrorMessage);\n this.allTasks = [];\n this.filteredTasks = [];\n }\n } catch (error) {\n console.error('Failed to load tasks:', error);\n this.allTasks = [];\n this.filteredTasks = [];\n } finally {\n this.isLoading = false;\n }\n }\n\n public async onTaskClick(task: MJTaskEntity): Promise<void> {\n console.log('Task clicked:', task);\n this.selectedTask = task;\n this.showDetailAnimation = true;\n\n // Emit task selection event for URL tracking\n this.taskSelected.emit(task.ID);\n\n // Load all tasks in the hierarchy using RootParentID\n await this.loadTaskHierarchy(task);\n }\n\n private async loadTaskHierarchy(task: MJTaskEntity): Promise<void> {\n try {\n const rv = new RunView();\n\n // Use RootParentID to load all tasks in this hierarchy\n // If task has no RootParentID, it's the root itself, so use its ID\n const rootId = task.RootParentID || task.ID;\n\n // Load all tasks where RootParentID matches, or tasks that are the root itself\n const hierarchyResult = await rv.RunView<MJTaskEntity>(\n {\n EntityName: 'MJ: Tasks',\n ExtraFilter: `RootParentID='${rootId}' OR ID='${rootId}'`,\n OrderBy: '__mj_CreatedAt ASC',\n MaxRows: 1000,\n ResultType: 'entity_object'\n },\n this.currentUser\n );\n\n if (hierarchyResult.Success) {\n const allHierarchy = hierarchyResult.Results || [];\n\n // For list view: Filter out the clicked task itself - only show its children/descendants\n this.subTasks = allHierarchy.filter(t => t.ID !== task.ID);\n\n // For Gantt view: Include the parent task so hierarchy works correctly\n this.subTasksWithParent = allHierarchy;\n\n console.log(`📋 Loaded ${this.subTasks.length} tasks in hierarchy for root ${rootId}`);\n\n // Load task dependencies for this hierarchy\n await this.loadTaskDependencies(rootId);\n\n // Load agent runs for this hierarchy\n await this.loadAgentRuns(allHierarchy);\n } else {\n console.error('❌ Failed to load task hierarchy:', hierarchyResult.ErrorMessage);\n this.subTasks = [];\n this.subTasksWithParent = [];\n this.taskDependencies = [];\n }\n } catch (error) {\n console.error('Failed to load task hierarchy:', error);\n this.subTasks = [];\n }\n }\n\n private async loadTaskDependencies(rootId: string): Promise<void> {\n try {\n const rv = new RunView();\n\n // Load task dependencies where either TaskID or DependsOnTaskID is in this hierarchy\n // Use subquery to find all tasks with this RootParentID\n // Note: Using __mj as the default schema - this is the standard MJ schema\n const schema = '__mj';\n const depsResult = await rv.RunView<MJTaskDependencyEntity>(\n {\n EntityName: 'MJ: Task Dependencies',\n ExtraFilter: `\n TaskID IN (SELECT ID FROM [${schema}].[vwTasks] WHERE RootParentID='${rootId}' OR ID='${rootId}')\n OR\n DependsOnTaskID IN (SELECT ID FROM [${schema}].[vwTasks] WHERE RootParentID='${rootId}' OR ID='${rootId}')\n `,\n ResultType: 'entity_object'\n },\n this.currentUser\n );\n\n if (depsResult.Success) {\n this.taskDependencies = depsResult.Results || [];\n console.log(`🔗 Loaded ${this.taskDependencies.length} task dependencies`);\n } else {\n console.error('❌ Failed to load task dependencies:', depsResult.ErrorMessage);\n this.taskDependencies = [];\n }\n } catch (error) {\n console.error('Failed to load task dependencies:', error);\n this.taskDependencies = [];\n }\n }\n\n private async loadAgentRuns(tasks: MJTaskEntity[]): Promise<void> {\n try {\n // Clear existing map\n this.agentRunMap.clear();\n\n // Get all unique ConversationDetailIDs from tasks (filter out nulls)\n const conversationDetailIds = tasks\n .filter(t => t.ConversationDetailID != null)\n .map(t => t.ConversationDetailID!);\n\n if (conversationDetailIds.length === 0) {\n console.log('💡 No tasks with ConversationDetailID');\n return;\n }\n\n const rv = new RunView();\n const schema = '__mj';\n\n // Build filter to find agent runs for these conversation details\n // Use a subquery to avoid passing large ID lists\n const taskIds = tasks.map(t => `'${t.ID}'`).join(',');\n\n const agentRunsResult = await rv.RunView<MJAIAgentRunEntity>(\n {\n EntityName: 'MJ: AI Agent Runs',\n ExtraFilter: `\n ConversationDetailID IN (\n SELECT DISTINCT ConversationDetailID\n FROM [${schema}].[vwTasks]\n WHERE ID IN (${taskIds})\n AND ConversationDetailID IS NOT NULL\n )\n `,\n ResultType: 'entity_object'\n },\n this.currentUser\n );\n\n if (agentRunsResult.Success) {\n const agentRuns = agentRunsResult.Results || [];\n console.log(`🤖 Loaded ${agentRuns.length} agent runs`, agentRuns);\n\n // Build map: ConversationDetailID -> AgentRunID\n const convoToRunMap = new Map<string, string>();\n agentRuns.forEach(run => {\n if (run.ConversationDetailID) {\n convoToRunMap.set(run.ConversationDetailID, run.ID);\n console.log(`📝 Mapping ConvoDetailID ${run.ConversationDetailID} -> RunID ${run.ID}`);\n }\n });\n\n // Map TaskID -> AgentRunID using ConversationDetailID as the link\n tasks.forEach(task => {\n console.log(`🔍 Task ${task.Name} - ConvoDetailID: ${task.ConversationDetailID}, AgentID: ${task.AgentID}`);\n if (task.ConversationDetailID) {\n const agentRunId = convoToRunMap.get(task.ConversationDetailID);\n if (agentRunId) {\n this.agentRunMap.set(task.ID, agentRunId);\n console.log(`✅ Mapped Task ${task.ID} -> AgentRun ${agentRunId}`);\n } else {\n console.log(`⚠️ No agent run found for ConvoDetailID ${task.ConversationDetailID}`);\n }\n }\n });\n\n console.log(`🔗 Mapped ${this.agentRunMap.size} tasks to agent runs`, Array.from(this.agentRunMap.entries()));\n } else {\n console.error('❌ Failed to load agent runs:', agentRunsResult.ErrorMessage);\n }\n } catch (error) {\n console.error('Failed to load agent runs:', error);\n }\n }\n\n public backToTaskList(): void {\n this.selectedTask = null;\n this.subTasks = [];\n this.subTasksWithParent = [];\n this.taskDependencies = [];\n this.agentRunMap.clear();\n this.showDetailAnimation = false;\n\n // Emit null to indicate returning to task list (for URL tracking)\n this.taskSelected.emit(null);\n }\n\n public onSubTaskClick(subTask: MJTaskEntity): void {\n console.log('Sub-task clicked:', subTask);\n // Could drill down further if needed\n }\n\n public onOpenEntityRecord(event: { entityName: string; recordId: string }): void {\n // Bubble up the event to parent component\n this.openEntityRecord.emit(event);\n }\n\n public getDescription(): string {\n const activeCount = this.allTasks.filter(t => t.Status === 'Pending' || t.Status === 'In Progress').length;\n const completedCount = this.allTasks.filter(t => t.Status === 'Complete').length;\n return `${activeCount} active, ${completedCount} completed, ${this.allTasks.length} total`;\n }\n\n public getTaskDetailDescription(): string {\n if (this.subTasks.length === 0) {\n return 'No sub-tasks';\n }\n const activeCount = this.subTasks.filter(t => t.Status === 'Pending' || t.Status === 'In Progress').length;\n const completedCount = this.subTasks.filter(t => t.Status === 'Complete').length;\n return `${activeCount} active, ${completedCount} completed, ${this.subTasks.length} sub-tasks`;\n }\n}\n"]}
1
+ {"version":3,"file":"tasks-full-view.component.js","sourceRoot":"","sources":["../../../../src/lib/components/task/tasks-full-view.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges } from '@angular/core';\n\nimport { UserInfo, RunView } from '@memberjunction/core';\nimport { MJTaskEntity, MJTaskDependencyEntity, MJAIAgentRunEntity } from '@memberjunction/core-entities';\nimport { TaskComponent } from '@memberjunction/ng-tasks';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n/**\n * Full-page tasks view with task list and Gantt chart\n * Generic component that displays tasks based on provided filter\n * Supports drilling into individual tasks to see sub-tasks\n */\n@Component({\n selector: 'mj-tasks-full-view',\n standalone: true,\n imports: [TaskComponent],\n template: `\n <div class=\"tasks-full-view\">\n @if (!selectedTask) {\n <!-- Task List View -->\n <mj-task\n [tasks]=\"filteredTasks\"\n [title]=\"'Tasks'\"\n [description]=\"getDescription()\"\n [showHeader]=\"true\"\n [showViewToggle]=\"false\"\n [viewMode]=\"'simple'\"\n (taskClicked)=\"onTaskClick($event)\">\n </mj-task>\n } @else {\n <!-- Task Detail View with Sub-tasks -->\n <div class=\"task-detail-view\" [class.swoosh-in]=\"showDetailAnimation\">\n <!-- Breadcrumb -->\n <div class=\"breadcrumb-nav\">\n <button class=\"breadcrumb-back\" (click)=\"backToTaskList()\">\n <i class=\"fas fa-arrow-left\"></i>\n <span>Back to Tasks</span>\n </button>\n <div class=\"breadcrumb-divider\">/</div>\n <span class=\"breadcrumb-current\">{{ selectedTask.Name }}</span>\n </div>\n\n <!-- Task Details & Sub-tasks with Gantt Toggle -->\n <mj-task\n [tasks]=\"subTasks\"\n [ganttTasks]=\"subTasksWithParent\"\n [taskDependencies]=\"taskDependencies\"\n [agentRunMap]=\"agentRunMap\"\n [title]=\"selectedTask.Name\"\n [description]=\"getTaskDetailDescription()\"\n [showHeader]=\"true\"\n [showViewToggle]=\"true\"\n [viewMode]=\"'gantt'\"\n (taskClicked)=\"onSubTaskClick($event)\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\">\n </mj-task>\n </div>\n }\n </div>\n `,\n styles: [`\n .tasks-full-view {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: #F9FAFB;\n }\n\n .task-detail-view {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: white;\n }\n\n .swoosh-in {\n animation: swooshIn 0.3s ease-out;\n }\n\n @keyframes swooshIn {\n from {\n opacity: 0;\n transform: translateX(50px);\n }\n to {\n opacity: 1;\n transform: translateX(0);\n }\n }\n\n .breadcrumb-nav {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px 24px;\n background: white;\n border-bottom: 1px solid #E5E7EB;\n }\n\n .breadcrumb-back {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: transparent;\n border: 1px solid #D1D5DB;\n border-radius: 6px;\n color: #374151;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .breadcrumb-back:hover {\n background: #F3F4F6;\n border-color: #9CA3AF;\n }\n\n .breadcrumb-back i {\n font-size: 12px;\n }\n\n .breadcrumb-divider {\n color: #9CA3AF;\n font-size: 14px;\n }\n\n .breadcrumb-current {\n font-size: 14px;\n font-weight: 600;\n color: #111827;\n }\n `]\n})\nexport class TasksFullViewComponent implements OnInit, OnChanges {\n @Input() environmentId!: string;\n @Input() currentUser!: UserInfo;\n @Input() baseFilter: string = '1=1'; // SQL filter for tasks (default: show all)\n @Input() activeTaskId?: string; // Task ID to auto-select and drill into\n @Output() openEntityRecord = new EventEmitter<{ entityName: string; recordId: string }>();\n @Output() taskSelected = new EventEmitter<string | null>(); // Emits task ID when drill-down occurs, null when returning to list\n\n public allTasks: MJTaskEntity[] = [];\n public filteredTasks: MJTaskEntity[] = [];\n public subTasks: MJTaskEntity[] = [];\n public subTasksWithParent: MJTaskEntity[] = []; // Includes parent for Gantt hierarchy\n public taskDependencies: MJTaskDependencyEntity[] = []; // Dependencies for Gantt links\n public agentRunMap = new Map<string, string>(); // Maps TaskID -> AgentRunID\n public selectedTask: MJTaskEntity | null = null;\n public showDetailAnimation: boolean = false;\n public isLoading: boolean = false;\n private aiEngineConfigured: boolean = false;\n\n ngOnInit() {\n this.loadTasks();\n }\n\n ngOnChanges(changes: SimpleChanges) {\n // Reload tasks if baseFilter changes\n if (changes['baseFilter'] && !changes['baseFilter'].firstChange) {\n this.loadTasks();\n }\n\n // Auto-drill into task if activeTaskId changes\n if (changes['activeTaskId'] && this.activeTaskId) {\n const task = this.allTasks.find(t => UUIDsEqual(t.ID, this.activeTaskId));\n if (task) {\n this.onTaskClick(task);\n }\n }\n }\n\n public async loadTasks(): Promise<void> {\n this.isLoading = true;\n\n try {\n // Configure AIEngineBase on first load (false = don't force refresh)\n if (!this.aiEngineConfigured) {\n await AIEngineBase.Instance.Config(false);\n this.aiEngineConfigured = true;\n }\n\n const rv = new RunView();\n\n console.log('📝 Tasks filter SQL:', this.baseFilter);\n\n // Load all tasks with the provided filter\n const tasksResult = await rv.RunView<MJTaskEntity>(\n {\n EntityName: 'MJ: Tasks',\n ExtraFilter: this.baseFilter,\n OrderBy: '__mj_CreatedAt DESC',\n MaxRows: 1000,\n ResultType: 'entity_object'\n },\n this.currentUser\n );\n\n console.log('📊 Tasks query result:', {\n success: tasksResult.Success,\n resultCount: tasksResult.Results?.length || 0,\n errorMessage: tasksResult.ErrorMessage\n });\n\n if (tasksResult.Success) {\n this.allTasks = tasksResult.Results || [];\n this.filteredTasks = this.allTasks;\n console.log(`📋 Loaded ${this.allTasks.length} tasks`);\n if (this.allTasks.length === 0) {\n console.log('💡 No tasks found with current filter');\n } else {\n console.log('✅ Sample task:', {\n id: this.allTasks[0].ID,\n name: this.allTasks[0].Name,\n status: this.allTasks[0].Status,\n conversationDetailID: this.allTasks[0].ConversationDetailID\n });\n }\n } else {\n console.error('❌ Failed to load tasks:', tasksResult.ErrorMessage);\n this.allTasks = [];\n this.filteredTasks = [];\n }\n } catch (error) {\n console.error('Failed to load tasks:', error);\n this.allTasks = [];\n this.filteredTasks = [];\n } finally {\n this.isLoading = false;\n }\n }\n\n public async onTaskClick(task: MJTaskEntity): Promise<void> {\n console.log('Task clicked:', task);\n this.selectedTask = task;\n this.showDetailAnimation = true;\n\n // Emit task selection event for URL tracking\n this.taskSelected.emit(task.ID);\n\n // Load all tasks in the hierarchy using RootParentID\n await this.loadTaskHierarchy(task);\n }\n\n private async loadTaskHierarchy(task: MJTaskEntity): Promise<void> {\n try {\n const rv = new RunView();\n\n // Use RootParentID to load all tasks in this hierarchy\n // If task has no RootParentID, it's the root itself, so use its ID\n const rootId = task.RootParentID || task.ID;\n\n // Load all tasks where RootParentID matches, or tasks that are the root itself\n const hierarchyResult = await rv.RunView<MJTaskEntity>(\n {\n EntityName: 'MJ: Tasks',\n ExtraFilter: `RootParentID='${rootId}' OR ID='${rootId}'`,\n OrderBy: '__mj_CreatedAt ASC',\n MaxRows: 1000,\n ResultType: 'entity_object'\n },\n this.currentUser\n );\n\n if (hierarchyResult.Success) {\n const allHierarchy = hierarchyResult.Results || [];\n\n // For list view: Filter out the clicked task itself - only show its children/descendants\n this.subTasks = allHierarchy.filter(t => !UUIDsEqual(t.ID, task.ID));\n\n // For Gantt view: Include the parent task so hierarchy works correctly\n this.subTasksWithParent = allHierarchy;\n\n console.log(`📋 Loaded ${this.subTasks.length} tasks in hierarchy for root ${rootId}`);\n\n // Load task dependencies for this hierarchy\n await this.loadTaskDependencies(rootId);\n\n // Load agent runs for this hierarchy\n await this.loadAgentRuns(allHierarchy);\n } else {\n console.error('❌ Failed to load task hierarchy:', hierarchyResult.ErrorMessage);\n this.subTasks = [];\n this.subTasksWithParent = [];\n this.taskDependencies = [];\n }\n } catch (error) {\n console.error('Failed to load task hierarchy:', error);\n this.subTasks = [];\n }\n }\n\n private async loadTaskDependencies(rootId: string): Promise<void> {\n try {\n const rv = new RunView();\n\n // Load task dependencies where either TaskID or DependsOnTaskID is in this hierarchy\n // Use subquery to find all tasks with this RootParentID\n // Note: Using __mj as the default schema - this is the standard MJ schema\n const schema = '__mj';\n const depsResult = await rv.RunView<MJTaskDependencyEntity>(\n {\n EntityName: 'MJ: Task Dependencies',\n ExtraFilter: `\n TaskID IN (SELECT ID FROM [${schema}].[vwTasks] WHERE RootParentID='${rootId}' OR ID='${rootId}')\n OR\n DependsOnTaskID IN (SELECT ID FROM [${schema}].[vwTasks] WHERE RootParentID='${rootId}' OR ID='${rootId}')\n `,\n ResultType: 'entity_object'\n },\n this.currentUser\n );\n\n if (depsResult.Success) {\n this.taskDependencies = depsResult.Results || [];\n console.log(`🔗 Loaded ${this.taskDependencies.length} task dependencies`);\n } else {\n console.error('❌ Failed to load task dependencies:', depsResult.ErrorMessage);\n this.taskDependencies = [];\n }\n } catch (error) {\n console.error('Failed to load task dependencies:', error);\n this.taskDependencies = [];\n }\n }\n\n private async loadAgentRuns(tasks: MJTaskEntity[]): Promise<void> {\n try {\n // Clear existing map\n this.agentRunMap.clear();\n\n // Get all unique ConversationDetailIDs from tasks (filter out nulls)\n const conversationDetailIds = tasks\n .filter(t => t.ConversationDetailID != null)\n .map(t => t.ConversationDetailID!);\n\n if (conversationDetailIds.length === 0) {\n console.log('💡 No tasks with ConversationDetailID');\n return;\n }\n\n const rv = new RunView();\n const schema = '__mj';\n\n // Build filter to find agent runs for these conversation details\n // Use a subquery to avoid passing large ID lists\n const taskIds = tasks.map(t => `'${t.ID}'`).join(',');\n\n const agentRunsResult = await rv.RunView<MJAIAgentRunEntity>(\n {\n EntityName: 'MJ: AI Agent Runs',\n ExtraFilter: `\n ConversationDetailID IN (\n SELECT DISTINCT ConversationDetailID\n FROM [${schema}].[vwTasks]\n WHERE ID IN (${taskIds})\n AND ConversationDetailID IS NOT NULL\n )\n `,\n ResultType: 'entity_object'\n },\n this.currentUser\n );\n\n if (agentRunsResult.Success) {\n const agentRuns = agentRunsResult.Results || [];\n console.log(`🤖 Loaded ${agentRuns.length} agent runs`, agentRuns);\n\n // Build map: ConversationDetailID -> AgentRunID\n const convoToRunMap = new Map<string, string>();\n agentRuns.forEach(run => {\n if (run.ConversationDetailID) {\n convoToRunMap.set(run.ConversationDetailID, run.ID);\n console.log(`📝 Mapping ConvoDetailID ${run.ConversationDetailID} -> RunID ${run.ID}`);\n }\n });\n\n // Map TaskID -> AgentRunID using ConversationDetailID as the link\n tasks.forEach(task => {\n console.log(`🔍 Task ${task.Name} - ConvoDetailID: ${task.ConversationDetailID}, AgentID: ${task.AgentID}`);\n if (task.ConversationDetailID) {\n const agentRunId = convoToRunMap.get(task.ConversationDetailID);\n if (agentRunId) {\n this.agentRunMap.set(task.ID, agentRunId);\n console.log(`✅ Mapped Task ${task.ID} -> AgentRun ${agentRunId}`);\n } else {\n console.log(`⚠️ No agent run found for ConvoDetailID ${task.ConversationDetailID}`);\n }\n }\n });\n\n console.log(`🔗 Mapped ${this.agentRunMap.size} tasks to agent runs`, Array.from(this.agentRunMap.entries()));\n } else {\n console.error('❌ Failed to load agent runs:', agentRunsResult.ErrorMessage);\n }\n } catch (error) {\n console.error('Failed to load agent runs:', error);\n }\n }\n\n public backToTaskList(): void {\n this.selectedTask = null;\n this.subTasks = [];\n this.subTasksWithParent = [];\n this.taskDependencies = [];\n this.agentRunMap.clear();\n this.showDetailAnimation = false;\n\n // Emit null to indicate returning to task list (for URL tracking)\n this.taskSelected.emit(null);\n }\n\n public onSubTaskClick(subTask: MJTaskEntity): void {\n console.log('Sub-task clicked:', subTask);\n // Could drill down further if needed\n }\n\n public onOpenEntityRecord(event: { entityName: string; recordId: string }): void {\n // Bubble up the event to parent component\n this.openEntityRecord.emit(event);\n }\n\n public getDescription(): string {\n const activeCount = this.allTasks.filter(t => t.Status === 'Pending' || t.Status === 'In Progress').length;\n const completedCount = this.allTasks.filter(t => t.Status === 'Complete').length;\n return `${activeCount} active, ${completedCount} completed, ${this.allTasks.length} total`;\n }\n\n public getTaskDetailDescription(): string {\n if (this.subTasks.length === 0) {\n return 'No sub-tasks';\n }\n const activeCount = this.subTasks.filter(t => t.Status === 'Pending' || t.Status === 'In Progress').length;\n const completedCount = this.subTasks.filter(t => t.Status === 'Complete').length;\n return `${activeCount} active, ${completedCount} completed, ${this.subTasks.length} sub-tasks`;\n }\n}\n"]}
@@ -18,6 +18,10 @@ export declare class AgentStateService implements OnDestroy {
18
18
  private pollSubscription?;
19
19
  private currentUser?;
20
20
  private pollInterval;
21
+ private pollCycleCount;
22
+ /** Minimum poll cycles before allowing auto-stop. Prevents premature shutdown
23
+ * when fire-and-forget ACK returns before the server creates the agent run record. */
24
+ private readonly minimumPollCycles;
21
25
  readonly activeAgents$: Observable<AgentWithStatus[]>;
22
26
  constructor();
23
27
  ngOnDestroy(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"agent-state.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/agent-state.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,SAAS,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAmB,UAAU,EAA0B,MAAM,MAAM,CAAC;AAE3E,OAAO,EAAwB,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;;AAEnE,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO,CAAC;AAE7F,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,kBAAkB,CAAC;IACxB,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;GAGG;AACH,qBAGa,iBAAkB,YAAW,SAAS;IACjD,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,gBAAgB,CAAC,CAAe;IACxC,OAAO,CAAC,WAAW,CAAC,CAAW;IAC/B,OAAO,CAAC,YAAY,CAAiB;IAGrC,SAAgB,aAAa,gCAAsC;;IAInE,WAAW,IAAI,IAAI;IAInB;;;;OAIG;IACH,YAAY,CAAC,WAAW,EAAE,QAAQ,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI;IAalE;;OAEG;IACH,WAAW,IAAI,IAAI;IAOnB;;;OAGG;IACH,eAAe,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC,eAAe,EAAE,CAAC;IAUvE;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAIzD;;;OAGG;IACG,OAAO,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD;;OAEG;YACW,gBAAgB;IA8C9B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAW/B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAqC5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAiBzB;;;OAGG;IACG,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA0BvD;;;OAGG;IACH,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;yCAtOhC,iBAAiB;6CAAjB,iBAAiB;CA8O7B"}
1
+ {"version":3,"file":"agent-state.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/agent-state.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,SAAS,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAmB,UAAU,EAA0B,MAAM,MAAM,CAAC;AAE3E,OAAO,EAAwB,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;;AAEnE,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO,CAAC;AAE7F,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,kBAAkB,CAAC;IACxB,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;GAGG;AACH,qBAGa,iBAAkB,YAAW,SAAS;IACjD,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,gBAAgB,CAAC,CAAe;IACxC,OAAO,CAAC,WAAW,CAAC,CAAW;IAC/B,OAAO,CAAC,YAAY,CAAiB;IACrC,OAAO,CAAC,cAAc,CAAK;IAC3B;2FACuF;IACvF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAK;IAGvC,SAAgB,aAAa,gCAAsC;;IAInE,WAAW,IAAI,IAAI;IAInB;;;;OAIG;IACH,YAAY,CAAC,WAAW,EAAE,QAAQ,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI;IAclE;;OAEG;IACH,WAAW,IAAI,IAAI;IAOnB;;;OAGG;IACH,eAAe,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC,eAAe,EAAE,CAAC;IAUvE;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAIzD;;;OAGG;IACG,OAAO,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD;;OAEG;YACW,gBAAgB;IAiD9B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAW/B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAqC5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAiBzB;;;OAGG;IACG,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA0BvD;;;OAGG;IACH,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;yCA9OhC,iBAAiB;6CAAjB,iBAAiB;CAsP7B"}
@@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
2
2
  import { BehaviorSubject, interval } from 'rxjs';
3
3
  import { map, shareReplay, switchMap } from 'rxjs/operators';
4
4
  import { LogStatusEx, RunView } from '@memberjunction/core';
5
+ import { UUIDsEqual } from '@memberjunction/global';
5
6
  import * as i0 from "@angular/core";
6
7
  /**
7
8
  * Manages agent state and provides real-time updates for active agents
@@ -12,6 +13,10 @@ export class AgentStateService {
12
13
  pollSubscription;
13
14
  currentUser;
14
15
  pollInterval = 30000; // Poll every 30 seconds (reduced from 3s to minimize DB load)
16
+ pollCycleCount = 0;
17
+ /** Minimum poll cycles before allowing auto-stop. Prevents premature shutdown
18
+ * when fire-and-forget ACK returns before the server creates the agent run record. */
19
+ minimumPollCycles = 3;
15
20
  // Public observable streams
16
21
  activeAgents$ = this._activeAgents$.asObservable();
17
22
  constructor() { }
@@ -26,6 +31,7 @@ export class AgentStateService {
26
31
  startPolling(currentUser, conversationId) {
27
32
  this.currentUser = currentUser;
28
33
  this.stopPolling();
34
+ this.pollCycleCount = 0;
29
35
  // Initial load
30
36
  this.loadActiveAgents(conversationId);
31
37
  // Start polling
@@ -48,7 +54,7 @@ export class AgentStateService {
48
54
  */
49
55
  getActiveAgents(conversationId) {
50
56
  if (conversationId) {
51
- return this.activeAgents$.pipe(map(agents => agents.filter(a => a.run.ConversationID === conversationId)), shareReplay(1));
57
+ return this.activeAgents$.pipe(map(agents => agents.filter(a => UUIDsEqual(a.run.ConversationID, conversationId))), shareReplay(1));
52
58
  }
53
59
  return this.activeAgents$;
54
60
  }
@@ -57,7 +63,7 @@ export class AgentStateService {
57
63
  * @param agentRunId The agent run ID
58
64
  */
59
65
  getAgent(agentRunId) {
60
- return this._activeAgents$.value.find(a => a.run.ID === agentRunId);
66
+ return this._activeAgents$.value.find(a => UUIDsEqual(a.run.ID, agentRunId));
61
67
  }
62
68
  /**
63
69
  * Manually refreshes active agents
@@ -73,8 +79,9 @@ export class AgentStateService {
73
79
  if (!this.currentUser) {
74
80
  return;
75
81
  }
82
+ this.pollCycleCount++;
76
83
  const timestamp = new Date().toISOString();
77
- LogStatusEx({ message: `[${timestamp}] 🤖 AgentStateService.loadActiveAgents - Polling for active agents (conversation: ${conversationId || 'ALL'})`, verboseOnly: true });
84
+ LogStatusEx({ message: `[${timestamp}] 🤖 AgentStateService.loadActiveAgents - Polling for active agents (conversation: ${conversationId || 'ALL'}, cycle: ${this.pollCycleCount})`, verboseOnly: true });
78
85
  try {
79
86
  const rv = new RunView();
80
87
  // Valid statuses: Running, Completed, Paused, Failed, Cancelled
@@ -95,9 +102,11 @@ export class AgentStateService {
95
102
  LogStatusEx({ message: `[${timestamp}] 🤖 AgentStateService - Found ${runs.length} active agent(s)`, verboseOnly: true });
96
103
  const agentsWithStatus = runs.map(run => this.mapRunToAgentWithStatus(run));
97
104
  this._activeAgents$.next(agentsWithStatus);
98
- // Stop polling if no active agents (optimization to reduce DB load)
99
- if (runs.length === 0 && this.pollSubscription) {
100
- LogStatusEx({ message: `[${timestamp}] 🤖 AgentStateService - No active agents, stopping polling`, verboseOnly: true });
105
+ // Stop polling if no active agents AND minimum cycles met (optimization to reduce DB load).
106
+ // The minimum cycle guard prevents premature shutdown when fire-and-forget returns
107
+ // before the server has created the agent run record.
108
+ if (runs.length === 0 && this.pollSubscription && this.pollCycleCount >= this.minimumPollCycles) {
109
+ LogStatusEx({ message: `[${timestamp}] 🤖 AgentStateService - No active agents after ${this.pollCycleCount} cycles, stopping polling`, verboseOnly: true });
101
110
  this.stopPolling();
102
111
  }
103
112
  }
@@ -1 +1 @@
1
- {"version":3,"file":"agent-state.service.js","sourceRoot":"","sources":["../../../src/lib/services/agent-state.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, OnDestroy } from '@angular/core';\nimport { BehaviorSubject, Observable, interval, Subscription } from 'rxjs';\nimport { map, shareReplay, switchMap } from 'rxjs/operators';\nimport { LogStatusEx, RunView, UserInfo } from '@memberjunction/core';\nimport { MJAIAgentRunEntity } from '@memberjunction/core-entities';\n\nexport type AgentStatus = 'acknowledging' | 'working' | 'completing' | 'completed' | 'error';\n\nexport interface AgentWithStatus {\n run: MJAIAgentRunEntity;\n status: AgentStatus;\n confidence: number | null;\n}\n\n/**\n * Manages agent state and provides real-time updates for active agents\n * Polls for agent status changes and provides reactive streams\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class AgentStateService implements OnDestroy {\n private _activeAgents$ = new BehaviorSubject<AgentWithStatus[]>([]);\n private pollSubscription?: Subscription;\n private currentUser?: UserInfo;\n private pollInterval: number = 30000; // Poll every 30 seconds (reduced from 3s to minimize DB load)\n\n // Public observable streams\n public readonly activeAgents$ = this._activeAgents$.asObservable();\n\n constructor() {}\n\n ngOnDestroy(): void {\n this.stopPolling();\n }\n\n /**\n * Starts polling for active agents\n * @param currentUser The current user context\n * @param conversationId Optional conversation ID to filter by\n */\n startPolling(currentUser: UserInfo, conversationId?: string): void {\n this.currentUser = currentUser;\n this.stopPolling();\n\n // Initial load\n this.loadActiveAgents(conversationId);\n\n // Start polling\n this.pollSubscription = interval(this.pollInterval)\n .pipe(switchMap(() => this.loadActiveAgents(conversationId)))\n .subscribe();\n }\n\n /**\n * Stops polling for active agents\n */\n stopPolling(): void {\n if (this.pollSubscription) {\n this.pollSubscription.unsubscribe();\n this.pollSubscription = undefined;\n }\n }\n\n /**\n * Gets active agents as an observable\n * @param conversationId Optional conversation ID to filter by\n */\n getActiveAgents(conversationId?: string): Observable<AgentWithStatus[]> {\n if (conversationId) {\n return this.activeAgents$.pipe(\n map(agents => agents.filter(a => a.run.ConversationID === conversationId)),\n shareReplay(1)\n );\n }\n return this.activeAgents$;\n }\n\n /**\n * Gets a specific agent by ID\n * @param agentRunId The agent run ID\n */\n getAgent(agentRunId: string): AgentWithStatus | undefined {\n return this._activeAgents$.value.find(a => a.run.ID === agentRunId);\n }\n\n /**\n * Manually refreshes active agents\n * @param conversationId Optional conversation ID to filter by\n */\n async refresh(conversationId?: string): Promise<void> {\n await this.loadActiveAgents(conversationId);\n }\n\n /**\n * Loads active agents from the database\n */\n private async loadActiveAgents(conversationId?: string): Promise<void> {\n if (!this.currentUser) {\n return;\n }\n\n const timestamp = new Date().toISOString();\n LogStatusEx({message: `[${timestamp}] 🤖 AgentStateService.loadActiveAgents - Polling for active agents (conversation: ${conversationId || 'ALL'})`, verboseOnly: true});\n\n try {\n const rv = new RunView();\n // Valid statuses: Running, Completed, Paused, Failed, Cancelled\n let filter = `Status IN ('Running', 'Paused')`;\n\n if (conversationId) {\n filter += ` AND ConversationID='${conversationId}'`;\n }\n\n LogStatusEx({message: `[${timestamp}] 🤖 AgentStateService - Executing RunView for AI Agent Runs`, verboseOnly: true});\n const result = await rv.RunView<MJAIAgentRunEntity>(\n {\n EntityName: 'MJ: AI Agent Runs',\n ExtraFilter: filter,\n OrderBy: 'StartedAt DESC',\n MaxRows: 50,\n ResultType: 'entity_object'\n },\n this.currentUser\n );\n\n if (result.Success) {\n const runs = result.Results || [];\n LogStatusEx({message: `[${timestamp}] 🤖 AgentStateService - Found ${runs.length} active agent(s)`, verboseOnly: true});\n const agentsWithStatus = runs.map(run => this.mapRunToAgentWithStatus(run));\n this._activeAgents$.next(agentsWithStatus);\n\n // Stop polling if no active agents (optimization to reduce DB load)\n if (runs.length === 0 && this.pollSubscription) {\n LogStatusEx({message: `[${timestamp}] 🤖 AgentStateService - No active agents, stopping polling`, verboseOnly: true});\n this.stopPolling();\n }\n }\n } catch (error) {\n console.error('Failed to load active agents:', error);\n }\n }\n\n /**\n * Maps an agent run to include status and confidence information\n */\n private mapRunToAgentWithStatus(run: MJAIAgentRunEntity): AgentWithStatus {\n const status = this.determineAgentStatus(run);\n const confidence = this.extractConfidence(run);\n\n return {\n run,\n status,\n confidence\n };\n }\n\n /**\n * Determines the agent status based on the run entity\n */\n private determineAgentStatus(run: MJAIAgentRunEntity): AgentStatus {\n const status = run.Status?.toLowerCase() || 'running';\n\n // Check for errors\n if (status === 'error' || status === 'failed') {\n return 'error';\n }\n\n // Check for completion\n if (status === 'completed' || status === 'complete' || status === 'success') {\n return 'completed';\n }\n\n // Determine stage based on progress or elapsed time\n if (run.StartedAt) {\n const elapsed = Date.now() - new Date(run.StartedAt).getTime();\n const seconds = elapsed / 1000;\n\n // First 5 seconds: acknowledging\n if (seconds < 5) {\n return 'acknowledging';\n }\n\n // Check if nearing completion (has results or output)\n if (run.Result || run.Status === 'Completed') {\n // If there's output, likely completing\n return 'completing';\n }\n\n // Otherwise, working\n return 'working';\n }\n\n // Default to acknowledging if just started\n return 'acknowledging';\n }\n\n /**\n * Extracts confidence score from agent run if available\n */\n private extractConfidence(run: MJAIAgentRunEntity): number | null {\n // Try to parse confidence from Result or other fields\n // This is a placeholder - adjust based on actual data structure\n try {\n if (run.Result) {\n const result = typeof run.Result === 'string' ? JSON.parse(run.Result) : run.Result;\n if (result.confidence != null) {\n return parseFloat(result.confidence);\n }\n }\n } catch {\n // Ignore parse errors\n }\n\n return null;\n }\n\n /**\n * Cancels an agent run\n * @param agentRunId The agent run ID to cancel\n */\n async cancelAgent(agentRunId: string): Promise<boolean> {\n if (!this.currentUser) {\n return false;\n }\n\n try {\n const agent = this.getAgent(agentRunId);\n if (!agent) {\n return false;\n }\n\n agent.run.Status = 'Cancelled';\n const saved = await agent.run.Save();\n\n if (saved) {\n // Refresh the active agents list\n await this.refresh();\n return true;\n }\n } catch (error) {\n console.error('Failed to cancel agent:', error);\n }\n\n return false;\n }\n\n /**\n * Updates the poll interval\n * @param milliseconds The new poll interval in milliseconds\n */\n setPollInterval(milliseconds: number): void {\n this.pollInterval = milliseconds;\n\n // Restart polling if currently active\n if (this.pollSubscription && this.currentUser) {\n this.startPolling(this.currentUser);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"agent-state.service.js","sourceRoot":"","sources":["../../../src/lib/services/agent-state.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, OnDestroy } from '@angular/core';\nimport { BehaviorSubject, Observable, interval, Subscription } from 'rxjs';\nimport { map, shareReplay, switchMap } from 'rxjs/operators';\nimport { LogStatusEx, RunView, UserInfo } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { MJAIAgentRunEntity } from '@memberjunction/core-entities';\n\nexport type AgentStatus = 'acknowledging' | 'working' | 'completing' | 'completed' | 'error';\n\nexport interface AgentWithStatus {\n run: MJAIAgentRunEntity;\n status: AgentStatus;\n confidence: number | null;\n}\n\n/**\n * Manages agent state and provides real-time updates for active agents\n * Polls for agent status changes and provides reactive streams\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class AgentStateService implements OnDestroy {\n private _activeAgents$ = new BehaviorSubject<AgentWithStatus[]>([]);\n private pollSubscription?: Subscription;\n private currentUser?: UserInfo;\n private pollInterval: number = 30000; // Poll every 30 seconds (reduced from 3s to minimize DB load)\n private pollCycleCount = 0;\n /** Minimum poll cycles before allowing auto-stop. Prevents premature shutdown\n * when fire-and-forget ACK returns before the server creates the agent run record. */\n private readonly minimumPollCycles = 3;\n\n // Public observable streams\n public readonly activeAgents$ = this._activeAgents$.asObservable();\n\n constructor() {}\n\n ngOnDestroy(): void {\n this.stopPolling();\n }\n\n /**\n * Starts polling for active agents\n * @param currentUser The current user context\n * @param conversationId Optional conversation ID to filter by\n */\n startPolling(currentUser: UserInfo, conversationId?: string): void {\n this.currentUser = currentUser;\n this.stopPolling();\n this.pollCycleCount = 0;\n\n // Initial load\n this.loadActiveAgents(conversationId);\n\n // Start polling\n this.pollSubscription = interval(this.pollInterval)\n .pipe(switchMap(() => this.loadActiveAgents(conversationId)))\n .subscribe();\n }\n\n /**\n * Stops polling for active agents\n */\n stopPolling(): void {\n if (this.pollSubscription) {\n this.pollSubscription.unsubscribe();\n this.pollSubscription = undefined;\n }\n }\n\n /**\n * Gets active agents as an observable\n * @param conversationId Optional conversation ID to filter by\n */\n getActiveAgents(conversationId?: string): Observable<AgentWithStatus[]> {\n if (conversationId) {\n return this.activeAgents$.pipe(\n map(agents => agents.filter(a => UUIDsEqual(a.run.ConversationID, conversationId))),\n shareReplay(1)\n );\n }\n return this.activeAgents$;\n }\n\n /**\n * Gets a specific agent by ID\n * @param agentRunId The agent run ID\n */\n getAgent(agentRunId: string): AgentWithStatus | undefined {\n return this._activeAgents$.value.find(a => UUIDsEqual(a.run.ID, agentRunId));\n }\n\n /**\n * Manually refreshes active agents\n * @param conversationId Optional conversation ID to filter by\n */\n async refresh(conversationId?: string): Promise<void> {\n await this.loadActiveAgents(conversationId);\n }\n\n /**\n * Loads active agents from the database\n */\n private async loadActiveAgents(conversationId?: string): Promise<void> {\n if (!this.currentUser) {\n return;\n }\n\n this.pollCycleCount++;\n const timestamp = new Date().toISOString();\n LogStatusEx({message: `[${timestamp}] 🤖 AgentStateService.loadActiveAgents - Polling for active agents (conversation: ${conversationId || 'ALL'}, cycle: ${this.pollCycleCount})`, verboseOnly: true});\n\n try {\n const rv = new RunView();\n // Valid statuses: Running, Completed, Paused, Failed, Cancelled\n let filter = `Status IN ('Running', 'Paused')`;\n\n if (conversationId) {\n filter += ` AND ConversationID='${conversationId}'`;\n }\n\n LogStatusEx({message: `[${timestamp}] 🤖 AgentStateService - Executing RunView for AI Agent Runs`, verboseOnly: true});\n const result = await rv.RunView<MJAIAgentRunEntity>(\n {\n EntityName: 'MJ: AI Agent Runs',\n ExtraFilter: filter,\n OrderBy: 'StartedAt DESC',\n MaxRows: 50,\n ResultType: 'entity_object'\n },\n this.currentUser\n );\n\n if (result.Success) {\n const runs = result.Results || [];\n LogStatusEx({message: `[${timestamp}] 🤖 AgentStateService - Found ${runs.length} active agent(s)`, verboseOnly: true});\n const agentsWithStatus = runs.map(run => this.mapRunToAgentWithStatus(run));\n this._activeAgents$.next(agentsWithStatus);\n\n // Stop polling if no active agents AND minimum cycles met (optimization to reduce DB load).\n // The minimum cycle guard prevents premature shutdown when fire-and-forget returns\n // before the server has created the agent run record.\n if (runs.length === 0 && this.pollSubscription && this.pollCycleCount >= this.minimumPollCycles) {\n LogStatusEx({message: `[${timestamp}] 🤖 AgentStateService - No active agents after ${this.pollCycleCount} cycles, stopping polling`, verboseOnly: true});\n this.stopPolling();\n }\n }\n } catch (error) {\n console.error('Failed to load active agents:', error);\n }\n }\n\n /**\n * Maps an agent run to include status and confidence information\n */\n private mapRunToAgentWithStatus(run: MJAIAgentRunEntity): AgentWithStatus {\n const status = this.determineAgentStatus(run);\n const confidence = this.extractConfidence(run);\n\n return {\n run,\n status,\n confidence\n };\n }\n\n /**\n * Determines the agent status based on the run entity\n */\n private determineAgentStatus(run: MJAIAgentRunEntity): AgentStatus {\n const status = run.Status?.toLowerCase() || 'running';\n\n // Check for errors\n if (status === 'error' || status === 'failed') {\n return 'error';\n }\n\n // Check for completion\n if (status === 'completed' || status === 'complete' || status === 'success') {\n return 'completed';\n }\n\n // Determine stage based on progress or elapsed time\n if (run.StartedAt) {\n const elapsed = Date.now() - new Date(run.StartedAt).getTime();\n const seconds = elapsed / 1000;\n\n // First 5 seconds: acknowledging\n if (seconds < 5) {\n return 'acknowledging';\n }\n\n // Check if nearing completion (has results or output)\n if (run.Result || run.Status === 'Completed') {\n // If there's output, likely completing\n return 'completing';\n }\n\n // Otherwise, working\n return 'working';\n }\n\n // Default to acknowledging if just started\n return 'acknowledging';\n }\n\n /**\n * Extracts confidence score from agent run if available\n */\n private extractConfidence(run: MJAIAgentRunEntity): number | null {\n // Try to parse confidence from Result or other fields\n // This is a placeholder - adjust based on actual data structure\n try {\n if (run.Result) {\n const result = typeof run.Result === 'string' ? JSON.parse(run.Result) : run.Result;\n if (result.confidence != null) {\n return parseFloat(result.confidence);\n }\n }\n } catch {\n // Ignore parse errors\n }\n\n return null;\n }\n\n /**\n * Cancels an agent run\n * @param agentRunId The agent run ID to cancel\n */\n async cancelAgent(agentRunId: string): Promise<boolean> {\n if (!this.currentUser) {\n return false;\n }\n\n try {\n const agent = this.getAgent(agentRunId);\n if (!agent) {\n return false;\n }\n\n agent.run.Status = 'Cancelled';\n const saved = await agent.run.Save();\n\n if (saved) {\n // Refresh the active agents list\n await this.refresh();\n return true;\n }\n } catch (error) {\n console.error('Failed to cancel agent:', error);\n }\n\n return false;\n }\n\n /**\n * Updates the poll interval\n * @param milliseconds The new poll interval in milliseconds\n */\n setPollInterval(milliseconds: number): void {\n this.pollInterval = milliseconds;\n\n // Restart polling if currently active\n if (this.pollSubscription && this.currentUser) {\n this.startPolling(this.currentUser);\n }\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-permission.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/artifact-permission.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"artifact-permission.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/artifact-permission.service.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { Injectable } from '@angular/core';
2
2
  import { RunView, Metadata } from '@memberjunction/core';
3
+ import { UUIDsEqual } from '@memberjunction/global';
3
4
  import * as i0 from "@angular/core";
4
5
  import * as i1 from "./collection-permission.service";
5
6
  export class ArtifactPermissionService {
@@ -30,7 +31,7 @@ export class ArtifactPermissionService {
30
31
  async checkPermission(artifactId, userId, permission, currentUser) {
31
32
  // 1. Check ownership - owner has all permissions
32
33
  const artifact = await this.getArtifact(artifactId, currentUser);
33
- if (artifact && artifact.UserID === userId) {
34
+ if (artifact && UUIDsEqual(artifact.UserID, userId)) {
34
35
  return true;
35
36
  }
36
37
  // 2. Check explicit artifact permission
@@ -197,7 +198,7 @@ export class ArtifactPermissionService {
197
198
  */
198
199
  async isOwner(artifactId, userId, currentUser) {
199
200
  const artifact = await this.getArtifact(artifactId, currentUser);
200
- return artifact ? artifact.UserID === userId : false;
201
+ return artifact ? UUIDsEqual(artifact.UserID, userId) : false;
201
202
  }
202
203
  /**
203
204
  * Get all permissions for current user on an artifact (convenience method for UI)
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-permission.service.js","sourceRoot":"","sources":["../../../src/lib/services/artifact-permission.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { UserInfo, RunView, Metadata } from '@memberjunction/core';\nimport { MJArtifactPermissionEntity, MJArtifactEntity, MJCollectionArtifactEntity } from '@memberjunction/core-entities';\nimport { CollectionPermissionService } from './collection-permission.service';\n\nexport interface ArtifactPermission {\n id: string;\n artifactId: string;\n userId: string;\n userName: string;\n canRead: boolean;\n canEdit: boolean;\n canShare: boolean;\n sharedByUserId: string | null;\n sharedByUserName: string | null;\n sharedAt: Date;\n}\n\nexport interface EffectivePermission extends ArtifactPermission {\n source: 'owner' | 'explicit' | 'collection';\n collectionName?: string; // If inherited from collection\n}\n\nexport interface ArtifactPermissionSet {\n canRead: boolean;\n canEdit: boolean;\n canShare: boolean;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ArtifactPermissionService {\n\n constructor(\n private collectionPermissionService: CollectionPermissionService\n ) {}\n\n /**\n * Load all explicit permissions for an artifact\n */\n async loadPermissions(artifactId: string, currentUser: UserInfo): Promise<ArtifactPermission[]> {\n const rv = new RunView();\n const result = await rv.RunView<MJArtifactPermissionEntity>({\n EntityName: 'MJ: Artifact Permissions',\n ExtraFilter: `ArtifactID='${artifactId}'`,\n OrderBy: '__mj_CreatedAt ASC',\n ResultType: 'entity_object'\n }, currentUser);\n\n if (result.Success && result.Results) {\n return result.Results.map(p => this.mapToPermission(p));\n }\n return [];\n }\n\n /**\n * Check if user has specific permission for an artifact (HYBRID CHECK)\n * Checks in order: Owner > Explicit Permission > Collection Inheritance\n */\n async checkPermission(\n artifactId: string,\n userId: string,\n permission: 'read' | 'edit' | 'share',\n currentUser: UserInfo\n ): Promise<boolean> {\n // 1. Check ownership - owner has all permissions\n const artifact = await this.getArtifact(artifactId, currentUser);\n if (artifact && artifact.UserID === userId) {\n return true;\n }\n\n // 2. Check explicit artifact permission\n const explicit = await this.getExplicitPermission(artifactId, userId, currentUser);\n if (explicit) {\n return this.hasPermission(explicit, permission);\n }\n\n // 3. Check collection permission inheritance\n const collections = await this.getArtifactCollections(artifactId, currentUser);\n for (const collection of collections) {\n const collectionPermission = await this.collectionPermissionService.checkPermission(\n collection.CollectionID,\n userId,\n currentUser\n );\n\n if (collectionPermission && this.hasCollectionPermission(collectionPermission, permission)) {\n return true; // Inherited from collection\n }\n }\n\n // 4. No access\n return false;\n }\n\n /**\n * Get explicit permission record for a user on an artifact\n */\n async getExplicitPermission(\n artifactId: string,\n userId: string,\n currentUser: UserInfo\n ): Promise<ArtifactPermission | null> {\n const rv = new RunView();\n const result = await rv.RunView<MJArtifactPermissionEntity>({\n EntityName: 'MJ: Artifact Permissions',\n ExtraFilter: `ArtifactID='${artifactId}' AND UserID='${userId}'`,\n MaxRows: 1,\n ResultType: 'entity_object'\n }, currentUser);\n\n if (result.Success && result.Results && result.Results.length > 0) {\n return this.mapToPermission(result.Results[0]);\n }\n return null;\n }\n\n /**\n * Get all effective permissions for an artifact (owner + explicit + inherited)\n */\n async getEffectiveUsers(artifactId: string, currentUser: UserInfo): Promise<EffectivePermission[]> {\n const effectivePermissions: EffectivePermission[] = [];\n const seenUsers = new Set<string>();\n\n // 1. Add owner\n const artifact = await this.getArtifact(artifactId, currentUser);\n if (artifact && artifact.UserID) {\n effectivePermissions.push({\n id: '', // No permission record for owner\n artifactId: artifactId,\n userId: artifact.UserID,\n userName: artifact.User || 'Owner',\n canRead: true,\n canEdit: true,\n canShare: true,\n sharedByUserId: null,\n sharedByUserName: null,\n sharedAt: artifact.__mj_CreatedAt,\n source: 'owner'\n });\n seenUsers.add(artifact.UserID);\n }\n\n // 2. Add explicit permissions\n const explicitPerms = await this.loadPermissions(artifactId, currentUser);\n for (const perm of explicitPerms) {\n if (!seenUsers.has(perm.userId)) {\n effectivePermissions.push({\n ...perm,\n source: 'explicit'\n });\n seenUsers.add(perm.userId);\n }\n }\n\n // 3. Add collection-inherited permissions\n const collections = await this.getArtifactCollections(artifactId, currentUser);\n for (const collection of collections) {\n const collectionPerms = await this.collectionPermissionService.loadPermissions(\n collection.CollectionID,\n currentUser\n );\n\n for (const collPerm of collectionPerms) {\n if (!seenUsers.has(collPerm.userId)) {\n effectivePermissions.push({\n id: '',\n artifactId: artifactId,\n userId: collPerm.userId,\n userName: collPerm.userName,\n canRead: collPerm.canRead,\n canEdit: collPerm.canEdit,\n canShare: collPerm.canShare,\n sharedByUserId: collPerm.sharedByUserId,\n sharedByUserName: collPerm.sharedByUserName,\n sharedAt: collPerm.sharedAt,\n source: 'collection',\n collectionName: collection.Collection || 'Unknown Collection'\n });\n seenUsers.add(collPerm.userId);\n }\n }\n }\n\n return effectivePermissions;\n }\n\n /**\n * Grant explicit permission to a user\n */\n async grantPermission(\n artifactId: string,\n userId: string,\n permissions: ArtifactPermissionSet,\n sharedByUserId: string,\n currentUser: UserInfo\n ): Promise<MJArtifactPermissionEntity> {\n const md = new Metadata();\n const permission = await md.GetEntityObject<MJArtifactPermissionEntity>(\n 'MJ: Artifact Permissions',\n currentUser\n );\n\n permission.ArtifactID = artifactId;\n permission.UserID = userId;\n permission.CanRead = permissions.canRead;\n permission.CanEdit = permissions.canEdit;\n permission.CanShare = permissions.canShare;\n permission.SharedByUserID = sharedByUserId;\n\n const saved = await permission.Save();\n if (!saved) {\n throw new Error(permission.LatestResult?.Message || 'Failed to grant permission');\n }\n\n return permission;\n }\n\n /**\n * Update existing permission\n */\n async updatePermission(\n permissionId: string,\n permissions: ArtifactPermissionSet,\n currentUser: UserInfo\n ): Promise<boolean> {\n const md = new Metadata();\n const permission = await md.GetEntityObject<MJArtifactPermissionEntity>(\n 'MJ: Artifact Permissions',\n currentUser\n );\n\n await permission.Load(permissionId);\n permission.CanRead = permissions.canRead;\n permission.CanEdit = permissions.canEdit;\n permission.CanShare = permissions.canShare;\n\n return await permission.Save();\n }\n\n /**\n * Revoke explicit permission\n */\n async revokePermission(permissionId: string, currentUser: UserInfo): Promise<boolean> {\n const md = new Metadata();\n const permission = await md.GetEntityObject<MJArtifactPermissionEntity>(\n 'MJ: Artifact Permissions',\n currentUser\n );\n\n await permission.Load(permissionId);\n return await permission.Delete();\n }\n\n /**\n * Validate that requested permissions don't exceed granter's permissions\n */\n validatePermissions(\n requested: ArtifactPermissionSet,\n granter: ArtifactPermissionSet,\n isOwner: boolean\n ): boolean {\n if (isOwner) return true; // Owner can grant anything\n\n // Can't grant permissions you don't have\n if (requested.canEdit && !granter.canEdit) return false;\n if (requested.canShare && !granter.canShare) return false;\n\n return true;\n }\n\n /**\n * Get available permissions for a user to grant based on their own permissions\n */\n getAvailablePermissions(userPermissions: ArtifactPermissionSet, isOwner: boolean): string[] {\n if (isOwner) {\n return ['Read', 'Edit', 'Share'];\n }\n\n const available = ['Read']; // Always have read\n if (userPermissions.canEdit) available.push('Edit');\n if (userPermissions.canShare) available.push('Share');\n\n return available;\n }\n\n /**\n * Check if user is owner of artifact\n */\n async isOwner(artifactId: string, userId: string, currentUser: UserInfo): Promise<boolean> {\n const artifact = await this.getArtifact(artifactId, currentUser);\n return artifact ? artifact.UserID === userId : false;\n }\n\n /**\n * Get all permissions for current user on an artifact (convenience method for UI)\n */\n async getUserPermissions(artifactId: string, currentUser: UserInfo): Promise<ArtifactPermissionSet> {\n const [canRead, canEdit, canShare] = await Promise.all([\n this.checkPermission(artifactId, currentUser.ID, 'read', currentUser),\n this.checkPermission(artifactId, currentUser.ID, 'edit', currentUser),\n this.checkPermission(artifactId, currentUser.ID, 'share', currentUser)\n ]);\n\n return { canRead, canEdit, canShare };\n }\n\n /**\n * Helper: Get artifact record\n */\n private async getArtifact(artifactId: string, currentUser: UserInfo): Promise<MJArtifactEntity | null> {\n const rv = new RunView();\n const result = await rv.RunView<MJArtifactEntity>({\n EntityName: 'MJ: Artifacts',\n ExtraFilter: `ID='${artifactId}'`,\n MaxRows: 1,\n ResultType: 'entity_object'\n }, currentUser);\n\n if (result.Success && result.Results && result.Results.length > 0) {\n return result.Results[0];\n }\n return null;\n }\n\n /**\n * Helper: Get all collections containing this artifact\n */\n private async getArtifactCollections(\n artifactId: string,\n currentUser: UserInfo\n ): Promise<MJCollectionArtifactEntity[]> {\n const rv = new RunView();\n const result = await rv.RunView<MJCollectionArtifactEntity>({\n EntityName: 'MJ: Collection Artifacts',\n ExtraFilter: `ArtifactVersionID IN (\n SELECT ID FROM [__mj].[vwArtifactVersions] WHERE ArtifactID='${artifactId}'\n )`,\n ResultType: 'entity_object'\n }, currentUser);\n\n return result.Success && result.Results ? result.Results : [];\n }\n\n /**\n * Helper: Check if permission set has specific permission\n */\n private hasPermission(permission: ArtifactPermission, type: 'read' | 'edit' | 'share'): boolean {\n switch (type) {\n case 'read':\n return permission.canRead;\n case 'edit':\n return permission.canEdit;\n case 'share':\n return permission.canShare;\n default:\n return false;\n }\n }\n\n /**\n * Helper: Check if collection permission has specific permission\n */\n private hasCollectionPermission(\n permission: { canRead: boolean; canEdit: boolean; canShare: boolean },\n type: 'read' | 'edit' | 'share'\n ): boolean {\n switch (type) {\n case 'read':\n return permission.canRead;\n case 'edit':\n return permission.canEdit;\n case 'share':\n return permission.canShare;\n default:\n return false;\n }\n }\n\n private mapToPermission(entity: MJArtifactPermissionEntity): ArtifactPermission {\n return {\n id: entity.ID,\n artifactId: entity.ArtifactID,\n userId: entity.UserID,\n userName: entity.User || '',\n canRead: entity.CanRead,\n canEdit: entity.CanEdit,\n canShare: entity.CanShare,\n sharedByUserId: entity.SharedByUserID || null,\n sharedByUserName: entity.SharedByUser || null,\n sharedAt: entity.__mj_CreatedAt\n };\n }\n}\n"]}
1
+ {"version":3,"file":"artifact-permission.service.js","sourceRoot":"","sources":["../../../src/lib/services/artifact-permission.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { UserInfo, RunView, Metadata } from '@memberjunction/core';\nimport { MJArtifactPermissionEntity, MJArtifactEntity, MJCollectionArtifactEntity } from '@memberjunction/core-entities';\nimport { CollectionPermissionService } from './collection-permission.service';\nimport { UUIDsEqual } from '@memberjunction/global';\n\nexport interface ArtifactPermission {\n id: string;\n artifactId: string;\n userId: string;\n userName: string;\n canRead: boolean;\n canEdit: boolean;\n canShare: boolean;\n sharedByUserId: string | null;\n sharedByUserName: string | null;\n sharedAt: Date;\n}\n\nexport interface EffectivePermission extends ArtifactPermission {\n source: 'owner' | 'explicit' | 'collection';\n collectionName?: string; // If inherited from collection\n}\n\nexport interface ArtifactPermissionSet {\n canRead: boolean;\n canEdit: boolean;\n canShare: boolean;\n}\n\n@Injectable({\n providedIn: 'root'\n})\nexport class ArtifactPermissionService {\n\n constructor(\n private collectionPermissionService: CollectionPermissionService\n ) {}\n\n /**\n * Load all explicit permissions for an artifact\n */\n async loadPermissions(artifactId: string, currentUser: UserInfo): Promise<ArtifactPermission[]> {\n const rv = new RunView();\n const result = await rv.RunView<MJArtifactPermissionEntity>({\n EntityName: 'MJ: Artifact Permissions',\n ExtraFilter: `ArtifactID='${artifactId}'`,\n OrderBy: '__mj_CreatedAt ASC',\n ResultType: 'entity_object'\n }, currentUser);\n\n if (result.Success && result.Results) {\n return result.Results.map(p => this.mapToPermission(p));\n }\n return [];\n }\n\n /**\n * Check if user has specific permission for an artifact (HYBRID CHECK)\n * Checks in order: Owner > Explicit Permission > Collection Inheritance\n */\n async checkPermission(\n artifactId: string,\n userId: string,\n permission: 'read' | 'edit' | 'share',\n currentUser: UserInfo\n ): Promise<boolean> {\n // 1. Check ownership - owner has all permissions\n const artifact = await this.getArtifact(artifactId, currentUser);\n if (artifact && UUIDsEqual(artifact.UserID, userId)) {\n return true;\n }\n\n // 2. Check explicit artifact permission\n const explicit = await this.getExplicitPermission(artifactId, userId, currentUser);\n if (explicit) {\n return this.hasPermission(explicit, permission);\n }\n\n // 3. Check collection permission inheritance\n const collections = await this.getArtifactCollections(artifactId, currentUser);\n for (const collection of collections) {\n const collectionPermission = await this.collectionPermissionService.checkPermission(\n collection.CollectionID,\n userId,\n currentUser\n );\n\n if (collectionPermission && this.hasCollectionPermission(collectionPermission, permission)) {\n return true; // Inherited from collection\n }\n }\n\n // 4. No access\n return false;\n }\n\n /**\n * Get explicit permission record for a user on an artifact\n */\n async getExplicitPermission(\n artifactId: string,\n userId: string,\n currentUser: UserInfo\n ): Promise<ArtifactPermission | null> {\n const rv = new RunView();\n const result = await rv.RunView<MJArtifactPermissionEntity>({\n EntityName: 'MJ: Artifact Permissions',\n ExtraFilter: `ArtifactID='${artifactId}' AND UserID='${userId}'`,\n MaxRows: 1,\n ResultType: 'entity_object'\n }, currentUser);\n\n if (result.Success && result.Results && result.Results.length > 0) {\n return this.mapToPermission(result.Results[0]);\n }\n return null;\n }\n\n /**\n * Get all effective permissions for an artifact (owner + explicit + inherited)\n */\n async getEffectiveUsers(artifactId: string, currentUser: UserInfo): Promise<EffectivePermission[]> {\n const effectivePermissions: EffectivePermission[] = [];\n const seenUsers = new Set<string>();\n\n // 1. Add owner\n const artifact = await this.getArtifact(artifactId, currentUser);\n if (artifact && artifact.UserID) {\n effectivePermissions.push({\n id: '', // No permission record for owner\n artifactId: artifactId,\n userId: artifact.UserID,\n userName: artifact.User || 'Owner',\n canRead: true,\n canEdit: true,\n canShare: true,\n sharedByUserId: null,\n sharedByUserName: null,\n sharedAt: artifact.__mj_CreatedAt,\n source: 'owner'\n });\n seenUsers.add(artifact.UserID);\n }\n\n // 2. Add explicit permissions\n const explicitPerms = await this.loadPermissions(artifactId, currentUser);\n for (const perm of explicitPerms) {\n if (!seenUsers.has(perm.userId)) {\n effectivePermissions.push({\n ...perm,\n source: 'explicit'\n });\n seenUsers.add(perm.userId);\n }\n }\n\n // 3. Add collection-inherited permissions\n const collections = await this.getArtifactCollections(artifactId, currentUser);\n for (const collection of collections) {\n const collectionPerms = await this.collectionPermissionService.loadPermissions(\n collection.CollectionID,\n currentUser\n );\n\n for (const collPerm of collectionPerms) {\n if (!seenUsers.has(collPerm.userId)) {\n effectivePermissions.push({\n id: '',\n artifactId: artifactId,\n userId: collPerm.userId,\n userName: collPerm.userName,\n canRead: collPerm.canRead,\n canEdit: collPerm.canEdit,\n canShare: collPerm.canShare,\n sharedByUserId: collPerm.sharedByUserId,\n sharedByUserName: collPerm.sharedByUserName,\n sharedAt: collPerm.sharedAt,\n source: 'collection',\n collectionName: collection.Collection || 'Unknown Collection'\n });\n seenUsers.add(collPerm.userId);\n }\n }\n }\n\n return effectivePermissions;\n }\n\n /**\n * Grant explicit permission to a user\n */\n async grantPermission(\n artifactId: string,\n userId: string,\n permissions: ArtifactPermissionSet,\n sharedByUserId: string,\n currentUser: UserInfo\n ): Promise<MJArtifactPermissionEntity> {\n const md = new Metadata();\n const permission = await md.GetEntityObject<MJArtifactPermissionEntity>(\n 'MJ: Artifact Permissions',\n currentUser\n );\n\n permission.ArtifactID = artifactId;\n permission.UserID = userId;\n permission.CanRead = permissions.canRead;\n permission.CanEdit = permissions.canEdit;\n permission.CanShare = permissions.canShare;\n permission.SharedByUserID = sharedByUserId;\n\n const saved = await permission.Save();\n if (!saved) {\n throw new Error(permission.LatestResult?.Message || 'Failed to grant permission');\n }\n\n return permission;\n }\n\n /**\n * Update existing permission\n */\n async updatePermission(\n permissionId: string,\n permissions: ArtifactPermissionSet,\n currentUser: UserInfo\n ): Promise<boolean> {\n const md = new Metadata();\n const permission = await md.GetEntityObject<MJArtifactPermissionEntity>(\n 'MJ: Artifact Permissions',\n currentUser\n );\n\n await permission.Load(permissionId);\n permission.CanRead = permissions.canRead;\n permission.CanEdit = permissions.canEdit;\n permission.CanShare = permissions.canShare;\n\n return await permission.Save();\n }\n\n /**\n * Revoke explicit permission\n */\n async revokePermission(permissionId: string, currentUser: UserInfo): Promise<boolean> {\n const md = new Metadata();\n const permission = await md.GetEntityObject<MJArtifactPermissionEntity>(\n 'MJ: Artifact Permissions',\n currentUser\n );\n\n await permission.Load(permissionId);\n return await permission.Delete();\n }\n\n /**\n * Validate that requested permissions don't exceed granter's permissions\n */\n validatePermissions(\n requested: ArtifactPermissionSet,\n granter: ArtifactPermissionSet,\n isOwner: boolean\n ): boolean {\n if (isOwner) return true; // Owner can grant anything\n\n // Can't grant permissions you don't have\n if (requested.canEdit && !granter.canEdit) return false;\n if (requested.canShare && !granter.canShare) return false;\n\n return true;\n }\n\n /**\n * Get available permissions for a user to grant based on their own permissions\n */\n getAvailablePermissions(userPermissions: ArtifactPermissionSet, isOwner: boolean): string[] {\n if (isOwner) {\n return ['Read', 'Edit', 'Share'];\n }\n\n const available = ['Read']; // Always have read\n if (userPermissions.canEdit) available.push('Edit');\n if (userPermissions.canShare) available.push('Share');\n\n return available;\n }\n\n /**\n * Check if user is owner of artifact\n */\n async isOwner(artifactId: string, userId: string, currentUser: UserInfo): Promise<boolean> {\n const artifact = await this.getArtifact(artifactId, currentUser);\n return artifact ? UUIDsEqual(artifact.UserID, userId) : false;\n }\n\n /**\n * Get all permissions for current user on an artifact (convenience method for UI)\n */\n async getUserPermissions(artifactId: string, currentUser: UserInfo): Promise<ArtifactPermissionSet> {\n const [canRead, canEdit, canShare] = await Promise.all([\n this.checkPermission(artifactId, currentUser.ID, 'read', currentUser),\n this.checkPermission(artifactId, currentUser.ID, 'edit', currentUser),\n this.checkPermission(artifactId, currentUser.ID, 'share', currentUser)\n ]);\n\n return { canRead, canEdit, canShare };\n }\n\n /**\n * Helper: Get artifact record\n */\n private async getArtifact(artifactId: string, currentUser: UserInfo): Promise<MJArtifactEntity | null> {\n const rv = new RunView();\n const result = await rv.RunView<MJArtifactEntity>({\n EntityName: 'MJ: Artifacts',\n ExtraFilter: `ID='${artifactId}'`,\n MaxRows: 1,\n ResultType: 'entity_object'\n }, currentUser);\n\n if (result.Success && result.Results && result.Results.length > 0) {\n return result.Results[0];\n }\n return null;\n }\n\n /**\n * Helper: Get all collections containing this artifact\n */\n private async getArtifactCollections(\n artifactId: string,\n currentUser: UserInfo\n ): Promise<MJCollectionArtifactEntity[]> {\n const rv = new RunView();\n const result = await rv.RunView<MJCollectionArtifactEntity>({\n EntityName: 'MJ: Collection Artifacts',\n ExtraFilter: `ArtifactVersionID IN (\n SELECT ID FROM [__mj].[vwArtifactVersions] WHERE ArtifactID='${artifactId}'\n )`,\n ResultType: 'entity_object'\n }, currentUser);\n\n return result.Success && result.Results ? result.Results : [];\n }\n\n /**\n * Helper: Check if permission set has specific permission\n */\n private hasPermission(permission: ArtifactPermission, type: 'read' | 'edit' | 'share'): boolean {\n switch (type) {\n case 'read':\n return permission.canRead;\n case 'edit':\n return permission.canEdit;\n case 'share':\n return permission.canShare;\n default:\n return false;\n }\n }\n\n /**\n * Helper: Check if collection permission has specific permission\n */\n private hasCollectionPermission(\n permission: { canRead: boolean; canEdit: boolean; canShare: boolean },\n type: 'read' | 'edit' | 'share'\n ): boolean {\n switch (type) {\n case 'read':\n return permission.canRead;\n case 'edit':\n return permission.canEdit;\n case 'share':\n return permission.canShare;\n default:\n return false;\n }\n }\n\n private mapToPermission(entity: MJArtifactPermissionEntity): ArtifactPermission {\n return {\n id: entity.ID,\n artifactId: entity.ArtifactID,\n userId: entity.UserID,\n userName: entity.User || '',\n canRead: entity.CanRead,\n canEdit: entity.CanEdit,\n canShare: entity.CanShare,\n sharedByUserId: entity.SharedByUserID || null,\n sharedByUserName: entity.SharedByUser || null,\n sharedAt: entity.__mj_CreatedAt\n };\n }\n}\n"]}