@memberjunction/ng-dashboards 2.47.0 → 2.49.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/README.md +105 -2
- package/dist/AI/ai-dashboard.component.d.ts +2 -0
- package/dist/AI/ai-dashboard.component.d.ts.map +1 -1
- package/dist/AI/ai-dashboard.component.js +66 -43
- package/dist/AI/ai-dashboard.component.js.map +1 -1
- package/dist/AI/components/agents/agent-configuration.component.js +45 -58
- package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
- package/dist/AI/components/agents/agent-editor.component.d.ts +6 -1
- package/dist/AI/components/agents/agent-editor.component.d.ts.map +1 -1
- package/dist/AI/components/agents/agent-editor.component.js +368 -366
- package/dist/AI/components/agents/agent-editor.component.js.map +1 -1
- package/dist/AI/components/agents/agent-filter-panel.component.js +83 -85
- package/dist/AI/components/agents/agent-filter-panel.component.js.map +1 -1
- package/dist/AI/components/charts/performance-heatmap.component.d.ts +66 -0
- package/dist/AI/components/charts/performance-heatmap.component.d.ts.map +1 -0
- package/dist/AI/components/charts/performance-heatmap.component.js +428 -0
- package/dist/AI/components/charts/performance-heatmap.component.js.map +1 -0
- package/dist/AI/components/charts/time-series-chart.component.d.ts +66 -0
- package/dist/AI/components/charts/time-series-chart.component.d.ts.map +1 -0
- package/dist/AI/components/charts/time-series-chart.component.js +547 -0
- package/dist/AI/components/charts/time-series-chart.component.js.map +1 -0
- package/dist/AI/components/execution-monitoring.component.d.ts +157 -5
- package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
- package/dist/AI/components/execution-monitoring.component.js +2032 -20
- package/dist/AI/components/execution-monitoring.component.js.map +1 -1
- package/dist/AI/components/models/model-management.component.js +211 -237
- package/dist/AI/components/models/model-management.component.js.map +1 -1
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js +208 -226
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js.map +1 -1
- package/dist/AI/components/prompts/prompt-filter-panel.component.js +97 -99
- package/dist/AI/components/prompts/prompt-filter-panel.component.js.map +1 -1
- package/dist/AI/components/prompts/prompt-management.component.js +381 -424
- package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
- package/dist/AI/components/prompts/prompt-version-control.component.js +173 -191
- package/dist/AI/components/prompts/prompt-version-control.component.js.map +1 -1
- package/dist/AI/components/system/system-config-filter-panel.component.js +85 -87
- package/dist/AI/components/system/system-config-filter-panel.component.js.map +1 -1
- package/dist/AI/components/system/system-configuration.component.js +86 -99
- package/dist/AI/components/system/system-configuration.component.js.map +1 -1
- package/dist/AI/components/widgets/kpi-card.component.d.ts +25 -0
- package/dist/AI/components/widgets/kpi-card.component.d.ts.map +1 -0
- package/dist/AI/components/widgets/kpi-card.component.js +163 -0
- package/dist/AI/components/widgets/kpi-card.component.js.map +1 -0
- package/dist/AI/components/widgets/live-execution-widget.component.d.ts +25 -0
- package/dist/AI/components/widgets/live-execution-widget.component.d.ts.map +1 -0
- package/dist/AI/components/widgets/live-execution-widget.component.js +298 -0
- package/dist/AI/components/widgets/live-execution-widget.component.js.map +1 -0
- package/dist/AI/index.d.ts +7 -0
- package/dist/AI/index.d.ts.map +1 -0
- package/dist/AI/index.js +9 -0
- package/dist/AI/index.js.map +1 -0
- package/dist/AI/services/ai-instrumentation.service.d.ts +109 -0
- package/dist/AI/services/ai-instrumentation.service.d.ts.map +1 -0
- package/dist/AI/services/ai-instrumentation.service.js +490 -0
- package/dist/AI/services/ai-instrumentation.service.js.map +1 -0
- package/dist/Actions/actions-management-dashboard.component.js +40 -41
- package/dist/Actions/actions-management-dashboard.component.js.map +1 -1
- package/dist/Actions/components/actions-list-view.component.js +117 -134
- package/dist/Actions/components/actions-list-view.component.js.map +1 -1
- package/dist/Actions/components/actions-overview.component.js +274 -296
- package/dist/Actions/components/actions-overview.component.js.map +1 -1
- package/dist/Actions/components/categories-list-view.component.js +12 -14
- package/dist/Actions/components/categories-list-view.component.js.map +1 -1
- package/dist/Actions/components/code-management.component.js +12 -14
- package/dist/Actions/components/code-management.component.js.map +1 -1
- package/dist/Actions/components/entity-integration.component.js +12 -14
- package/dist/Actions/components/entity-integration.component.js.map +1 -1
- package/dist/Actions/components/execution-monitoring.component.js +238 -256
- package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
- package/dist/Actions/components/executions-list-view.component.js +12 -14
- package/dist/Actions/components/executions-list-view.component.js.map +1 -1
- package/dist/Actions/components/scheduled-actions.component.js +12 -14
- package/dist/Actions/components/scheduled-actions.component.js.map +1 -1
- package/dist/Actions/components/security-permissions.component.js +12 -14
- package/dist/Actions/components/security-permissions.component.js.map +1 -1
- package/dist/EntityAdmin/components/entity-details.component.js +105 -107
- package/dist/EntityAdmin/components/entity-details.component.js.map +1 -1
- package/dist/EntityAdmin/components/entity-filter-panel.component.js +100 -102
- package/dist/EntityAdmin/components/entity-filter-panel.component.js.map +1 -1
- package/dist/EntityAdmin/components/erd-composite.component.js +84 -100
- package/dist/EntityAdmin/components/erd-composite.component.js.map +1 -1
- package/dist/EntityAdmin/components/erd-diagram.component.js +50 -50
- package/dist/EntityAdmin/components/erd-diagram.component.js.map +1 -1
- package/dist/EntityAdmin/entity-admin-dashboard.component.js +45 -49
- package/dist/EntityAdmin/entity-admin-dashboard.component.js.map +1 -1
- package/dist/generic/base-dashboard.js +28 -40
- package/dist/generic/base-dashboard.js.map +1 -1
- package/dist/module.d.ts +16 -12
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +36 -15
- package/dist/module.js.map +1 -1
- package/package.json +6 -6
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
11
2
|
import { RunView, Metadata, LogError, LogStatus } from '@memberjunction/core';
|
|
12
3
|
import { Subject, BehaviorSubject } from 'rxjs';
|
|
@@ -400,41 +391,42 @@ function ModelPromptPriorityMatrixComponent_Conditional_35_Template(rf, ctx) { i
|
|
|
400
391
|
i0.ɵɵtextInterpolate1(" ", ctx_r1.error, " ");
|
|
401
392
|
} }
|
|
402
393
|
export class ModelPromptPriorityMatrixComponent {
|
|
394
|
+
notificationService;
|
|
395
|
+
selectedPrompts = [];
|
|
396
|
+
selectedModels = [];
|
|
397
|
+
readonly = false;
|
|
398
|
+
associationsChange = new EventEmitter();
|
|
399
|
+
stateChange = new EventEmitter();
|
|
400
|
+
promptSelected = new EventEmitter();
|
|
401
|
+
// Data
|
|
402
|
+
prompts = [];
|
|
403
|
+
models = [];
|
|
404
|
+
associations = [];
|
|
405
|
+
matrix = [];
|
|
406
|
+
// UI State
|
|
407
|
+
isLoading = false;
|
|
408
|
+
loadingMessage = '';
|
|
409
|
+
error = null;
|
|
410
|
+
viewMode = 'matrix';
|
|
411
|
+
sortBy = 'priority';
|
|
412
|
+
sortDirection = 'asc';
|
|
413
|
+
showInactiveAssociations = false;
|
|
414
|
+
// Selection and editing
|
|
415
|
+
selectedCells = new Set();
|
|
416
|
+
editingCell = null;
|
|
417
|
+
bulkEditMode = false;
|
|
418
|
+
bulkEditPriority = 1;
|
|
419
|
+
bulkEditStatus = 'Active';
|
|
420
|
+
// Filtering
|
|
421
|
+
promptFilter$ = new BehaviorSubject('');
|
|
422
|
+
modelFilter$ = new BehaviorSubject('');
|
|
423
|
+
statusFilter$ = new BehaviorSubject('all');
|
|
424
|
+
// Performance metrics
|
|
425
|
+
performanceData = {};
|
|
426
|
+
showPerformanceOverlay = false;
|
|
427
|
+
destroy$ = new Subject();
|
|
403
428
|
constructor(notificationService) {
|
|
404
429
|
this.notificationService = notificationService;
|
|
405
|
-
this.selectedPrompts = [];
|
|
406
|
-
this.selectedModels = [];
|
|
407
|
-
this.readonly = false;
|
|
408
|
-
this.associationsChange = new EventEmitter();
|
|
409
|
-
this.stateChange = new EventEmitter();
|
|
410
|
-
this.promptSelected = new EventEmitter();
|
|
411
|
-
// Data
|
|
412
|
-
this.prompts = [];
|
|
413
|
-
this.models = [];
|
|
414
|
-
this.associations = [];
|
|
415
|
-
this.matrix = [];
|
|
416
|
-
// UI State
|
|
417
|
-
this.isLoading = false;
|
|
418
|
-
this.loadingMessage = '';
|
|
419
|
-
this.error = null;
|
|
420
|
-
this.viewMode = 'matrix';
|
|
421
|
-
this.sortBy = 'priority';
|
|
422
|
-
this.sortDirection = 'asc';
|
|
423
|
-
this.showInactiveAssociations = false;
|
|
424
|
-
// Selection and editing
|
|
425
|
-
this.selectedCells = new Set();
|
|
426
|
-
this.editingCell = null;
|
|
427
|
-
this.bulkEditMode = false;
|
|
428
|
-
this.bulkEditPriority = 1;
|
|
429
|
-
this.bulkEditStatus = 'Active';
|
|
430
|
-
// Filtering
|
|
431
|
-
this.promptFilter$ = new BehaviorSubject('');
|
|
432
|
-
this.modelFilter$ = new BehaviorSubject('');
|
|
433
|
-
this.statusFilter$ = new BehaviorSubject('all');
|
|
434
|
-
// Performance metrics
|
|
435
|
-
this.performanceData = {};
|
|
436
|
-
this.showPerformanceOverlay = false;
|
|
437
|
-
this.destroy$ = new Subject();
|
|
438
430
|
}
|
|
439
431
|
ngOnInit() {
|
|
440
432
|
this.loadData();
|
|
@@ -443,88 +435,80 @@ export class ModelPromptPriorityMatrixComponent {
|
|
|
443
435
|
this.destroy$.next();
|
|
444
436
|
this.destroy$.complete();
|
|
445
437
|
}
|
|
446
|
-
loadData() {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
}
|
|
470
|
-
});
|
|
438
|
+
async loadData() {
|
|
439
|
+
try {
|
|
440
|
+
this.isLoading = true;
|
|
441
|
+
this.error = null;
|
|
442
|
+
this.loadingMessage = 'Loading prompts, models, and associations...';
|
|
443
|
+
const [prompts, models, associations] = await Promise.all([
|
|
444
|
+
this.loadPrompts(),
|
|
445
|
+
this.loadModels(),
|
|
446
|
+
this.loadAssociations()
|
|
447
|
+
]);
|
|
448
|
+
this.prompts = this.selectedPrompts.length > 0 ? this.selectedPrompts : prompts;
|
|
449
|
+
this.models = this.selectedModels.length > 0 ? this.selectedModels : models;
|
|
450
|
+
this.buildAssociations(associations);
|
|
451
|
+
this.buildMatrix();
|
|
452
|
+
LogStatus('Model-prompt priority matrix loaded successfully');
|
|
453
|
+
}
|
|
454
|
+
catch (error) {
|
|
455
|
+
this.error = 'Failed to load matrix data. Please try again.';
|
|
456
|
+
LogError('Error loading matrix data', undefined, error);
|
|
457
|
+
}
|
|
458
|
+
finally {
|
|
459
|
+
this.isLoading = false;
|
|
460
|
+
}
|
|
471
461
|
}
|
|
472
|
-
loadPrompts() {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
MaxRows: 500
|
|
482
|
-
});
|
|
483
|
-
if (result && result.Success && result.Results) {
|
|
484
|
-
return result.Results;
|
|
485
|
-
}
|
|
486
|
-
else {
|
|
487
|
-
throw new Error('Failed to load AI prompts');
|
|
488
|
-
}
|
|
462
|
+
async loadPrompts() {
|
|
463
|
+
const rv = new RunView();
|
|
464
|
+
const result = await rv.RunView({
|
|
465
|
+
EntityName: 'AI Prompts',
|
|
466
|
+
ExtraFilter: "Status = 'Active'",
|
|
467
|
+
OrderBy: 'Name',
|
|
468
|
+
UserSearchString: '',
|
|
469
|
+
IgnoreMaxRows: false,
|
|
470
|
+
MaxRows: 500
|
|
489
471
|
});
|
|
472
|
+
if (result && result.Success && result.Results) {
|
|
473
|
+
return result.Results;
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
throw new Error('Failed to load AI prompts');
|
|
477
|
+
}
|
|
490
478
|
}
|
|
491
|
-
loadModels() {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
MaxRows: 200
|
|
501
|
-
});
|
|
502
|
-
if (result && result.Success && result.Results) {
|
|
503
|
-
return result.Results;
|
|
504
|
-
}
|
|
505
|
-
else {
|
|
506
|
-
throw new Error('Failed to load AI models');
|
|
507
|
-
}
|
|
479
|
+
async loadModels() {
|
|
480
|
+
const rv = new RunView();
|
|
481
|
+
const result = await rv.RunView({
|
|
482
|
+
EntityName: 'AI Models',
|
|
483
|
+
ExtraFilter: "IsActive = 1",
|
|
484
|
+
OrderBy: 'Name',
|
|
485
|
+
UserSearchString: '',
|
|
486
|
+
IgnoreMaxRows: false,
|
|
487
|
+
MaxRows: 200
|
|
508
488
|
});
|
|
489
|
+
if (result && result.Success && result.Results) {
|
|
490
|
+
return result.Results;
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
throw new Error('Failed to load AI models');
|
|
494
|
+
}
|
|
509
495
|
}
|
|
510
|
-
loadAssociations() {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
MaxRows: 2000
|
|
520
|
-
});
|
|
521
|
-
if (result && result.Success && result.Results) {
|
|
522
|
-
return result.Results;
|
|
523
|
-
}
|
|
524
|
-
else {
|
|
525
|
-
throw new Error('Failed to load prompt-model associations');
|
|
526
|
-
}
|
|
496
|
+
async loadAssociations() {
|
|
497
|
+
const rv = new RunView();
|
|
498
|
+
const result = await rv.RunView({
|
|
499
|
+
EntityName: 'MJ: AI Prompt Models',
|
|
500
|
+
ExtraFilter: '',
|
|
501
|
+
OrderBy: 'Priority',
|
|
502
|
+
UserSearchString: '',
|
|
503
|
+
IgnoreMaxRows: false,
|
|
504
|
+
MaxRows: 2000
|
|
527
505
|
});
|
|
506
|
+
if (result && result.Success && result.Results) {
|
|
507
|
+
return result.Results;
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
throw new Error('Failed to load prompt-model associations');
|
|
511
|
+
}
|
|
528
512
|
}
|
|
529
513
|
buildAssociations(dbAssociations) {
|
|
530
514
|
this.associations = [];
|
|
@@ -735,54 +719,52 @@ export class ModelPromptPriorityMatrixComponent {
|
|
|
735
719
|
});
|
|
736
720
|
this.selectedCells.clear();
|
|
737
721
|
}
|
|
738
|
-
saveChanges() {
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
yield entity.Load(association.association.ID);
|
|
754
|
-
}
|
|
755
|
-
else {
|
|
756
|
-
// Create new
|
|
757
|
-
entity = yield md.GetEntityObject('MJ: AI Prompt Models', md.CurrentUser);
|
|
758
|
-
}
|
|
759
|
-
entity.PromptID = association.promptId;
|
|
760
|
-
entity.ModelID = association.modelId;
|
|
761
|
-
entity.Priority = association.priority;
|
|
762
|
-
entity.Status = association.status;
|
|
763
|
-
savePromises.push(entity.Save());
|
|
722
|
+
async saveChanges() {
|
|
723
|
+
try {
|
|
724
|
+
this.isLoading = true;
|
|
725
|
+
this.loadingMessage = 'Saving associations...';
|
|
726
|
+
const md = new Metadata();
|
|
727
|
+
if (!md)
|
|
728
|
+
throw new Error('Metadata provider not available');
|
|
729
|
+
const savePromises = [];
|
|
730
|
+
for (const association of this.associations) {
|
|
731
|
+
if (association.isNew || association.isModified) {
|
|
732
|
+
let entity;
|
|
733
|
+
if (association.association) {
|
|
734
|
+
// Update existing
|
|
735
|
+
entity = await md.GetEntityObject('MJ: AI Prompt Models', md.CurrentUser);
|
|
736
|
+
await entity.Load(association.association.ID);
|
|
764
737
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
this.notificationService.CreateSimpleNotification(`${failures} association(s) failed to save`, 'warning', 4000);
|
|
738
|
+
else {
|
|
739
|
+
// Create new
|
|
740
|
+
entity = await md.GetEntityObject('MJ: AI Prompt Models', md.CurrentUser);
|
|
741
|
+
}
|
|
742
|
+
entity.PromptID = association.promptId;
|
|
743
|
+
entity.ModelID = association.modelId;
|
|
744
|
+
entity.Priority = association.priority;
|
|
745
|
+
entity.Status = association.status;
|
|
746
|
+
savePromises.push(entity.Save());
|
|
775
747
|
}
|
|
776
748
|
}
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
this.notificationService.CreateSimpleNotification('
|
|
749
|
+
const results = await Promise.all(savePromises);
|
|
750
|
+
const failures = results.filter(r => !r).length;
|
|
751
|
+
if (failures === 0) {
|
|
752
|
+
this.notificationService.CreateSimpleNotification('All associations saved successfully', 'success', 3000);
|
|
753
|
+
// Reload data to get fresh state
|
|
754
|
+
await this.loadData();
|
|
781
755
|
}
|
|
782
|
-
|
|
783
|
-
this.
|
|
756
|
+
else {
|
|
757
|
+
this.notificationService.CreateSimpleNotification(`${failures} association(s) failed to save`, 'warning', 4000);
|
|
784
758
|
}
|
|
785
|
-
}
|
|
759
|
+
}
|
|
760
|
+
catch (error) {
|
|
761
|
+
this.error = 'Failed to save associations. Please try again.';
|
|
762
|
+
LogError('Error saving associations', undefined, error);
|
|
763
|
+
this.notificationService.CreateSimpleNotification('Failed to save associations', 'error', 4000);
|
|
764
|
+
}
|
|
765
|
+
finally {
|
|
766
|
+
this.isLoading = false;
|
|
767
|
+
}
|
|
786
768
|
}
|
|
787
769
|
hasUnsavedChanges() {
|
|
788
770
|
return this.associations.some(a => a.isNew || a.isModified);
|
|
@@ -868,72 +850,72 @@ export class ModelPromptPriorityMatrixComponent {
|
|
|
868
850
|
selectPrompt(prompt) {
|
|
869
851
|
this.promptSelected.emit(prompt);
|
|
870
852
|
}
|
|
853
|
+
static ɵfac = function ModelPromptPriorityMatrixComponent_Factory(t) { return new (t || ModelPromptPriorityMatrixComponent)(i0.ɵɵdirectiveInject(i1.MJNotificationService)); };
|
|
854
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ModelPromptPriorityMatrixComponent, selectors: [["app-model-prompt-priority-matrix"]], inputs: { selectedPrompts: "selectedPrompts", selectedModels: "selectedModels", readonly: "readonly" }, outputs: { associationsChange: "associationsChange", stateChange: "stateChange", promptSelected: "promptSelected" }, decls: 36, vars: 10, consts: [[1, "model-prompt-priority-matrix"], [1, "matrix-toolbar"], [1, "toolbar-section"], [1, "toolbar-title"], [1, "fa-solid", "fa-table-cells"], [1, "view-mode-toggle"], ["role", "group", 1, "btn-group"], ["type", "radio", "name", "viewMode", "id", "matrixView", "value", "matrix", 1, "btn-check", 3, "ngModelChange", "ngModel"], ["for", "matrixView", 1, "btn", "btn-outline-primary", "btn-sm"], ["type", "radio", "name", "viewMode", "id", "listView", "value", "list", 1, "btn-check", 3, "ngModelChange", "ngModel"], ["for", "listView", 1, "btn", "btn-outline-primary", "btn-sm"], [1, "fa-solid", "fa-list"], [1, "matrix-stats"], [1, "stat-item"], [1, "fa-solid", "fa-link", "text-primary"], [1, "fa-solid", "fa-star", "text-warning"], [1, "stat-item", "text-warning"], [1, "bulk-actions"], [1, "action-buttons"], ["type", "button", "title", "Export matrix", 1, "btn", "btn-sm", "btn-outline-info", 3, "click"], [1, "fa-solid", "fa-download"], [1, "bulk-edit-panel"], [1, "loading-container"], [1, "error-container"], [1, "fa-solid", "fa-exclamation-triangle"], ["type", "button", "title", "Bulk edit selected cells", 1, "btn", "btn-sm", "btn-outline-primary", 3, "click"], [1, "fa-solid", "fa-edit"], ["type", "button", "title", "Remove selected associations", 1, "btn", "btn-sm", "btn-outline-danger", 3, "click"], [1, "fa-solid", "fa-trash"], ["type", "button", "title", "Discard changes", 1, "btn", "btn-sm", "btn-outline-secondary", 3, "click"], [1, "fa-solid", "fa-undo"], ["type", "button", "title", "Save changes", 1, "btn", "btn-sm", "btn-success", 3, "click", "disabled"], [1, "fa-solid", "fa-save"], [1, "bulk-edit-controls"], [1, "form-group"], ["for", "bulkPriority", 1, "form-label"], ["type", "number", "id", "bulkPriority", "min", "1", "max", "10", 1, "form-control", "form-control-sm", 3, "ngModelChange", "ngModel"], ["for", "bulkStatus", 1, "form-label"], ["id", "bulkStatus", 1, "form-select", "form-select-sm", 3, "ngModelChange", "ngModel"], ["value", "Active"], ["value", "Inactive"], ["type", "button", "title", "Apply changes to selected cells", 1, "btn", "btn-sm", "btn-primary", 3, "click"], [1, "fa-solid", "fa-check"], ["type", "button", "title", "Cancel bulk edit", 1, "btn", "btn-sm", "btn-outline-secondary", 3, "click"], [1, "fa-solid", "fa-times"], [1, "bulk-edit-info"], [1, "text-muted"], [1, "loading-content"], ["role", "status", 1, "spinner-border", "text-primary"], [1, "visually-hidden"], [1, "loading-message"], [1, "matrix-container"], [1, "list-container"], [1, "matrix-scroll"], [1, "matrix-table"], [1, "prompt-header"], [1, "model-header", 3, "title"], [1, "matrix-row"], [1, "header-content"], [1, "header-name"], [1, "header-stats"], [1, "prompt-header", 3, "click", "title"], [3, "class", "title"], [3, "click", "dblclick", "title"], [1, "cell-content"], [1, "cell-content", "empty"], [1, "status-indicator", "inactive"], [1, "change-indicator", "new"], [1, "change-indicator", "modified"], [1, "performance-overlay"], [1, "fa-solid", "fa-ban"], [1, "fa-solid", "fa-plus"], [1, "empty-cell-indicator"], [1, "blocked-cell-indicator"], [1, "list-header"], [1, "list-controls"], [1, "sort-controls"], [1, "form-label"], [1, "form-select", "form-select-sm", 3, "ngModelChange", "ngModel"], ["value", "prompt"], ["value", "model"], ["value", "priority"], ["type", "button", 1, "btn", "btn-sm", "btn-outline-secondary", 3, "click", "title"], [1, "fa-solid"], [1, "filter-controls"], [1, "form-check", "form-switch"], ["type", "checkbox", "id", "showInactive", 1, "form-check-input", 3, "ngModelChange", "ngModel"], ["for", "showInactive", 1, "form-check-label"], [1, "associations-list"], [1, "no-associations-message"], [1, "association-item", 3, "inactive", "new", "modified"], [1, "association-item"], [1, "association-header"], [1, "association-names"], [1, "prompt-name"], [1, "fa-solid", "fa-arrow-right", "text-muted"], [1, "model-name"], [1, "association-actions"], [1, "association-details"], [1, "detail-item"], [1, "detail-label"], [1, "status-badge"], ["type", "button", "title", "Edit association", 1, "btn", "btn-sm", "btn-outline-primary"], ["type", "button", "title", "Remove association", 1, "btn", "btn-sm", "btn-outline-danger", 3, "click"], [1, "change-badge", "new"], [1, "change-badge", "modified"], [1, "fa-solid", "fa-info-circle", "text-muted"], [1, "text-muted", "mb-0"], ["role", "alert", 1, "alert", "alert-danger"], ["type", "button", 1, "btn", "btn-sm", "btn-outline-danger", "ms-2", 3, "click"], [1, "fa-solid", "fa-refresh"]], template: function ModelPromptPriorityMatrixComponent_Template(rf, ctx) { if (rf & 1) {
|
|
855
|
+
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "h5", 3);
|
|
856
|
+
i0.ɵɵelement(4, "i", 4);
|
|
857
|
+
i0.ɵɵtext(5, " Model-Prompt Priority Matrix ");
|
|
858
|
+
i0.ɵɵelementEnd();
|
|
859
|
+
i0.ɵɵelementStart(6, "div", 5)(7, "div", 6)(8, "input", 7);
|
|
860
|
+
i0.ɵɵtwoWayListener("ngModelChange", function ModelPromptPriorityMatrixComponent_Template_input_ngModelChange_8_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.viewMode, $event) || (ctx.viewMode = $event); return $event; });
|
|
861
|
+
i0.ɵɵlistener("ngModelChange", function ModelPromptPriorityMatrixComponent_Template_input_ngModelChange_8_listener($event) { return ctx.onViewModeChange($event); });
|
|
862
|
+
i0.ɵɵelementEnd();
|
|
863
|
+
i0.ɵɵelementStart(9, "label", 8);
|
|
864
|
+
i0.ɵɵelement(10, "i", 4);
|
|
865
|
+
i0.ɵɵtext(11, " Matrix ");
|
|
866
|
+
i0.ɵɵelementEnd();
|
|
867
|
+
i0.ɵɵelementStart(12, "input", 9);
|
|
868
|
+
i0.ɵɵtwoWayListener("ngModelChange", function ModelPromptPriorityMatrixComponent_Template_input_ngModelChange_12_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.viewMode, $event) || (ctx.viewMode = $event); return $event; });
|
|
869
|
+
i0.ɵɵlistener("ngModelChange", function ModelPromptPriorityMatrixComponent_Template_input_ngModelChange_12_listener($event) { return ctx.onViewModeChange($event); });
|
|
870
|
+
i0.ɵɵelementEnd();
|
|
871
|
+
i0.ɵɵelementStart(13, "label", 10);
|
|
872
|
+
i0.ɵɵelement(14, "i", 11);
|
|
873
|
+
i0.ɵɵtext(15, " List ");
|
|
874
|
+
i0.ɵɵelementEnd()()()();
|
|
875
|
+
i0.ɵɵelementStart(16, "div", 2)(17, "div", 12)(18, "span", 13);
|
|
876
|
+
i0.ɵɵelement(19, "i", 14);
|
|
877
|
+
i0.ɵɵtext(20);
|
|
878
|
+
i0.ɵɵelementEnd();
|
|
879
|
+
i0.ɵɵelementStart(21, "span", 13);
|
|
880
|
+
i0.ɵɵelement(22, "i", 15);
|
|
881
|
+
i0.ɵɵtext(23);
|
|
882
|
+
i0.ɵɵelementEnd();
|
|
883
|
+
i0.ɵɵtemplate(24, ModelPromptPriorityMatrixComponent_Conditional_24_Template, 3, 0, "span", 16);
|
|
884
|
+
i0.ɵɵelementEnd()();
|
|
885
|
+
i0.ɵɵelementStart(25, "div", 2);
|
|
886
|
+
i0.ɵɵtemplate(26, ModelPromptPriorityMatrixComponent_Conditional_26_Template, 7, 3, "div", 17);
|
|
887
|
+
i0.ɵɵelementStart(27, "div", 18);
|
|
888
|
+
i0.ɵɵtemplate(28, ModelPromptPriorityMatrixComponent_Conditional_28_Template, 6, 1);
|
|
889
|
+
i0.ɵɵelementStart(29, "button", 19);
|
|
890
|
+
i0.ɵɵlistener("click", function ModelPromptPriorityMatrixComponent_Template_button_click_29_listener() { return ctx.exportMatrix(); });
|
|
891
|
+
i0.ɵɵelement(30, "i", 20);
|
|
892
|
+
i0.ɵɵtext(31, " Export ");
|
|
893
|
+
i0.ɵɵelementEnd()()()();
|
|
894
|
+
i0.ɵɵtemplate(32, ModelPromptPriorityMatrixComponent_Conditional_32_Template, 24, 3, "div", 21)(33, ModelPromptPriorityMatrixComponent_Conditional_33_Template, 7, 1, "div", 22)(34, ModelPromptPriorityMatrixComponent_Conditional_34_Template, 2, 2)(35, ModelPromptPriorityMatrixComponent_Conditional_35_Template, 7, 1, "div", 23);
|
|
895
|
+
i0.ɵɵelementEnd();
|
|
896
|
+
} if (rf & 2) {
|
|
897
|
+
i0.ɵɵadvance(8);
|
|
898
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx.viewMode);
|
|
899
|
+
i0.ɵɵadvance(4);
|
|
900
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx.viewMode);
|
|
901
|
+
i0.ɵɵadvance(8);
|
|
902
|
+
i0.ɵɵtextInterpolate1(" ", ctx.getAssociationCount(), " associations ");
|
|
903
|
+
i0.ɵɵadvance(3);
|
|
904
|
+
i0.ɵɵtextInterpolate1(" ", ctx.getAveragePriority(), " avg priority ");
|
|
905
|
+
i0.ɵɵadvance();
|
|
906
|
+
i0.ɵɵconditional(ctx.hasUnsavedChanges() ? 24 : -1);
|
|
907
|
+
i0.ɵɵadvance(2);
|
|
908
|
+
i0.ɵɵconditional(ctx.selectedCells.size > 0 ? 26 : -1);
|
|
909
|
+
i0.ɵɵadvance(2);
|
|
910
|
+
i0.ɵɵconditional(ctx.hasUnsavedChanges() ? 28 : -1);
|
|
911
|
+
i0.ɵɵadvance(4);
|
|
912
|
+
i0.ɵɵconditional(ctx.bulkEditMode && ctx.selectedCells.size > 0 ? 32 : -1);
|
|
913
|
+
i0.ɵɵadvance();
|
|
914
|
+
i0.ɵɵconditional(ctx.isLoading ? 33 : 34);
|
|
915
|
+
i0.ɵɵadvance(2);
|
|
916
|
+
i0.ɵɵconditional(ctx.error ? 35 : -1);
|
|
917
|
+
} }, dependencies: [i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.NumberValueAccessor, i2.CheckboxControlValueAccessor, i2.SelectControlValueAccessor, i2.RadioControlValueAccessor, i2.NgControlStatus, i2.MinValidator, i2.MaxValidator, i2.NgModel], styles: [".model-prompt-priority-matrix[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: #f8f9fa;\n\n .matrix-toolbar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1rem;\n background: white;\n border-bottom: 1px solid #dee2e6;\n flex-shrink: 0;\n gap: 1rem;\n flex-wrap: wrap;\n\n .toolbar-section {\n display: flex;\n align-items: center;\n gap: 1rem;\n\n .toolbar-title {\n margin: 0;\n color: #495057;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-weight: 600;\n\n i {\n color: #0d6efd;\n }\n }\n\n .matrix-stats {\n display: flex;\n gap: 1rem;\n\n .stat-item {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n font-size: 0.875rem;\n color: #6c757d;\n\n i {\n font-size: 1rem;\n }\n }\n }\n\n .bulk-actions,\n .action-buttons {\n display: flex;\n gap: 0.5rem;\n\n .btn {\n font-size: 0.875rem;\n }\n }\n }\n }\n\n .bulk-edit-panel {\n padding: 1rem;\n background: #fff3cd;\n border-bottom: 1px solid #ffeaa7;\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-wrap: wrap;\n gap: 1rem;\n\n .bulk-edit-controls {\n display: flex;\n align-items: center;\n gap: 1rem;\n\n .form-group {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n\n .form-label {\n margin: 0;\n font-size: 0.875rem;\n font-weight: 500;\n white-space: nowrap;\n }\n\n .form-control,\n .form-select {\n min-width: 100px;\n }\n }\n }\n\n .bulk-edit-info {\n font-size: 0.875rem;\n color: #856404;\n }\n }\n\n .loading-container {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n\n .loading-content {\n text-align: center;\n \n .loading-message {\n margin-top: 1rem;\n color: #6c757d;\n }\n }\n }\n\n .matrix-container {\n flex: 1;\n overflow: hidden;\n\n .matrix-scroll {\n height: 100%;\n overflow: auto;\n padding: 1rem;\n\n .matrix-table {\n border-collapse: separate;\n border-spacing: 2px;\n background: white;\n border-radius: 0.5rem;\n overflow: hidden;\n\n .prompt-header,\n .model-header {\n background: #f8f9fa;\n border: 1px solid #dee2e6;\n padding: 0.75rem;\n font-weight: 600;\n text-align: center;\n position: sticky;\n top: 0;\n z-index: 10;\n\n .header-content {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n\n .header-name {\n font-size: 0.875rem;\n font-weight: 600;\n }\n\n .header-stats {\n font-size: 0.75rem;\n color: #6c757d;\n }\n }\n }\n\n .prompt-header {\n min-width: 200px;\n position: sticky;\n left: 0;\n z-index: 11;\n }\n\n .matrix-cell {\n width: 80px;\n height: 60px;\n border: 2px solid #e9ecef;\n text-align: center;\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n\n &:hover {\n border-color: #007bff;\n transform: scale(1.05);\n }\n\n &.selected {\n border-color: #007bff;\n background: rgba(0, 123, 255, 0.1);\n }\n\n &.editing {\n border-color: #28a745;\n background: rgba(40, 167, 69, 0.1);\n }\n\n &.no-association {\n background: #f8f9fa;\n border-style: dashed;\n\n .empty-cell-indicator {\n color: #6c757d;\n font-size: 1.5rem;\n opacity: 0.5;\n }\n }\n\n &.cannot-assign {\n background: #f5f5f5;\n cursor: not-allowed;\n opacity: 0.5;\n\n .blocked-cell-indicator {\n color: #dc3545;\n font-size: 1.25rem;\n }\n }\n\n &.has-association {\n background: white;\n\n &.priority-1 { border-color: #28a745; }\n &.priority-2 { border-color: #20c997; }\n &.priority-3 { border-color: #ffc107; }\n &.priority-4 { border-color: #fd7e14; }\n &.priority-5 { border-color: #dc3545; }\n\n &.inactive {\n opacity: 0.6;\n background: #f8f9fa;\n }\n\n &.new {\n box-shadow: 0 0 0 2px #28a745;\n }\n\n &.modified {\n box-shadow: 0 0 0 2px #ffc107;\n }\n }\n\n .cell-content {\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n height: 100%;\n gap: 0.25rem;\n\n .priority-badge {\n background: #007bff;\n color: white;\n border-radius: 50%;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.75rem;\n font-weight: 600;\n\n &.priority-1 { background: #28a745; }\n &.priority-2 { background: #20c997; }\n &.priority-3 { background: #ffc107; color: #212529; }\n &.priority-4 { background: #fd7e14; }\n &.priority-5 { background: #dc3545; }\n }\n\n .status-indicator {\n font-size: 0.75rem;\n\n &.inactive {\n color: #dc3545;\n }\n }\n\n .change-indicator {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 12px;\n height: 12px;\n border-radius: 50%;\n font-size: 0.625rem;\n display: flex;\n align-items: center;\n justify-content: center;\n\n &.new {\n background: #28a745;\n color: white;\n }\n\n &.modified {\n background: #ffc107;\n color: #212529;\n }\n }\n\n .performance-overlay {\n position: absolute;\n bottom: 2px;\n left: 2px;\n right: 2px;\n background: rgba(0, 0, 0, 0.8);\n color: white;\n border-radius: 0.25rem;\n padding: 0.125rem;\n font-size: 0.625rem;\n }\n }\n }\n }\n }\n }\n\n .list-container {\n flex: 1;\n padding: 1rem;\n overflow-y: auto;\n\n .list-header {\n margin-bottom: 1.5rem;\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 0.5rem;\n padding: 1rem;\n\n .list-controls {\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-wrap: wrap;\n gap: 1rem;\n\n .sort-controls,\n .filter-controls {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n\n .form-label {\n margin: 0;\n font-size: 0.875rem;\n color: #6c757d;\n white-space: nowrap;\n }\n\n .form-select {\n min-width: 120px;\n }\n\n .form-check {\n margin: 0;\n }\n }\n }\n }\n\n .associations-list {\n .association-item {\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 0.5rem;\n padding: 1rem;\n margin-bottom: 1rem;\n transition: all 0.2s ease;\n\n &:hover {\n box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);\n transform: translateY(-1px);\n }\n\n &.inactive {\n opacity: 0.7;\n background: #f8f9fa;\n }\n\n &.new {\n border-color: #28a745;\n border-left-width: 4px;\n }\n\n &.modified {\n border-color: #ffc107;\n border-left-width: 4px;\n }\n\n .association-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 0.75rem;\n\n .association-names {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n\n .prompt-name,\n .model-name {\n color: #495057;\n font-weight: 500;\n }\n\n i {\n color: #6c757d;\n }\n }\n\n .association-actions {\n display: flex;\n gap: 0.5rem;\n\n .btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.75rem;\n }\n }\n }\n\n .association-details {\n display: flex;\n align-items: center;\n gap: 1rem;\n flex-wrap: wrap;\n\n .detail-item {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n\n .detail-label {\n font-size: 0.875rem;\n color: #6c757d;\n }\n\n .priority-badge {\n background: #007bff;\n color: white;\n padding: 0.25rem 0.5rem;\n border-radius: 0.25rem;\n font-size: 0.75rem;\n font-weight: 600;\n\n &.priority-1 { background: #28a745; }\n &.priority-2 { background: #20c997; }\n &.priority-3 { background: #ffc107; color: #212529; }\n &.priority-4 { background: #fd7e14; }\n &.priority-5 { background: #dc3545; }\n }\n\n .status-badge {\n padding: 0.25rem 0.5rem;\n border-radius: 0.25rem;\n font-size: 0.75rem;\n font-weight: 500;\n\n &.badge-success {\n background: #d4edda;\n color: #155724;\n }\n\n &.badge-secondary {\n background: #e2e3e5;\n color: #383d41;\n }\n }\n\n .change-badge {\n padding: 0.25rem 0.5rem;\n border-radius: 0.25rem;\n font-size: 0.75rem;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 0.25rem;\n\n &.new {\n background: #d4edda;\n color: #155724;\n }\n\n &.modified {\n background: #fff3cd;\n color: #856404;\n }\n }\n }\n }\n }\n\n .no-associations-message {\n text-align: center;\n padding: 3rem 1rem;\n color: #6c757d;\n\n i {\n font-size: 3rem;\n margin-bottom: 1rem;\n display: block;\n opacity: 0.5;\n }\n\n p {\n margin: 0;\n font-size: 1rem;\n line-height: 1.5;\n }\n }\n }\n }\n\n .error-container {\n padding: 1rem;\n\n .alert {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n }\n }\n}\n\n//[_ngcontent-%COMP%] Responsive[_ngcontent-%COMP%] adjustments\n@media[_ngcontent-%COMP%] (max-width[_ngcontent-%COMP%]: 1200px)[_ngcontent-%COMP%] {\n .model-prompt-priority-matrix {\n .matrix-toolbar {\n .toolbar-section {\n min-width: 100%;\n justify-content: space-between;\n }\n }\n\n .matrix-container {\n .matrix-scroll {\n .matrix-table {\n .matrix-cell {\n width: 60px;\n height: 50px;\n }\n }\n }\n }\n }\n}\n\n@media (max-width: 768px) {\n .model-prompt-priority-matrix[_ngcontent-%COMP%] {\n .matrix-toolbar {\n padding: 0.75rem;\n \n .toolbar-section {\n flex-wrap: wrap;\n gap: 0.5rem;\n }\n }\n\n .bulk-edit-panel {\n padding: 0.75rem;\n\n .bulk-edit-controls {\n flex-direction: column;\n align-items: stretch;\n gap: 0.75rem;\n }\n }\n\n .matrix-container {\n .matrix-scroll {\n padding: 0.75rem;\n\n .matrix-table {\n .matrix-cell {\n width: 50px;\n height: 40px;\n }\n }\n }\n }\n\n .list-container {\n padding: 0.75rem;\n\n .list-header {\n .list-controls {\n flex-direction: column;\n align-items: stretch;\n }\n }\n\n .associations-list {\n .association-item {\n .association-header {\n flex-direction: column;\n align-items: flex-start;\n gap: 0.75rem;\n }\n\n .association-details {\n flex-direction: column;\n align-items: flex-start;\n }\n }\n }\n }\n }\n}"] });
|
|
871
918
|
}
|
|
872
|
-
ModelPromptPriorityMatrixComponent.ɵfac = function ModelPromptPriorityMatrixComponent_Factory(t) { return new (t || ModelPromptPriorityMatrixComponent)(i0.ɵɵdirectiveInject(i1.MJNotificationService)); };
|
|
873
|
-
ModelPromptPriorityMatrixComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ModelPromptPriorityMatrixComponent, selectors: [["app-model-prompt-priority-matrix"]], inputs: { selectedPrompts: "selectedPrompts", selectedModels: "selectedModels", readonly: "readonly" }, outputs: { associationsChange: "associationsChange", stateChange: "stateChange", promptSelected: "promptSelected" }, decls: 36, vars: 10, consts: [[1, "model-prompt-priority-matrix"], [1, "matrix-toolbar"], [1, "toolbar-section"], [1, "toolbar-title"], [1, "fa-solid", "fa-table-cells"], [1, "view-mode-toggle"], ["role", "group", 1, "btn-group"], ["type", "radio", "name", "viewMode", "id", "matrixView", "value", "matrix", 1, "btn-check", 3, "ngModelChange", "ngModel"], ["for", "matrixView", 1, "btn", "btn-outline-primary", "btn-sm"], ["type", "radio", "name", "viewMode", "id", "listView", "value", "list", 1, "btn-check", 3, "ngModelChange", "ngModel"], ["for", "listView", 1, "btn", "btn-outline-primary", "btn-sm"], [1, "fa-solid", "fa-list"], [1, "matrix-stats"], [1, "stat-item"], [1, "fa-solid", "fa-link", "text-primary"], [1, "fa-solid", "fa-star", "text-warning"], [1, "stat-item", "text-warning"], [1, "bulk-actions"], [1, "action-buttons"], ["type", "button", "title", "Export matrix", 1, "btn", "btn-sm", "btn-outline-info", 3, "click"], [1, "fa-solid", "fa-download"], [1, "bulk-edit-panel"], [1, "loading-container"], [1, "error-container"], [1, "fa-solid", "fa-exclamation-triangle"], ["type", "button", "title", "Bulk edit selected cells", 1, "btn", "btn-sm", "btn-outline-primary", 3, "click"], [1, "fa-solid", "fa-edit"], ["type", "button", "title", "Remove selected associations", 1, "btn", "btn-sm", "btn-outline-danger", 3, "click"], [1, "fa-solid", "fa-trash"], ["type", "button", "title", "Discard changes", 1, "btn", "btn-sm", "btn-outline-secondary", 3, "click"], [1, "fa-solid", "fa-undo"], ["type", "button", "title", "Save changes", 1, "btn", "btn-sm", "btn-success", 3, "click", "disabled"], [1, "fa-solid", "fa-save"], [1, "bulk-edit-controls"], [1, "form-group"], ["for", "bulkPriority", 1, "form-label"], ["type", "number", "id", "bulkPriority", "min", "1", "max", "10", 1, "form-control", "form-control-sm", 3, "ngModelChange", "ngModel"], ["for", "bulkStatus", 1, "form-label"], ["id", "bulkStatus", 1, "form-select", "form-select-sm", 3, "ngModelChange", "ngModel"], ["value", "Active"], ["value", "Inactive"], ["type", "button", "title", "Apply changes to selected cells", 1, "btn", "btn-sm", "btn-primary", 3, "click"], [1, "fa-solid", "fa-check"], ["type", "button", "title", "Cancel bulk edit", 1, "btn", "btn-sm", "btn-outline-secondary", 3, "click"], [1, "fa-solid", "fa-times"], [1, "bulk-edit-info"], [1, "text-muted"], [1, "loading-content"], ["role", "status", 1, "spinner-border", "text-primary"], [1, "visually-hidden"], [1, "loading-message"], [1, "matrix-container"], [1, "list-container"], [1, "matrix-scroll"], [1, "matrix-table"], [1, "prompt-header"], [1, "model-header", 3, "title"], [1, "matrix-row"], [1, "header-content"], [1, "header-name"], [1, "header-stats"], [1, "prompt-header", 3, "click", "title"], [3, "class", "title"], [3, "click", "dblclick", "title"], [1, "cell-content"], [1, "cell-content", "empty"], [1, "status-indicator", "inactive"], [1, "change-indicator", "new"], [1, "change-indicator", "modified"], [1, "performance-overlay"], [1, "fa-solid", "fa-ban"], [1, "fa-solid", "fa-plus"], [1, "empty-cell-indicator"], [1, "blocked-cell-indicator"], [1, "list-header"], [1, "list-controls"], [1, "sort-controls"], [1, "form-label"], [1, "form-select", "form-select-sm", 3, "ngModelChange", "ngModel"], ["value", "prompt"], ["value", "model"], ["value", "priority"], ["type", "button", 1, "btn", "btn-sm", "btn-outline-secondary", 3, "click", "title"], [1, "fa-solid"], [1, "filter-controls"], [1, "form-check", "form-switch"], ["type", "checkbox", "id", "showInactive", 1, "form-check-input", 3, "ngModelChange", "ngModel"], ["for", "showInactive", 1, "form-check-label"], [1, "associations-list"], [1, "no-associations-message"], [1, "association-item", 3, "inactive", "new", "modified"], [1, "association-item"], [1, "association-header"], [1, "association-names"], [1, "prompt-name"], [1, "fa-solid", "fa-arrow-right", "text-muted"], [1, "model-name"], [1, "association-actions"], [1, "association-details"], [1, "detail-item"], [1, "detail-label"], [1, "status-badge"], ["type", "button", "title", "Edit association", 1, "btn", "btn-sm", "btn-outline-primary"], ["type", "button", "title", "Remove association", 1, "btn", "btn-sm", "btn-outline-danger", 3, "click"], [1, "change-badge", "new"], [1, "change-badge", "modified"], [1, "fa-solid", "fa-info-circle", "text-muted"], [1, "text-muted", "mb-0"], ["role", "alert", 1, "alert", "alert-danger"], ["type", "button", 1, "btn", "btn-sm", "btn-outline-danger", "ms-2", 3, "click"], [1, "fa-solid", "fa-refresh"]], template: function ModelPromptPriorityMatrixComponent_Template(rf, ctx) { if (rf & 1) {
|
|
874
|
-
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "h5", 3);
|
|
875
|
-
i0.ɵɵelement(4, "i", 4);
|
|
876
|
-
i0.ɵɵtext(5, " Model-Prompt Priority Matrix ");
|
|
877
|
-
i0.ɵɵelementEnd();
|
|
878
|
-
i0.ɵɵelementStart(6, "div", 5)(7, "div", 6)(8, "input", 7);
|
|
879
|
-
i0.ɵɵtwoWayListener("ngModelChange", function ModelPromptPriorityMatrixComponent_Template_input_ngModelChange_8_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.viewMode, $event) || (ctx.viewMode = $event); return $event; });
|
|
880
|
-
i0.ɵɵlistener("ngModelChange", function ModelPromptPriorityMatrixComponent_Template_input_ngModelChange_8_listener($event) { return ctx.onViewModeChange($event); });
|
|
881
|
-
i0.ɵɵelementEnd();
|
|
882
|
-
i0.ɵɵelementStart(9, "label", 8);
|
|
883
|
-
i0.ɵɵelement(10, "i", 4);
|
|
884
|
-
i0.ɵɵtext(11, " Matrix ");
|
|
885
|
-
i0.ɵɵelementEnd();
|
|
886
|
-
i0.ɵɵelementStart(12, "input", 9);
|
|
887
|
-
i0.ɵɵtwoWayListener("ngModelChange", function ModelPromptPriorityMatrixComponent_Template_input_ngModelChange_12_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.viewMode, $event) || (ctx.viewMode = $event); return $event; });
|
|
888
|
-
i0.ɵɵlistener("ngModelChange", function ModelPromptPriorityMatrixComponent_Template_input_ngModelChange_12_listener($event) { return ctx.onViewModeChange($event); });
|
|
889
|
-
i0.ɵɵelementEnd();
|
|
890
|
-
i0.ɵɵelementStart(13, "label", 10);
|
|
891
|
-
i0.ɵɵelement(14, "i", 11);
|
|
892
|
-
i0.ɵɵtext(15, " List ");
|
|
893
|
-
i0.ɵɵelementEnd()()()();
|
|
894
|
-
i0.ɵɵelementStart(16, "div", 2)(17, "div", 12)(18, "span", 13);
|
|
895
|
-
i0.ɵɵelement(19, "i", 14);
|
|
896
|
-
i0.ɵɵtext(20);
|
|
897
|
-
i0.ɵɵelementEnd();
|
|
898
|
-
i0.ɵɵelementStart(21, "span", 13);
|
|
899
|
-
i0.ɵɵelement(22, "i", 15);
|
|
900
|
-
i0.ɵɵtext(23);
|
|
901
|
-
i0.ɵɵelementEnd();
|
|
902
|
-
i0.ɵɵtemplate(24, ModelPromptPriorityMatrixComponent_Conditional_24_Template, 3, 0, "span", 16);
|
|
903
|
-
i0.ɵɵelementEnd()();
|
|
904
|
-
i0.ɵɵelementStart(25, "div", 2);
|
|
905
|
-
i0.ɵɵtemplate(26, ModelPromptPriorityMatrixComponent_Conditional_26_Template, 7, 3, "div", 17);
|
|
906
|
-
i0.ɵɵelementStart(27, "div", 18);
|
|
907
|
-
i0.ɵɵtemplate(28, ModelPromptPriorityMatrixComponent_Conditional_28_Template, 6, 1);
|
|
908
|
-
i0.ɵɵelementStart(29, "button", 19);
|
|
909
|
-
i0.ɵɵlistener("click", function ModelPromptPriorityMatrixComponent_Template_button_click_29_listener() { return ctx.exportMatrix(); });
|
|
910
|
-
i0.ɵɵelement(30, "i", 20);
|
|
911
|
-
i0.ɵɵtext(31, " Export ");
|
|
912
|
-
i0.ɵɵelementEnd()()()();
|
|
913
|
-
i0.ɵɵtemplate(32, ModelPromptPriorityMatrixComponent_Conditional_32_Template, 24, 3, "div", 21)(33, ModelPromptPriorityMatrixComponent_Conditional_33_Template, 7, 1, "div", 22)(34, ModelPromptPriorityMatrixComponent_Conditional_34_Template, 2, 2)(35, ModelPromptPriorityMatrixComponent_Conditional_35_Template, 7, 1, "div", 23);
|
|
914
|
-
i0.ɵɵelementEnd();
|
|
915
|
-
} if (rf & 2) {
|
|
916
|
-
i0.ɵɵadvance(8);
|
|
917
|
-
i0.ɵɵtwoWayProperty("ngModel", ctx.viewMode);
|
|
918
|
-
i0.ɵɵadvance(4);
|
|
919
|
-
i0.ɵɵtwoWayProperty("ngModel", ctx.viewMode);
|
|
920
|
-
i0.ɵɵadvance(8);
|
|
921
|
-
i0.ɵɵtextInterpolate1(" ", ctx.getAssociationCount(), " associations ");
|
|
922
|
-
i0.ɵɵadvance(3);
|
|
923
|
-
i0.ɵɵtextInterpolate1(" ", ctx.getAveragePriority(), " avg priority ");
|
|
924
|
-
i0.ɵɵadvance();
|
|
925
|
-
i0.ɵɵconditional(ctx.hasUnsavedChanges() ? 24 : -1);
|
|
926
|
-
i0.ɵɵadvance(2);
|
|
927
|
-
i0.ɵɵconditional(ctx.selectedCells.size > 0 ? 26 : -1);
|
|
928
|
-
i0.ɵɵadvance(2);
|
|
929
|
-
i0.ɵɵconditional(ctx.hasUnsavedChanges() ? 28 : -1);
|
|
930
|
-
i0.ɵɵadvance(4);
|
|
931
|
-
i0.ɵɵconditional(ctx.bulkEditMode && ctx.selectedCells.size > 0 ? 32 : -1);
|
|
932
|
-
i0.ɵɵadvance();
|
|
933
|
-
i0.ɵɵconditional(ctx.isLoading ? 33 : 34);
|
|
934
|
-
i0.ɵɵadvance(2);
|
|
935
|
-
i0.ɵɵconditional(ctx.error ? 35 : -1);
|
|
936
|
-
} }, dependencies: [i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.NumberValueAccessor, i2.CheckboxControlValueAccessor, i2.SelectControlValueAccessor, i2.RadioControlValueAccessor, i2.NgControlStatus, i2.MinValidator, i2.MaxValidator, i2.NgModel], styles: [".model-prompt-priority-matrix[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: #f8f9fa;\n\n .matrix-toolbar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1rem;\n background: white;\n border-bottom: 1px solid #dee2e6;\n flex-shrink: 0;\n gap: 1rem;\n flex-wrap: wrap;\n\n .toolbar-section {\n display: flex;\n align-items: center;\n gap: 1rem;\n\n .toolbar-title {\n margin: 0;\n color: #495057;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-weight: 600;\n\n i {\n color: #0d6efd;\n }\n }\n\n .matrix-stats {\n display: flex;\n gap: 1rem;\n\n .stat-item {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n font-size: 0.875rem;\n color: #6c757d;\n\n i {\n font-size: 1rem;\n }\n }\n }\n\n .bulk-actions,\n .action-buttons {\n display: flex;\n gap: 0.5rem;\n\n .btn {\n font-size: 0.875rem;\n }\n }\n }\n }\n\n .bulk-edit-panel {\n padding: 1rem;\n background: #fff3cd;\n border-bottom: 1px solid #ffeaa7;\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-wrap: wrap;\n gap: 1rem;\n\n .bulk-edit-controls {\n display: flex;\n align-items: center;\n gap: 1rem;\n\n .form-group {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n\n .form-label {\n margin: 0;\n font-size: 0.875rem;\n font-weight: 500;\n white-space: nowrap;\n }\n\n .form-control,\n .form-select {\n min-width: 100px;\n }\n }\n }\n\n .bulk-edit-info {\n font-size: 0.875rem;\n color: #856404;\n }\n }\n\n .loading-container {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n\n .loading-content {\n text-align: center;\n \n .loading-message {\n margin-top: 1rem;\n color: #6c757d;\n }\n }\n }\n\n .matrix-container {\n flex: 1;\n overflow: hidden;\n\n .matrix-scroll {\n height: 100%;\n overflow: auto;\n padding: 1rem;\n\n .matrix-table {\n border-collapse: separate;\n border-spacing: 2px;\n background: white;\n border-radius: 0.5rem;\n overflow: hidden;\n\n .prompt-header,\n .model-header {\n background: #f8f9fa;\n border: 1px solid #dee2e6;\n padding: 0.75rem;\n font-weight: 600;\n text-align: center;\n position: sticky;\n top: 0;\n z-index: 10;\n\n .header-content {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n\n .header-name {\n font-size: 0.875rem;\n font-weight: 600;\n }\n\n .header-stats {\n font-size: 0.75rem;\n color: #6c757d;\n }\n }\n }\n\n .prompt-header {\n min-width: 200px;\n position: sticky;\n left: 0;\n z-index: 11;\n }\n\n .matrix-cell {\n width: 80px;\n height: 60px;\n border: 2px solid #e9ecef;\n text-align: center;\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n\n &:hover {\n border-color: #007bff;\n transform: scale(1.05);\n }\n\n &.selected {\n border-color: #007bff;\n background: rgba(0, 123, 255, 0.1);\n }\n\n &.editing {\n border-color: #28a745;\n background: rgba(40, 167, 69, 0.1);\n }\n\n &.no-association {\n background: #f8f9fa;\n border-style: dashed;\n\n .empty-cell-indicator {\n color: #6c757d;\n font-size: 1.5rem;\n opacity: 0.5;\n }\n }\n\n &.cannot-assign {\n background: #f5f5f5;\n cursor: not-allowed;\n opacity: 0.5;\n\n .blocked-cell-indicator {\n color: #dc3545;\n font-size: 1.25rem;\n }\n }\n\n &.has-association {\n background: white;\n\n &.priority-1 { border-color: #28a745; }\n &.priority-2 { border-color: #20c997; }\n &.priority-3 { border-color: #ffc107; }\n &.priority-4 { border-color: #fd7e14; }\n &.priority-5 { border-color: #dc3545; }\n\n &.inactive {\n opacity: 0.6;\n background: #f8f9fa;\n }\n\n &.new {\n box-shadow: 0 0 0 2px #28a745;\n }\n\n &.modified {\n box-shadow: 0 0 0 2px #ffc107;\n }\n }\n\n .cell-content {\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n height: 100%;\n gap: 0.25rem;\n\n .priority-badge {\n background: #007bff;\n color: white;\n border-radius: 50%;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.75rem;\n font-weight: 600;\n\n &.priority-1 { background: #28a745; }\n &.priority-2 { background: #20c997; }\n &.priority-3 { background: #ffc107; color: #212529; }\n &.priority-4 { background: #fd7e14; }\n &.priority-5 { background: #dc3545; }\n }\n\n .status-indicator {\n font-size: 0.75rem;\n\n &.inactive {\n color: #dc3545;\n }\n }\n\n .change-indicator {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 12px;\n height: 12px;\n border-radius: 50%;\n font-size: 0.625rem;\n display: flex;\n align-items: center;\n justify-content: center;\n\n &.new {\n background: #28a745;\n color: white;\n }\n\n &.modified {\n background: #ffc107;\n color: #212529;\n }\n }\n\n .performance-overlay {\n position: absolute;\n bottom: 2px;\n left: 2px;\n right: 2px;\n background: rgba(0, 0, 0, 0.8);\n color: white;\n border-radius: 0.25rem;\n padding: 0.125rem;\n font-size: 0.625rem;\n }\n }\n }\n }\n }\n }\n\n .list-container {\n flex: 1;\n padding: 1rem;\n overflow-y: auto;\n\n .list-header {\n margin-bottom: 1.5rem;\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 0.5rem;\n padding: 1rem;\n\n .list-controls {\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-wrap: wrap;\n gap: 1rem;\n\n .sort-controls,\n .filter-controls {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n\n .form-label {\n margin: 0;\n font-size: 0.875rem;\n color: #6c757d;\n white-space: nowrap;\n }\n\n .form-select {\n min-width: 120px;\n }\n\n .form-check {\n margin: 0;\n }\n }\n }\n }\n\n .associations-list {\n .association-item {\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 0.5rem;\n padding: 1rem;\n margin-bottom: 1rem;\n transition: all 0.2s ease;\n\n &:hover {\n box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);\n transform: translateY(-1px);\n }\n\n &.inactive {\n opacity: 0.7;\n background: #f8f9fa;\n }\n\n &.new {\n border-color: #28a745;\n border-left-width: 4px;\n }\n\n &.modified {\n border-color: #ffc107;\n border-left-width: 4px;\n }\n\n .association-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 0.75rem;\n\n .association-names {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n\n .prompt-name,\n .model-name {\n color: #495057;\n font-weight: 500;\n }\n\n i {\n color: #6c757d;\n }\n }\n\n .association-actions {\n display: flex;\n gap: 0.5rem;\n\n .btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.75rem;\n }\n }\n }\n\n .association-details {\n display: flex;\n align-items: center;\n gap: 1rem;\n flex-wrap: wrap;\n\n .detail-item {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n\n .detail-label {\n font-size: 0.875rem;\n color: #6c757d;\n }\n\n .priority-badge {\n background: #007bff;\n color: white;\n padding: 0.25rem 0.5rem;\n border-radius: 0.25rem;\n font-size: 0.75rem;\n font-weight: 600;\n\n &.priority-1 { background: #28a745; }\n &.priority-2 { background: #20c997; }\n &.priority-3 { background: #ffc107; color: #212529; }\n &.priority-4 { background: #fd7e14; }\n &.priority-5 { background: #dc3545; }\n }\n\n .status-badge {\n padding: 0.25rem 0.5rem;\n border-radius: 0.25rem;\n font-size: 0.75rem;\n font-weight: 500;\n\n &.badge-success {\n background: #d4edda;\n color: #155724;\n }\n\n &.badge-secondary {\n background: #e2e3e5;\n color: #383d41;\n }\n }\n\n .change-badge {\n padding: 0.25rem 0.5rem;\n border-radius: 0.25rem;\n font-size: 0.75rem;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 0.25rem;\n\n &.new {\n background: #d4edda;\n color: #155724;\n }\n\n &.modified {\n background: #fff3cd;\n color: #856404;\n }\n }\n }\n }\n }\n\n .no-associations-message {\n text-align: center;\n padding: 3rem 1rem;\n color: #6c757d;\n\n i {\n font-size: 3rem;\n margin-bottom: 1rem;\n display: block;\n opacity: 0.5;\n }\n\n p {\n margin: 0;\n font-size: 1rem;\n line-height: 1.5;\n }\n }\n }\n }\n\n .error-container {\n padding: 1rem;\n\n .alert {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n }\n }\n}\n\n//[_ngcontent-%COMP%] Responsive[_ngcontent-%COMP%] adjustments\n@media[_ngcontent-%COMP%] (max-width[_ngcontent-%COMP%]: 1200px)[_ngcontent-%COMP%] {\n .model-prompt-priority-matrix {\n .matrix-toolbar {\n .toolbar-section {\n min-width: 100%;\n justify-content: space-between;\n }\n }\n\n .matrix-container {\n .matrix-scroll {\n .matrix-table {\n .matrix-cell {\n width: 60px;\n height: 50px;\n }\n }\n }\n }\n }\n}\n\n@media (max-width: 768px) {\n .model-prompt-priority-matrix[_ngcontent-%COMP%] {\n .matrix-toolbar {\n padding: 0.75rem;\n \n .toolbar-section {\n flex-wrap: wrap;\n gap: 0.5rem;\n }\n }\n\n .bulk-edit-panel {\n padding: 0.75rem;\n\n .bulk-edit-controls {\n flex-direction: column;\n align-items: stretch;\n gap: 0.75rem;\n }\n }\n\n .matrix-container {\n .matrix-scroll {\n padding: 0.75rem;\n\n .matrix-table {\n .matrix-cell {\n width: 50px;\n height: 40px;\n }\n }\n }\n }\n\n .list-container {\n padding: 0.75rem;\n\n .list-header {\n .list-controls {\n flex-direction: column;\n align-items: stretch;\n }\n }\n\n .associations-list {\n .association-item {\n .association-header {\n flex-direction: column;\n align-items: flex-start;\n gap: 0.75rem;\n }\n\n .association-details {\n flex-direction: column;\n align-items: flex-start;\n }\n }\n }\n }\n }\n}"] });
|
|
937
919
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ModelPromptPriorityMatrixComponent, [{
|
|
938
920
|
type: Component,
|
|
939
921
|
args: [{ selector: 'app-model-prompt-priority-matrix', template: "<div class=\"model-prompt-priority-matrix\">\n <!-- Header toolbar -->\n <div class=\"matrix-toolbar\">\n <div class=\"toolbar-section\">\n <h5 class=\"toolbar-title\">\n <i class=\"fa-solid fa-table-cells\"></i>\n Model-Prompt Priority Matrix\n </h5>\n \n <div class=\"view-mode-toggle\">\n <div class=\"btn-group\" role=\"group\">\n <input \n type=\"radio\" \n class=\"btn-check\" \n name=\"viewMode\" \n id=\"matrixView\" \n value=\"matrix\"\n [(ngModel)]=\"viewMode\"\n (ngModelChange)=\"onViewModeChange($event)\">\n <label class=\"btn btn-outline-primary btn-sm\" for=\"matrixView\">\n <i class=\"fa-solid fa-table-cells\"></i>\n Matrix\n </label>\n \n <input \n type=\"radio\" \n class=\"btn-check\" \n name=\"viewMode\" \n id=\"listView\" \n value=\"list\"\n [(ngModel)]=\"viewMode\"\n (ngModelChange)=\"onViewModeChange($event)\">\n <label class=\"btn btn-outline-primary btn-sm\" for=\"listView\">\n <i class=\"fa-solid fa-list\"></i>\n List\n </label>\n </div>\n </div>\n </div>\n \n <div class=\"toolbar-section\">\n <div class=\"matrix-stats\">\n <span class=\"stat-item\">\n <i class=\"fa-solid fa-link text-primary\"></i>\n {{ getAssociationCount() }} associations\n </span>\n <span class=\"stat-item\">\n <i class=\"fa-solid fa-star text-warning\"></i>\n {{ getAveragePriority() }} avg priority\n </span>\n @if (hasUnsavedChanges()) {\n <span class=\"stat-item text-warning\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n Unsaved changes\n </span>\n }\n </div>\n </div>\n \n <div class=\"toolbar-section\">\n @if (selectedCells.size > 0) {\n <div class=\"bulk-actions\">\n <button \n type=\"button\" \n class=\"btn btn-sm btn-outline-primary\"\n [class.active]=\"bulkEditMode\"\n (click)=\"bulkEditMode = !bulkEditMode\"\n title=\"Bulk edit selected cells\">\n <i class=\"fa-solid fa-edit\"></i>\n Edit ({{ selectedCells.size }})\n </button>\n \n <button \n type=\"button\" \n class=\"btn btn-sm btn-outline-danger\"\n (click)=\"bulkRemoveSelectedCells()\"\n title=\"Remove selected associations\">\n <i class=\"fa-solid fa-trash\"></i>\n Remove\n </button>\n </div>\n }\n \n <div class=\"action-buttons\">\n @if (hasUnsavedChanges()) {\n <button \n type=\"button\" \n class=\"btn btn-sm btn-outline-secondary\"\n (click)=\"discardChanges()\"\n title=\"Discard changes\">\n <i class=\"fa-solid fa-undo\"></i>\n Discard\n </button>\n \n <button \n type=\"button\" \n class=\"btn btn-sm btn-success\"\n (click)=\"saveChanges()\"\n [disabled]=\"isLoading\"\n title=\"Save changes\">\n <i class=\"fa-solid fa-save\"></i>\n Save\n </button>\n }\n \n <button \n type=\"button\" \n class=\"btn btn-sm btn-outline-info\"\n (click)=\"exportMatrix()\"\n title=\"Export matrix\">\n <i class=\"fa-solid fa-download\"></i>\n Export\n </button>\n </div>\n </div>\n </div>\n \n <!-- Bulk edit panel -->\n @if (bulkEditMode && selectedCells.size > 0) {\n <div class=\"bulk-edit-panel\">\n <div class=\"bulk-edit-controls\">\n <div class=\"form-group\">\n <label for=\"bulkPriority\" class=\"form-label\">Priority:</label>\n <input \n type=\"number\" \n id=\"bulkPriority\"\n class=\"form-control form-control-sm\"\n [(ngModel)]=\"bulkEditPriority\"\n min=\"1\"\n max=\"10\">\n </div>\n \n <div class=\"form-group\">\n <label for=\"bulkStatus\" class=\"form-label\">Status:</label>\n <select \n id=\"bulkStatus\"\n class=\"form-select form-select-sm\"\n [(ngModel)]=\"bulkEditStatus\">\n <option value=\"Active\">Active</option>\n <option value=\"Inactive\">Inactive</option>\n </select>\n </div>\n \n <div class=\"form-group\">\n <button \n type=\"button\" \n class=\"btn btn-sm btn-primary\"\n (click)=\"bulkUpdateSelectedCells()\"\n title=\"Apply changes to selected cells\">\n <i class=\"fa-solid fa-check\"></i>\n Apply\n </button>\n \n <button \n type=\"button\" \n class=\"btn btn-sm btn-outline-secondary\"\n (click)=\"bulkEditMode = false\"\n title=\"Cancel bulk edit\">\n <i class=\"fa-solid fa-times\"></i>\n Cancel\n </button>\n </div>\n </div>\n \n <div class=\"bulk-edit-info\">\n <small class=\"text-muted\">\n Editing {{ selectedCells.size }} selected cell(s). \n Use Ctrl+Click for multi-select, Shift+Click for range select.\n </small>\n </div>\n </div>\n }\n \n <!-- Loading state -->\n @if (isLoading) {\n <div class=\"loading-container\">\n <div class=\"loading-content\">\n <div class=\"spinner-border text-primary\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n <p class=\"loading-message\">{{ loadingMessage }}</p>\n </div>\n </div>\n } @else {\n <!-- Matrix view -->\n @if (viewMode === 'matrix') {\n <div class=\"matrix-container\">\n <div class=\"matrix-scroll\">\n <table class=\"matrix-table\">\n <!-- Header row with model names -->\n <thead>\n <tr>\n <th class=\"prompt-header\">Prompts \\\\ Models</th>\n @for (model of models; track model.ID) {\n <th class=\"model-header\" [title]=\"model.Description || model.Name\">\n <div class=\"header-content\">\n <div class=\"header-name\">{{ model.Name }}</div>\n <div class=\"header-stats\">\n <small class=\"text-muted\">{{ getModelAssociationCount(model.ID) }}</small>\n </div>\n </div>\n </th>\n }\n </tr>\n </thead>\n \n <!-- Matrix body -->\n <tbody>\n @for (prompt of prompts; track prompt.ID; let promptIndex = $index) {\n <tr class=\"matrix-row\">\n <th class=\"prompt-header\" [title]=\"prompt.Description || prompt.Name\" (click)=\"selectPrompt(prompt)\">\n <div class=\"header-content\">\n <div class=\"header-name\">{{ prompt.Name }}</div>\n <div class=\"header-stats\">\n <small class=\"text-muted\">{{ getPromptAssociationCount(prompt.ID) }}</small>\n </div>\n </div>\n </th>\n \n @for (model of models; track model.ID; let modelIndex = $index) {\n <td \n [class]=\"getCellClass(matrix[promptIndex][modelIndex])\"\n (click)=\"onCellClick(promptIndex, modelIndex, $event)\"\n (dblclick)=\"onCellDoubleClick(promptIndex, modelIndex)\"\n [title]=\"getCellTooltip(matrix[promptIndex][modelIndex])\">\n \n @if (matrix[promptIndex][modelIndex].association; as assoc) {\n <div class=\"cell-content\">\n <div class=\"priority-badge priority-{{ assoc.priority }}\">\n {{ assoc.priority }}\n </div>\n \n @if (assoc.status === 'Inactive') {\n <div class=\"status-indicator inactive\">\n <i class=\"fa-solid fa-ban\"></i>\n </div>\n }\n \n @if (assoc.isNew) {\n <div class=\"change-indicator new\">\n <i class=\"fa-solid fa-plus\"></i>\n </div>\n } @else if (assoc.isModified) {\n <div class=\"change-indicator modified\">\n <i class=\"fa-solid fa-edit\"></i>\n </div>\n }\n \n @if (showPerformanceOverlay && performanceData[assoc.promptId + '_' + assoc.modelId]) {\n <div class=\"performance-overlay\">\n <small>{{ performanceData[assoc.promptId + '_' + assoc.modelId].avgResponseTime }}ms</small>\n </div>\n }\n </div>\n } @else {\n <div class=\"cell-content empty\">\n @if (matrix[promptIndex][modelIndex].canAssign) {\n <div class=\"empty-cell-indicator\">\n <i class=\"fa-solid fa-plus\"></i>\n </div>\n } @else {\n <div class=\"blocked-cell-indicator\">\n <i class=\"fa-solid fa-ban\"></i>\n </div>\n }\n </div>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n }\n \n <!-- List view -->\n @if (viewMode === 'list') {\n <div class=\"list-container\">\n <div class=\"list-header\">\n <div class=\"list-controls\">\n <div class=\"sort-controls\">\n <label class=\"form-label\">Sort by:</label>\n <select \n class=\"form-select form-select-sm\"\n [(ngModel)]=\"sortBy\"\n (ngModelChange)=\"sortAssociations()\">\n <option value=\"prompt\">Prompt Name</option>\n <option value=\"model\">Model Name</option>\n <option value=\"priority\">Priority</option>\n </select>\n \n <button \n type=\"button\" \n class=\"btn btn-sm btn-outline-secondary\"\n (click)=\"toggleSortDirection()\"\n [title]=\"'Sort ' + (sortDirection === 'asc' ? 'descending' : 'ascending')\">\n <i class=\"fa-solid\" [class.fa-sort-up]=\"sortDirection === 'asc'\" [class.fa-sort-down]=\"sortDirection === 'desc'\"></i>\n </button>\n </div>\n \n <div class=\"filter-controls\">\n <div class=\"form-check form-switch\">\n <input \n class=\"form-check-input\" \n type=\"checkbox\" \n id=\"showInactive\"\n [(ngModel)]=\"showInactiveAssociations\">\n <label class=\"form-check-label\" for=\"showInactive\">\n Show inactive\n </label>\n </div>\n </div>\n </div>\n </div>\n \n <div class=\"associations-list\">\n @for (association of associations; track association.promptId + '_' + association.modelId) {\n @if (showInactiveAssociations || association.status === 'Active') {\n <div class=\"association-item\" \n [class.inactive]=\"association.status === 'Inactive'\"\n [class.new]=\"association.isNew\"\n [class.modified]=\"association.isModified\">\n \n <div class=\"association-header\">\n <div class=\"association-names\">\n <strong class=\"prompt-name\">{{ association.promptName }}</strong>\n <i class=\"fa-solid fa-arrow-right text-muted\"></i>\n <strong class=\"model-name\">{{ association.modelName }}</strong>\n </div>\n \n <div class=\"association-actions\">\n @if (!readonly) {\n <button \n type=\"button\" \n class=\"btn btn-sm btn-outline-primary\"\n title=\"Edit association\">\n <i class=\"fa-solid fa-edit\"></i>\n </button>\n \n <button \n type=\"button\" \n class=\"btn btn-sm btn-outline-danger\"\n (click)=\"removeAssociation(association.promptId, association.modelId)\"\n title=\"Remove association\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n }\n </div>\n </div>\n \n <div class=\"association-details\">\n <div class=\"detail-item\">\n <span class=\"detail-label\">Priority:</span>\n <span class=\"priority-badge priority-{{ association.priority }}\">\n {{ association.priority }}\n </span>\n </div>\n \n <div class=\"detail-item\">\n <span class=\"detail-label\">Status:</span>\n <span class=\"status-badge\" [class.badge-success]=\"association.status === 'Active'\" [class.badge-secondary]=\"association.status === 'Inactive'\">\n {{ association.status }}\n </span>\n </div>\n \n @if (association.isNew) {\n <div class=\"detail-item\">\n <span class=\"change-badge new\">\n <i class=\"fa-solid fa-plus\"></i>\n New\n </span>\n </div>\n } @else if (association.isModified) {\n <div class=\"detail-item\">\n <span class=\"change-badge modified\">\n <i class=\"fa-solid fa-edit\"></i>\n Modified\n </span>\n </div>\n }\n </div>\n </div>\n }\n }\n \n @if (associations.length === 0) {\n <div class=\"no-associations-message\">\n <i class=\"fa-solid fa-info-circle text-muted\"></i>\n <p class=\"text-muted mb-0\">No prompt-model associations found. Click on matrix cells to create associations.</p>\n </div>\n }\n </div>\n </div>\n }\n }\n \n <!-- Error state -->\n @if (error) {\n <div class=\"error-container\">\n <div class=\"alert alert-danger\" role=\"alert\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n {{ error }}\n <button \n type=\"button\" \n class=\"btn btn-sm btn-outline-danger ms-2\"\n (click)=\"loadData()\">\n <i class=\"fa-solid fa-refresh\"></i>\n Retry\n </button>\n </div>\n </div>\n }\n</div>", styles: [".model-prompt-priority-matrix {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: #f8f9fa;\n\n .matrix-toolbar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1rem;\n background: white;\n border-bottom: 1px solid #dee2e6;\n flex-shrink: 0;\n gap: 1rem;\n flex-wrap: wrap;\n\n .toolbar-section {\n display: flex;\n align-items: center;\n gap: 1rem;\n\n .toolbar-title {\n margin: 0;\n color: #495057;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-weight: 600;\n\n i {\n color: #0d6efd;\n }\n }\n\n .matrix-stats {\n display: flex;\n gap: 1rem;\n\n .stat-item {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n font-size: 0.875rem;\n color: #6c757d;\n\n i {\n font-size: 1rem;\n }\n }\n }\n\n .bulk-actions,\n .action-buttons {\n display: flex;\n gap: 0.5rem;\n\n .btn {\n font-size: 0.875rem;\n }\n }\n }\n }\n\n .bulk-edit-panel {\n padding: 1rem;\n background: #fff3cd;\n border-bottom: 1px solid #ffeaa7;\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-wrap: wrap;\n gap: 1rem;\n\n .bulk-edit-controls {\n display: flex;\n align-items: center;\n gap: 1rem;\n\n .form-group {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n\n .form-label {\n margin: 0;\n font-size: 0.875rem;\n font-weight: 500;\n white-space: nowrap;\n }\n\n .form-control,\n .form-select {\n min-width: 100px;\n }\n }\n }\n\n .bulk-edit-info {\n font-size: 0.875rem;\n color: #856404;\n }\n }\n\n .loading-container {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n\n .loading-content {\n text-align: center;\n \n .loading-message {\n margin-top: 1rem;\n color: #6c757d;\n }\n }\n }\n\n .matrix-container {\n flex: 1;\n overflow: hidden;\n\n .matrix-scroll {\n height: 100%;\n overflow: auto;\n padding: 1rem;\n\n .matrix-table {\n border-collapse: separate;\n border-spacing: 2px;\n background: white;\n border-radius: 0.5rem;\n overflow: hidden;\n\n .prompt-header,\n .model-header {\n background: #f8f9fa;\n border: 1px solid #dee2e6;\n padding: 0.75rem;\n font-weight: 600;\n text-align: center;\n position: sticky;\n top: 0;\n z-index: 10;\n\n .header-content {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n\n .header-name {\n font-size: 0.875rem;\n font-weight: 600;\n }\n\n .header-stats {\n font-size: 0.75rem;\n color: #6c757d;\n }\n }\n }\n\n .prompt-header {\n min-width: 200px;\n position: sticky;\n left: 0;\n z-index: 11;\n }\n\n .matrix-cell {\n width: 80px;\n height: 60px;\n border: 2px solid #e9ecef;\n text-align: center;\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n\n &:hover {\n border-color: #007bff;\n transform: scale(1.05);\n }\n\n &.selected {\n border-color: #007bff;\n background: rgba(0, 123, 255, 0.1);\n }\n\n &.editing {\n border-color: #28a745;\n background: rgba(40, 167, 69, 0.1);\n }\n\n &.no-association {\n background: #f8f9fa;\n border-style: dashed;\n\n .empty-cell-indicator {\n color: #6c757d;\n font-size: 1.5rem;\n opacity: 0.5;\n }\n }\n\n &.cannot-assign {\n background: #f5f5f5;\n cursor: not-allowed;\n opacity: 0.5;\n\n .blocked-cell-indicator {\n color: #dc3545;\n font-size: 1.25rem;\n }\n }\n\n &.has-association {\n background: white;\n\n &.priority-1 { border-color: #28a745; }\n &.priority-2 { border-color: #20c997; }\n &.priority-3 { border-color: #ffc107; }\n &.priority-4 { border-color: #fd7e14; }\n &.priority-5 { border-color: #dc3545; }\n\n &.inactive {\n opacity: 0.6;\n background: #f8f9fa;\n }\n\n &.new {\n box-shadow: 0 0 0 2px #28a745;\n }\n\n &.modified {\n box-shadow: 0 0 0 2px #ffc107;\n }\n }\n\n .cell-content {\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n height: 100%;\n gap: 0.25rem;\n\n .priority-badge {\n background: #007bff;\n color: white;\n border-radius: 50%;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.75rem;\n font-weight: 600;\n\n &.priority-1 { background: #28a745; }\n &.priority-2 { background: #20c997; }\n &.priority-3 { background: #ffc107; color: #212529; }\n &.priority-4 { background: #fd7e14; }\n &.priority-5 { background: #dc3545; }\n }\n\n .status-indicator {\n font-size: 0.75rem;\n\n &.inactive {\n color: #dc3545;\n }\n }\n\n .change-indicator {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 12px;\n height: 12px;\n border-radius: 50%;\n font-size: 0.625rem;\n display: flex;\n align-items: center;\n justify-content: center;\n\n &.new {\n background: #28a745;\n color: white;\n }\n\n &.modified {\n background: #ffc107;\n color: #212529;\n }\n }\n\n .performance-overlay {\n position: absolute;\n bottom: 2px;\n left: 2px;\n right: 2px;\n background: rgba(0, 0, 0, 0.8);\n color: white;\n border-radius: 0.25rem;\n padding: 0.125rem;\n font-size: 0.625rem;\n }\n }\n }\n }\n }\n }\n\n .list-container {\n flex: 1;\n padding: 1rem;\n overflow-y: auto;\n\n .list-header {\n margin-bottom: 1.5rem;\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 0.5rem;\n padding: 1rem;\n\n .list-controls {\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-wrap: wrap;\n gap: 1rem;\n\n .sort-controls,\n .filter-controls {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n\n .form-label {\n margin: 0;\n font-size: 0.875rem;\n color: #6c757d;\n white-space: nowrap;\n }\n\n .form-select {\n min-width: 120px;\n }\n\n .form-check {\n margin: 0;\n }\n }\n }\n }\n\n .associations-list {\n .association-item {\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 0.5rem;\n padding: 1rem;\n margin-bottom: 1rem;\n transition: all 0.2s ease;\n\n &:hover {\n box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);\n transform: translateY(-1px);\n }\n\n &.inactive {\n opacity: 0.7;\n background: #f8f9fa;\n }\n\n &.new {\n border-color: #28a745;\n border-left-width: 4px;\n }\n\n &.modified {\n border-color: #ffc107;\n border-left-width: 4px;\n }\n\n .association-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 0.75rem;\n\n .association-names {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n\n .prompt-name,\n .model-name {\n color: #495057;\n font-weight: 500;\n }\n\n i {\n color: #6c757d;\n }\n }\n\n .association-actions {\n display: flex;\n gap: 0.5rem;\n\n .btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.75rem;\n }\n }\n }\n\n .association-details {\n display: flex;\n align-items: center;\n gap: 1rem;\n flex-wrap: wrap;\n\n .detail-item {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n\n .detail-label {\n font-size: 0.875rem;\n color: #6c757d;\n }\n\n .priority-badge {\n background: #007bff;\n color: white;\n padding: 0.25rem 0.5rem;\n border-radius: 0.25rem;\n font-size: 0.75rem;\n font-weight: 600;\n\n &.priority-1 { background: #28a745; }\n &.priority-2 { background: #20c997; }\n &.priority-3 { background: #ffc107; color: #212529; }\n &.priority-4 { background: #fd7e14; }\n &.priority-5 { background: #dc3545; }\n }\n\n .status-badge {\n padding: 0.25rem 0.5rem;\n border-radius: 0.25rem;\n font-size: 0.75rem;\n font-weight: 500;\n\n &.badge-success {\n background: #d4edda;\n color: #155724;\n }\n\n &.badge-secondary {\n background: #e2e3e5;\n color: #383d41;\n }\n }\n\n .change-badge {\n padding: 0.25rem 0.5rem;\n border-radius: 0.25rem;\n font-size: 0.75rem;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 0.25rem;\n\n &.new {\n background: #d4edda;\n color: #155724;\n }\n\n &.modified {\n background: #fff3cd;\n color: #856404;\n }\n }\n }\n }\n }\n\n .no-associations-message {\n text-align: center;\n padding: 3rem 1rem;\n color: #6c757d;\n\n i {\n font-size: 3rem;\n margin-bottom: 1rem;\n display: block;\n opacity: 0.5;\n }\n\n p {\n margin: 0;\n font-size: 1rem;\n line-height: 1.5;\n }\n }\n }\n }\n\n .error-container {\n padding: 1rem;\n\n .alert {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n }\n }\n}\n\n// Responsive adjustments\n@media (max-width: 1200px) {\n .model-prompt-priority-matrix {\n .matrix-toolbar {\n .toolbar-section {\n min-width: 100%;\n justify-content: space-between;\n }\n }\n\n .matrix-container {\n .matrix-scroll {\n .matrix-table {\n .matrix-cell {\n width: 60px;\n height: 50px;\n }\n }\n }\n }\n }\n}\n\n@media (max-width: 768px) {\n .model-prompt-priority-matrix {\n .matrix-toolbar {\n padding: 0.75rem;\n \n .toolbar-section {\n flex-wrap: wrap;\n gap: 0.5rem;\n }\n }\n\n .bulk-edit-panel {\n padding: 0.75rem;\n\n .bulk-edit-controls {\n flex-direction: column;\n align-items: stretch;\n gap: 0.75rem;\n }\n }\n\n .matrix-container {\n .matrix-scroll {\n padding: 0.75rem;\n\n .matrix-table {\n .matrix-cell {\n width: 50px;\n height: 40px;\n }\n }\n }\n }\n\n .list-container {\n padding: 0.75rem;\n\n .list-header {\n .list-controls {\n flex-direction: column;\n align-items: stretch;\n }\n }\n\n .associations-list {\n .association-item {\n .association-header {\n flex-direction: column;\n align-items: flex-start;\n gap: 0.75rem;\n }\n\n .association-details {\n flex-direction: column;\n align-items: flex-start;\n }\n }\n }\n }\n }\n}"] }]
|