@memberjunction/ng-conversations 2.105.0 → 2.107.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +19 -13
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +120 -122
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +64 -0
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +251 -107
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +3 -5
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +38 -9
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/models/lazy-artifact-info.d.ts +68 -0
- package/dist/lib/models/lazy-artifact-info.d.ts.map +1 -0
- package/dist/lib/models/lazy-artifact-info.js +150 -0
- package/dist/lib/models/lazy-artifact-info.js.map +1 -0
- package/dist/lib/services/conversation-agent.service.d.ts +11 -0
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +138 -5
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +12 -12
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { EventEmitter, OnInit, OnDestroy, DoCheck, ChangeDetectorRef, AfterViewChecked } from '@angular/core';
|
|
2
2
|
import { UserInfo, CompositeKey } from '@memberjunction/core';
|
|
3
|
-
import { ConversationDetailEntity, AIAgentRunEntity, AIAgentRunEntityExtended,
|
|
3
|
+
import { ConversationDetailEntity, AIAgentRunEntity, AIAgentRunEntityExtended, TaskEntity } from '@memberjunction/core-entities';
|
|
4
4
|
import { ConversationStateService } from '../../services/conversation-state.service';
|
|
5
5
|
import { DataCacheService } from '../../services/data-cache.service';
|
|
6
6
|
import { AgentStateService } from '../../services/agent-state.service';
|
|
7
7
|
import { ConversationAgentService } from '../../services/conversation-agent.service';
|
|
8
8
|
import { ActiveTasksService } from '../../services/active-tasks.service';
|
|
9
|
+
import { LazyArtifactInfo } from '../../models/lazy-artifact-info';
|
|
9
10
|
import { Subject } from 'rxjs';
|
|
10
11
|
import * as i0 from "@angular/core";
|
|
11
12
|
export declare class ConversationChatAreaComponent implements OnInit, OnDestroy, DoCheck, AfterViewChecked {
|
|
@@ -32,6 +33,7 @@ export declare class ConversationChatAreaComponent implements OnInit, OnDestroy,
|
|
|
32
33
|
showScrollToBottomIcon: boolean;
|
|
33
34
|
private scrollToBottom;
|
|
34
35
|
private previousConversationId;
|
|
36
|
+
private lastLoadedConversationId;
|
|
35
37
|
isProcessing: boolean;
|
|
36
38
|
memberCount: number;
|
|
37
39
|
artifactCount: number;
|
|
@@ -46,10 +48,7 @@ export declare class ConversationChatAreaComponent implements OnInit, OnDestroy,
|
|
|
46
48
|
selectedVersionNumber: number | undefined;
|
|
47
49
|
artifactPaneWidth: number;
|
|
48
50
|
expandedArtifactId: string | null;
|
|
49
|
-
artifactsByDetailId: Map<string,
|
|
50
|
-
artifact: ArtifactEntity;
|
|
51
|
-
version: ArtifactVersionEntity;
|
|
52
|
-
}[]>;
|
|
51
|
+
artifactsByDetailId: Map<string, LazyArtifactInfo[]>;
|
|
53
52
|
agentRunsByDetailId: Map<string, AIAgentRunEntityExtended>;
|
|
54
53
|
isLoadingPeripheralData: boolean;
|
|
55
54
|
artifactViewerRefresh$: Subject<{
|
|
@@ -70,6 +69,14 @@ export declare class ConversationChatAreaComponent implements OnInit, OnDestroy,
|
|
|
70
69
|
/**
|
|
71
70
|
* Load peripheral data (agent runs and artifacts) in background
|
|
72
71
|
* This allows messages to display immediately while slower queries complete
|
|
72
|
+
*
|
|
73
|
+
* PERFORMANCE OPTIMIZATION: Uses single optimized query for artifacts instead of 3 sequential queries
|
|
74
|
+
* - OLD: 3 sequential RunView queries (~880ms, ~500KB payload with Content field)
|
|
75
|
+
* - NEW: 1 RunQuery with JOINs (~200ms, ~15KB payload without Content field)
|
|
76
|
+
* - Lazy-loading pattern: Display data loaded immediately, full entities loaded on-demand
|
|
77
|
+
*
|
|
78
|
+
* Uses lastLoadedConversationId to ensure we only load once per conversation, even during
|
|
79
|
+
* multiple change detection cycles that might occur during async operations.
|
|
73
80
|
*/
|
|
74
81
|
private loadPeripheralData;
|
|
75
82
|
/**
|
|
@@ -99,6 +106,7 @@ export declare class ConversationChatAreaComponent implements OnInit, OnDestroy,
|
|
|
99
106
|
/**
|
|
100
107
|
* Reload artifacts for a specific message ID
|
|
101
108
|
* Called after an artifact is created to update the UI immediately
|
|
109
|
+
* Uses same optimized query pattern as loadPeripheralData()
|
|
102
110
|
*/
|
|
103
111
|
private reloadArtifactsForMessage;
|
|
104
112
|
openProjectSelector(): void;
|
|
@@ -106,11 +114,13 @@ export declare class ConversationChatAreaComponent implements OnInit, OnDestroy,
|
|
|
106
114
|
viewArtifacts(): void;
|
|
107
115
|
/**
|
|
108
116
|
* Calculate count of unique artifacts (not versions)
|
|
117
|
+
* Works with LazyArtifactInfo - uses artifactId from display data
|
|
109
118
|
*/
|
|
110
119
|
private calculateUniqueArtifactCount;
|
|
111
120
|
/**
|
|
112
121
|
* Get unique artifacts grouped by artifact ID (not by conversation detail)
|
|
113
122
|
* Returns the latest version info for each unique artifact with all versions
|
|
123
|
+
* Works with LazyArtifactInfo - uses display data without loading full entities
|
|
114
124
|
*/
|
|
115
125
|
getArtifactsArray(): Array<{
|
|
116
126
|
artifactId: string;
|
|
@@ -157,19 +167,15 @@ export declare class ConversationChatAreaComponent implements OnInit, OnDestroy,
|
|
|
157
167
|
/**
|
|
158
168
|
* Get artifact info for a conversation detail
|
|
159
169
|
* Returns the first artifact if multiple exist (for backward compatibility with message display)
|
|
170
|
+
* Returns LazyArtifactInfo - caller can trigger lazy load if full entities needed
|
|
160
171
|
*/
|
|
161
|
-
getArtifactInfo(conversationDetailId: string):
|
|
162
|
-
artifact: ArtifactEntity;
|
|
163
|
-
version: ArtifactVersionEntity;
|
|
164
|
-
} | undefined;
|
|
172
|
+
getArtifactInfo(conversationDetailId: string): LazyArtifactInfo | undefined;
|
|
165
173
|
/**
|
|
166
174
|
* Get ALL artifacts for a conversation detail
|
|
167
175
|
* Use this when you need to display all artifacts (e.g., in a list)
|
|
176
|
+
* Returns LazyArtifactInfo array - caller can trigger lazy load if full entities needed
|
|
168
177
|
*/
|
|
169
|
-
getAllArtifactsForDetail(conversationDetailId: string):
|
|
170
|
-
artifact: ArtifactEntity;
|
|
171
|
-
version: ArtifactVersionEntity;
|
|
172
|
-
}>;
|
|
178
|
+
getAllArtifactsForDetail(conversationDetailId: string): LazyArtifactInfo[];
|
|
173
179
|
/**
|
|
174
180
|
* Resize handle methods for artifact pane
|
|
175
181
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-chat-area.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/conversation/conversation-chat-area.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAyB,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC/J,OAAO,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"conversation-chat-area.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/conversation/conversation-chat-area.component.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
|
|
2
|
-
import { RunView, Metadata } from '@memberjunction/core';
|
|
2
|
+
import { RunView, RunQuery, Metadata } from '@memberjunction/core';
|
|
3
|
+
import { LazyArtifactInfo } from '../../models/lazy-artifact-info';
|
|
3
4
|
import { Subject } from 'rxjs';
|
|
4
5
|
import * as i0 from "@angular/core";
|
|
5
6
|
import * as i1 from "../../services/conversation-state.service";
|
|
@@ -295,6 +296,7 @@ export class ConversationChatAreaComponent {
|
|
|
295
296
|
showScrollToBottomIcon = false;
|
|
296
297
|
scrollToBottom = false;
|
|
297
298
|
previousConversationId = null;
|
|
299
|
+
lastLoadedConversationId = null; // Track which conversation's peripheral data was loaded
|
|
298
300
|
isProcessing = false;
|
|
299
301
|
memberCount = 1;
|
|
300
302
|
artifactCount = 0;
|
|
@@ -309,8 +311,8 @@ export class ConversationChatAreaComponent {
|
|
|
309
311
|
selectedVersionNumber = undefined; // Version to show in artifact viewer
|
|
310
312
|
artifactPaneWidth = 40; // Default 40% width
|
|
311
313
|
expandedArtifactId = null; // Track which artifact card is expanded in modal
|
|
312
|
-
// Artifact mapping: ConversationDetailID -> Array of
|
|
313
|
-
//
|
|
314
|
+
// Artifact mapping: ConversationDetailID -> Array of LazyArtifactInfo
|
|
315
|
+
// Uses lazy-loading pattern: display data loaded immediately, full entities on-demand
|
|
314
316
|
// Supports multiple artifacts per conversation detail (0-N relationship)
|
|
315
317
|
artifactsByDetailId = new Map();
|
|
316
318
|
// Agent run mapping: ConversationDetailID -> AIAgentRunEntityExtended
|
|
@@ -411,14 +413,32 @@ export class ConversationChatAreaComponent {
|
|
|
411
413
|
/**
|
|
412
414
|
* Load peripheral data (agent runs and artifacts) in background
|
|
413
415
|
* This allows messages to display immediately while slower queries complete
|
|
416
|
+
*
|
|
417
|
+
* PERFORMANCE OPTIMIZATION: Uses single optimized query for artifacts instead of 3 sequential queries
|
|
418
|
+
* - OLD: 3 sequential RunView queries (~880ms, ~500KB payload with Content field)
|
|
419
|
+
* - NEW: 1 RunQuery with JOINs (~200ms, ~15KB payload without Content field)
|
|
420
|
+
* - Lazy-loading pattern: Display data loaded immediately, full entities loaded on-demand
|
|
421
|
+
*
|
|
422
|
+
* Uses lastLoadedConversationId to ensure we only load once per conversation, even during
|
|
423
|
+
* multiple change detection cycles that might occur during async operations.
|
|
414
424
|
*/
|
|
415
425
|
async loadPeripheralData(conversationId) {
|
|
426
|
+
// Skip if we've already loaded peripheral data for this conversation
|
|
427
|
+
console.log(` Last Loaded Conversation ID: ${this.lastLoadedConversationId}, Current Conversation ID: ${conversationId}`);
|
|
428
|
+
if (this.lastLoadedConversationId === conversationId) {
|
|
429
|
+
console.log(`⏭️ Skipping peripheral data load - already loaded for conversation ${conversationId}`);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
// Mark this conversation as loaded to prevent duplicate loads from starting at same time or similar time
|
|
433
|
+
this.lastLoadedConversationId = conversationId;
|
|
434
|
+
console.log(`📊 Loading peripheral data for conversation ${conversationId}`);
|
|
416
435
|
try {
|
|
417
436
|
const rv = new RunView();
|
|
437
|
+
const rq = new RunQuery();
|
|
418
438
|
const md = new Metadata();
|
|
419
439
|
const convoDetailEntity = md.EntityByName("Conversation Details");
|
|
420
440
|
// Load agent runs and artifacts in parallel
|
|
421
|
-
const [agentRunsResult,
|
|
441
|
+
const [agentRunsResult, artifactMapResult] = await Promise.all([
|
|
422
442
|
rv.RunView({
|
|
423
443
|
EntityName: 'MJ: AI Agent Runs',
|
|
424
444
|
ExtraFilter: `ConversationDetailID IN (SELECT ID FROM [${convoDetailEntity.SchemaName}].[${convoDetailEntity.BaseView}] WHERE ConversationID='${conversationId}')`,
|
|
@@ -426,10 +446,10 @@ export class ConversationChatAreaComponent {
|
|
|
426
446
|
// Only fetch fields we actually display to reduce payload size
|
|
427
447
|
Fields: ['ID', 'AgentID', 'Agent', 'Status', '__mj_CreatedAt', '__mj_UpdatedAt', 'TotalPromptTokensUsed', 'TotalCompletionTokensUsed', 'TotalCost', 'ConversationDetailID']
|
|
428
448
|
}, this.currentUser),
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
449
|
+
rq.RunQuery({
|
|
450
|
+
QueryName: 'GetConversationArtifactsMap',
|
|
451
|
+
CategoryPath: '/MJ/Conversations',
|
|
452
|
+
Parameters: { ConversationID: conversationId }
|
|
433
453
|
}, this.currentUser)
|
|
434
454
|
]);
|
|
435
455
|
// Build agent runs map - single query loads all runs for this conversation
|
|
@@ -441,54 +461,47 @@ export class ConversationChatAreaComponent {
|
|
|
441
461
|
}
|
|
442
462
|
}
|
|
443
463
|
}
|
|
444
|
-
// Build artifact map
|
|
464
|
+
// Build artifact map using batch-loading pattern for better performance
|
|
445
465
|
this.artifactsByDetailId.clear();
|
|
446
|
-
if (
|
|
447
|
-
//
|
|
448
|
-
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
466
|
+
if (artifactMapResult.Success && artifactMapResult.Results && artifactMapResult.Results.length > 0) {
|
|
467
|
+
// PERFORMANCE: Batch load all artifacts and versions upfront to avoid N+1 queries
|
|
468
|
+
// Collect all unique artifact and version IDs
|
|
469
|
+
const artifactIds = new Set();
|
|
470
|
+
const versionIds = new Set();
|
|
471
|
+
for (const row of artifactMapResult.Results) {
|
|
472
|
+
artifactIds.add(row.ArtifactID);
|
|
473
|
+
versionIds.add(row.ArtifactVersionID);
|
|
474
|
+
}
|
|
475
|
+
console.log(`📦 Batch loading ${artifactIds.size} artifacts and ${versionIds.size} versions...`);
|
|
476
|
+
// Batch load ALL artifacts and versions with 2 queries instead of N queries
|
|
477
|
+
const [artifactsResult, versionsResult] = await Promise.all([
|
|
478
|
+
rv.RunView({
|
|
459
479
|
EntityName: 'MJ: Artifacts',
|
|
460
|
-
ExtraFilter: `ID IN (${
|
|
480
|
+
ExtraFilter: `ID IN ('${Array.from(artifactIds).join("','")}')`,
|
|
461
481
|
ResultType: 'entity_object'
|
|
462
|
-
}, this.currentUser)
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
existing.push({
|
|
482
|
-
artifact: artifact, // Full ArtifactEntity
|
|
483
|
-
version: version // Full ArtifactVersionEntity
|
|
484
|
-
});
|
|
485
|
-
this.artifactsByDetailId.set(junctionRecord.ConversationDetailID, existing);
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
// Create new Map reference to trigger Angular change detection
|
|
489
|
-
this.artifactsByDetailId = new Map(this.artifactsByDetailId);
|
|
490
|
-
console.log(`📦 Preloaded ${this.artifactsByDetailId.size} artifacts for conversation ${conversationId}`);
|
|
482
|
+
}, this.currentUser),
|
|
483
|
+
rv.RunView({
|
|
484
|
+
EntityName: 'MJ: Artifact Versions',
|
|
485
|
+
ExtraFilter: `ID IN ('${Array.from(versionIds).join("','")}')`,
|
|
486
|
+
ResultType: 'entity_object'
|
|
487
|
+
}, this.currentUser)
|
|
488
|
+
]);
|
|
489
|
+
// Create lookup maps for O(1) access
|
|
490
|
+
const artifactMap = new Map(artifactsResult.Results?.map(a => [a.ID, a]) || []);
|
|
491
|
+
const versionMap = new Map(versionsResult.Results?.map(v => [v.ID, v]) || []);
|
|
492
|
+
console.log(`📦 Batch loaded ${artifactMap.size} artifacts and ${versionMap.size} versions`);
|
|
493
|
+
// Group by ConversationDetailID with pre-loaded entities
|
|
494
|
+
for (const row of artifactMapResult.Results) {
|
|
495
|
+
const lazyInfo = new LazyArtifactInfo(row, this.currentUser, artifactMap.get(row.ArtifactID), // Pre-loaded artifact
|
|
496
|
+
versionMap.get(row.ArtifactVersionID) // Pre-loaded version
|
|
497
|
+
);
|
|
498
|
+
const existing = this.artifactsByDetailId.get(row.ConversationDetailID) || [];
|
|
499
|
+
existing.push(lazyInfo);
|
|
500
|
+
this.artifactsByDetailId.set(row.ConversationDetailID, existing);
|
|
491
501
|
}
|
|
502
|
+
// Create new Map reference to trigger Angular change detection
|
|
503
|
+
this.artifactsByDetailId = new Map(this.artifactsByDetailId);
|
|
504
|
+
console.log(`📦 Loaded ${this.artifactsByDetailId.size} artifact mappings for conversation ${conversationId} (batch-loaded, no lazy loading needed)`);
|
|
492
505
|
}
|
|
493
506
|
// Update artifact count for header display (unique artifacts, not versions)
|
|
494
507
|
this.artifactCount = this.calculateUniqueArtifactCount();
|
|
@@ -496,18 +509,20 @@ export class ConversationChatAreaComponent {
|
|
|
496
509
|
console.log(`📊 Artifact Count: ${this.artifactCount}`);
|
|
497
510
|
console.log(`📦 Artifacts by Detail ID:`, Array.from(this.artifactsByDetailId.entries()).flatMap(([detailId, artifactList]) => artifactList.map(info => ({
|
|
498
511
|
conversationDetailId: detailId,
|
|
499
|
-
artifactId: info.
|
|
500
|
-
artifactName: info.
|
|
501
|
-
versionId: info.
|
|
502
|
-
versionNumber: info.
|
|
512
|
+
artifactId: info.artifactId,
|
|
513
|
+
artifactName: info.artifactName,
|
|
514
|
+
versionId: info.artifactVersionId,
|
|
515
|
+
versionNumber: info.versionNumber
|
|
503
516
|
}))));
|
|
504
517
|
// CRITICAL: Trigger message re-render now that agent runs and artifacts are loaded
|
|
505
518
|
// This updates all message components with the newly loaded agent run data
|
|
506
519
|
this.messages = [...this.messages]; // Create new array reference to trigger change detection
|
|
507
520
|
this.cdr.detectChanges();
|
|
521
|
+
console.log(`✅ Peripheral data loaded successfully for conversation ${conversationId}`);
|
|
508
522
|
}
|
|
509
523
|
catch (error) {
|
|
510
524
|
console.error('Failed to load peripheral data:', error);
|
|
525
|
+
// Don't set lastLoadedConversationId on error so we can retry
|
|
511
526
|
}
|
|
512
527
|
}
|
|
513
528
|
/**
|
|
@@ -564,8 +579,8 @@ export class ConversationChatAreaComponent {
|
|
|
564
579
|
if (this.artifactsByDetailId.has(event.message.ID) && !this.showArtifactPanel) {
|
|
565
580
|
const artifactList = this.artifactsByDetailId.get(event.message.ID);
|
|
566
581
|
if (artifactList && artifactList.length > 0) {
|
|
567
|
-
// Show the first (or most recent) artifact
|
|
568
|
-
this.selectedArtifactId = artifactList[0].
|
|
582
|
+
// Show the first (or most recent) artifact - uses display data, no lazy load needed
|
|
583
|
+
this.selectedArtifactId = artifactList[0].artifactId;
|
|
569
584
|
this.showArtifactPanel = true;
|
|
570
585
|
}
|
|
571
586
|
}
|
|
@@ -591,69 +606,48 @@ export class ConversationChatAreaComponent {
|
|
|
591
606
|
/**
|
|
592
607
|
* Reload artifacts for a specific message ID
|
|
593
608
|
* Called after an artifact is created to update the UI immediately
|
|
609
|
+
* Uses same optimized query pattern as loadPeripheralData()
|
|
594
610
|
*/
|
|
595
611
|
async reloadArtifactsForMessage(conversationDetailId) {
|
|
596
612
|
console.log(`🔄 Reloading artifacts for message ${conversationDetailId}`);
|
|
597
613
|
try {
|
|
598
|
-
const
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
614
|
+
const rq = new RunQuery();
|
|
615
|
+
// Get the ConversationID for this detail
|
|
616
|
+
const md = new Metadata();
|
|
617
|
+
const detail = await md.GetEntityObject('Conversation Details', this.currentUser);
|
|
618
|
+
if (!(await detail.Load(conversationDetailId))) {
|
|
619
|
+
console.error('Failed to load conversation detail');
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
// Use optimized query to reload all artifacts for this conversation
|
|
623
|
+
const artifactMapResult = await rq.RunQuery({
|
|
624
|
+
QueryName: 'GetConversationArtifactsMap',
|
|
625
|
+
CategoryPath: '/MJ/Conversations',
|
|
626
|
+
Parameters: { ConversationID: detail.ConversationID }
|
|
603
627
|
}, this.currentUser);
|
|
604
|
-
console.log(`📊
|
|
605
|
-
success:
|
|
606
|
-
count:
|
|
607
|
-
error:
|
|
628
|
+
console.log(`📊 Query result:`, {
|
|
629
|
+
success: artifactMapResult.Success,
|
|
630
|
+
count: artifactMapResult.Results?.length || 0,
|
|
631
|
+
error: artifactMapResult.ErrorMessage
|
|
608
632
|
});
|
|
609
|
-
if (
|
|
610
|
-
//
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
const fullArtifactsResult = await rv.RunView({
|
|
621
|
-
EntityName: 'MJ: Artifacts',
|
|
622
|
-
ExtraFilter: `ID IN (${artifactIds})`,
|
|
623
|
-
ResultType: 'entity_object'
|
|
624
|
-
}, this.currentUser);
|
|
625
|
-
if (fullArtifactsResult.Success && fullArtifactsResult.Results) {
|
|
626
|
-
// Create maps for fast lookup
|
|
627
|
-
const artifactEntities = new Map();
|
|
628
|
-
const versionEntities = new Map();
|
|
629
|
-
for (const artifact of fullArtifactsResult.Results) {
|
|
630
|
-
artifactEntities.set(artifact.ID, artifact);
|
|
631
|
-
}
|
|
632
|
-
for (const version of versionsResult.Results) {
|
|
633
|
-
versionEntities.set(version.ID, version);
|
|
634
|
-
}
|
|
635
|
-
// Update artifact map with full entities (supports multiple artifacts per detail)
|
|
636
|
-
const artifactList = [];
|
|
637
|
-
for (const junctionRecord of artifactsResult.Results) {
|
|
638
|
-
const version = versionEntities.get(junctionRecord.ArtifactVersionID);
|
|
639
|
-
const artifact = version ? artifactEntities.get(version.ArtifactID) : undefined;
|
|
640
|
-
if (version && artifact) {
|
|
641
|
-
artifactList.push({
|
|
642
|
-
artifact: artifact,
|
|
643
|
-
version: version
|
|
644
|
-
});
|
|
645
|
-
console.log(`✅ Loaded artifact ${artifact.ID} v${version.VersionNumber} for message ${conversationDetailId}`);
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
if (artifactList.length > 0) {
|
|
649
|
-
this.artifactsByDetailId.set(conversationDetailId, artifactList);
|
|
650
|
-
}
|
|
651
|
-
// Create new Map reference to trigger Angular change detection
|
|
652
|
-
this.artifactsByDetailId = new Map(this.artifactsByDetailId);
|
|
653
|
-
// Update artifact count
|
|
654
|
-
this.artifactCount = this.calculateUniqueArtifactCount();
|
|
633
|
+
if (artifactMapResult.Success && artifactMapResult.Results && artifactMapResult.Results.length > 0) {
|
|
634
|
+
// Clear existing artifacts for this detail and rebuild
|
|
635
|
+
this.artifactsByDetailId.delete(conversationDetailId);
|
|
636
|
+
// Filter results for this specific conversation detail ID
|
|
637
|
+
const detailArtifacts = artifactMapResult.Results.filter(row => row.ConversationDetailID === conversationDetailId);
|
|
638
|
+
if (detailArtifacts.length > 0) {
|
|
639
|
+
const artifactList = [];
|
|
640
|
+
for (const row of detailArtifacts) {
|
|
641
|
+
const lazyInfo = new LazyArtifactInfo(row, this.currentUser);
|
|
642
|
+
artifactList.push(lazyInfo);
|
|
643
|
+
console.log(`✅ Loaded artifact ${row.ArtifactID} v${row.VersionNumber} for message ${conversationDetailId}`);
|
|
655
644
|
}
|
|
645
|
+
this.artifactsByDetailId.set(conversationDetailId, artifactList);
|
|
656
646
|
}
|
|
647
|
+
// Create new Map reference to trigger Angular change detection
|
|
648
|
+
this.artifactsByDetailId = new Map(this.artifactsByDetailId);
|
|
649
|
+
// Update artifact count
|
|
650
|
+
this.artifactCount = this.calculateUniqueArtifactCount();
|
|
657
651
|
}
|
|
658
652
|
}
|
|
659
653
|
catch (error) {
|
|
@@ -671,12 +665,13 @@ export class ConversationChatAreaComponent {
|
|
|
671
665
|
}
|
|
672
666
|
/**
|
|
673
667
|
* Calculate count of unique artifacts (not versions)
|
|
668
|
+
* Works with LazyArtifactInfo - uses artifactId from display data
|
|
674
669
|
*/
|
|
675
670
|
calculateUniqueArtifactCount() {
|
|
676
671
|
const uniqueArtifactIds = new Set();
|
|
677
672
|
for (const artifactList of this.artifactsByDetailId.values()) {
|
|
678
673
|
for (const info of artifactList) {
|
|
679
|
-
uniqueArtifactIds.add(info.
|
|
674
|
+
uniqueArtifactIds.add(info.artifactId);
|
|
680
675
|
}
|
|
681
676
|
}
|
|
682
677
|
return uniqueArtifactIds.size;
|
|
@@ -684,16 +679,17 @@ export class ConversationChatAreaComponent {
|
|
|
684
679
|
/**
|
|
685
680
|
* Get unique artifacts grouped by artifact ID (not by conversation detail)
|
|
686
681
|
* Returns the latest version info for each unique artifact with all versions
|
|
682
|
+
* Works with LazyArtifactInfo - uses display data without loading full entities
|
|
687
683
|
*/
|
|
688
684
|
getArtifactsArray() {
|
|
689
685
|
const artifactMap = new Map();
|
|
690
686
|
// Group by artifactId, collecting all version details
|
|
691
687
|
for (const artifactList of this.artifactsByDetailId.values()) {
|
|
692
688
|
for (const info of artifactList) {
|
|
693
|
-
const artifactId = info.
|
|
694
|
-
const versionId = info.
|
|
695
|
-
const versionNumber = info.
|
|
696
|
-
const name = info.
|
|
689
|
+
const artifactId = info.artifactId;
|
|
690
|
+
const versionId = info.artifactVersionId;
|
|
691
|
+
const versionNumber = info.versionNumber || 1;
|
|
692
|
+
const name = info.artifactName || 'Untitled';
|
|
697
693
|
if (!artifactMap.has(artifactId)) {
|
|
698
694
|
artifactMap.set(artifactId, {
|
|
699
695
|
artifactId: artifactId,
|
|
@@ -815,12 +811,12 @@ export class ConversationChatAreaComponent {
|
|
|
815
811
|
}
|
|
816
812
|
onArtifactClicked(data) {
|
|
817
813
|
this.selectedArtifactId = data.artifactId;
|
|
818
|
-
// If versionId is provided, find the version number
|
|
814
|
+
// If versionId is provided, find the version number from display data (no lazy load needed)
|
|
819
815
|
if (data.versionId) {
|
|
820
816
|
for (const [detailId, artifactList] of this.artifactsByDetailId.entries()) {
|
|
821
817
|
for (const artifactInfo of artifactList) {
|
|
822
|
-
if (artifactInfo.
|
|
823
|
-
this.selectedVersionNumber = artifactInfo.
|
|
818
|
+
if (artifactInfo.artifactVersionId === data.versionId) {
|
|
819
|
+
this.selectedVersionNumber = artifactInfo.versionNumber;
|
|
824
820
|
console.log(`📦 Opening artifact viewer for v${this.selectedVersionNumber}`);
|
|
825
821
|
break;
|
|
826
822
|
}
|
|
@@ -863,6 +859,7 @@ export class ConversationChatAreaComponent {
|
|
|
863
859
|
/**
|
|
864
860
|
* Get artifact info for a conversation detail
|
|
865
861
|
* Returns the first artifact if multiple exist (for backward compatibility with message display)
|
|
862
|
+
* Returns LazyArtifactInfo - caller can trigger lazy load if full entities needed
|
|
866
863
|
*/
|
|
867
864
|
getArtifactInfo(conversationDetailId) {
|
|
868
865
|
const artifactList = this.artifactsByDetailId.get(conversationDetailId);
|
|
@@ -871,6 +868,7 @@ export class ConversationChatAreaComponent {
|
|
|
871
868
|
/**
|
|
872
869
|
* Get ALL artifacts for a conversation detail
|
|
873
870
|
* Use this when you need to display all artifacts (e.g., in a list)
|
|
871
|
+
* Returns LazyArtifactInfo array - caller can trigger lazy load if full entities needed
|
|
874
872
|
*/
|
|
875
873
|
getAllArtifactsForDetail(conversationDetailId) {
|
|
876
874
|
return this.artifactsByDetailId.get(conversationDetailId) || [];
|
|
@@ -1053,5 +1051,5 @@ export class ConversationChatAreaComponent {
|
|
|
1053
1051
|
type: ViewChild,
|
|
1054
1052
|
args: ['scrollContainer']
|
|
1055
1053
|
}] }); })();
|
|
1056
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ConversationChatAreaComponent, { className: "ConversationChatAreaComponent", filePath: "src/lib/components/conversation/conversation-chat-area.component.ts", lineNumber:
|
|
1054
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ConversationChatAreaComponent, { className: "ConversationChatAreaComponent", filePath: "src/lib/components/conversation/conversation-chat-area.component.ts", lineNumber: 17 }); })();
|
|
1057
1055
|
//# sourceMappingURL=conversation-chat-area.component.js.map
|