@memberjunction/ng-ai-test-harness
Version:
MemberJunction AI Test Harness - A reusable component for testing AI agents and prompts with beautiful UX
172 lines • 6.5 kB
JavaScript
import { Injectable } from '@angular/core';
import { AITestHarnessWindowComponent } from './ai-test-harness-window.component';
import { Subject } from 'rxjs';
import * as i0 from "@angular/core";
import * as i1 from "@progress/kendo-angular-dialog";
/**
* Service for managing test harness windows for AI Agents and AI Prompts.
* Uses Kendo Window component which provides maximize and close functionality.
*
* Note: Kendo Window created via WindowService does not include a minimize button
* in the titlebar. The window supports maximize/restore and close actions only.
* To add minimize functionality, a custom window component with custom titlebar
* would need to be implemented.
*/
export class TestHarnessWindowService {
constructor(windowService) {
this.windowService = windowService;
this.openWindows = new Map();
this.windowCounter = 0;
}
/**
* Opens the AI Agent Test Harness in a window
*/
openAgentTestHarness(options) {
const data = {
agentId: options.agentId,
agent: options.agent,
title: options.title,
width: options.width || '90vw',
height: options.height || '90vh',
initialDataContext: options.initialDataContext,
initialTemplateData: options.initialTemplateData,
mode: 'agent'
};
return this.openWindow(data, options.viewContainerRef);
}
/**
* Opens the AI Prompt Test Harness in a window
*/
openPromptTestHarness(options) {
console.log('🎯 openPromptTestHarness called with options:', options);
console.log('📌 promptRunId:', options.promptRunId);
const data = {
promptId: options.promptId,
prompt: options.prompt,
title: options.title || 'Test AI Prompt',
width: options.width || '90vw',
height: options.height || '90vh',
initialTemplateVariables: options.initialTemplateVariables,
selectedModelId: options.selectedModelId,
promptRunId: options.promptRunId,
mode: 'prompt'
};
console.log('📦 Final AITestHarnessWindowData:', data);
return this.openWindow(data, options.viewContainerRef);
}
/**
* Opens a test harness window
*/
openWindow(data, viewContainerRef) {
const resultSubject = new Subject();
const windowId = `test-harness-${++this.windowCounter}`;
const windowSettings = {
title: data.title || 'AI Test Harness',
content: AITestHarnessWindowComponent,
width: this.convertToNumber(data.width) || 1200,
height: this.convertToNumber(data.height) || 800,
minWidth: 800,
minHeight: 600,
draggable: true,
resizable: true,
state: 'default',
cssClass: 'test-harness-window-wrapper'
};
if (viewContainerRef) {
windowSettings.appendTo = viewContainerRef;
}
const windowRef = this.windowService.open(windowSettings);
this.openWindows.set(windowId, windowRef);
// Pass data to the component
const componentRef = windowRef.content;
if (componentRef && componentRef.instance) {
componentRef.instance.data = data;
// Handle window close
componentRef.instance.closeWindow.subscribe(() => {
this.closeWindow(windowId);
// Don't complete the observable here, as the window.result will handle it
});
}
// Handle window close via close button
windowRef.result.subscribe({
next: (result) => {
this.openWindows.delete(windowId);
resultSubject.next({
success: true,
result: result
});
resultSubject.complete();
},
error: (error) => {
this.openWindows.delete(windowId);
resultSubject.next({
success: false,
error: error.message || 'Test failed'
});
resultSubject.complete();
}
});
return resultSubject.asObservable();
}
/**
* Closes a specific window
*/
closeWindow(windowId) {
const windowRef = this.openWindows.get(windowId);
if (windowRef) {
try {
windowRef.close();
this.openWindows.delete(windowId);
}
catch (error) {
console.error('Error closing window:', error);
// Force delete from map even if close fails
this.openWindows.delete(windowId);
}
}
}
/**
* Closes all open windows
*/
closeAllWindows() {
this.openWindows.forEach((windowRef, id) => {
windowRef.close();
});
this.openWindows.clear();
}
/**
* Helper method to convert string dimensions to pixel numbers
*/
convertToNumber(value) {
if (!value)
return undefined;
if (typeof value === 'number')
return value;
// Handle percentage values
if (value.endsWith('vw') || value.endsWith('vh')) {
const percentage = parseFloat(value) / 100;
if (value.endsWith('vw')) {
return window.innerWidth * percentage;
}
else {
return window.innerHeight * percentage;
}
}
// Handle pixel values
if (value.endsWith('px')) {
return parseFloat(value);
}
// Try to parse as number
const parsed = parseFloat(value);
return isNaN(parsed) ? undefined : parsed;
}
static { this.ɵfac = function TestHarnessWindowService_Factory(t) { return new (t || TestHarnessWindowService)(i0.ɵɵinject(i1.WindowService)); }; }
static { this.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: TestHarnessWindowService, factory: TestHarnessWindowService.ɵfac, providedIn: 'root' }); }
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TestHarnessWindowService, [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], () => [{ type: i1.WindowService }], null); })();
//# sourceMappingURL=test-harness-window.service.js.map