@memberjunction/ng-core-entity-forms 2.111.1 → 2.112.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +10 -10
  2. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-diagram.component.d.ts.map +1 -1
  3. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-diagram.component.js +45 -45
  4. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-diagram.component.js.map +1 -1
  5. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-form-section.component.d.ts.map +1 -1
  6. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-form-section.component.js +6 -7
  7. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-form-section.component.js.map +1 -1
  8. package/dist/lib/custom/AIAgents/FlowAgentType/mj-integrated-flow-editor.component.d.ts.map +1 -1
  9. package/dist/lib/custom/AIAgents/FlowAgentType/mj-integrated-flow-editor.component.js +17 -32
  10. package/dist/lib/custom/AIAgents/FlowAgentType/mj-integrated-flow-editor.component.js.map +1 -1
  11. package/dist/lib/custom/AIAgents/add-action-dialog.component.d.ts.map +1 -1
  12. package/dist/lib/custom/AIAgents/add-action-dialog.component.js +37 -36
  13. package/dist/lib/custom/AIAgents/add-action-dialog.component.js.map +1 -1
  14. package/dist/lib/custom/AIAgents/agent-advanced-settings-dialog.component.js +2 -2
  15. package/dist/lib/custom/AIAgents/agent-advanced-settings-dialog.component.js.map +1 -1
  16. package/dist/lib/custom/AIAgents/agent-permissions-dialog.component.d.ts +1 -1
  17. package/dist/lib/custom/AIAgents/agent-permissions-dialog.component.d.ts.map +1 -1
  18. package/dist/lib/custom/AIAgents/agent-permissions-dialog.component.js +18 -25
  19. package/dist/lib/custom/AIAgents/agent-permissions-dialog.component.js.map +1 -1
  20. package/dist/lib/custom/AIAgents/agent-prompt-advanced-settings-dialog.component.d.ts.map +1 -1
  21. package/dist/lib/custom/AIAgents/agent-prompt-advanced-settings-dialog.component.js +10 -11
  22. package/dist/lib/custom/AIAgents/agent-prompt-advanced-settings-dialog.component.js.map +1 -1
  23. package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts.map +1 -1
  24. package/dist/lib/custom/AIAgents/ai-agent-form.component.js +159 -147
  25. package/dist/lib/custom/AIAgents/ai-agent-form.component.js.map +1 -1
  26. package/dist/lib/custom/AIAgents/create-prompt-dialog.component.d.ts.map +1 -1
  27. package/dist/lib/custom/AIAgents/create-prompt-dialog.component.js +11 -10
  28. package/dist/lib/custom/AIAgents/create-prompt-dialog.component.js.map +1 -1
  29. package/dist/lib/custom/AIAgents/create-sub-agent-dialog.component.d.ts.map +1 -1
  30. package/dist/lib/custom/AIAgents/create-sub-agent-dialog.component.js +36 -32
  31. package/dist/lib/custom/AIAgents/create-sub-agent-dialog.component.js.map +1 -1
  32. package/dist/lib/custom/AIAgents/new-agent-dialog.component.js +5 -5
  33. package/dist/lib/custom/AIAgents/new-agent-dialog.component.js.map +1 -1
  34. package/dist/lib/custom/AIAgents/prompt-selector-dialog.component.d.ts.map +1 -1
  35. package/dist/lib/custom/AIAgents/prompt-selector-dialog.component.js +15 -13
  36. package/dist/lib/custom/AIAgents/prompt-selector-dialog.component.js.map +1 -1
  37. package/dist/lib/custom/AIAgents/sub-agent-advanced-settings-dialog.component.d.ts.map +1 -1
  38. package/dist/lib/custom/AIAgents/sub-agent-advanced-settings-dialog.component.js +13 -15
  39. package/dist/lib/custom/AIAgents/sub-agent-advanced-settings-dialog.component.js.map +1 -1
  40. package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.d.ts.map +1 -1
  41. package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.js +28 -23
  42. package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.js.map +1 -1
  43. package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.d.ts.map +1 -1
  44. package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js +15 -12
  45. package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js.map +1 -1
  46. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.d.ts.map +1 -1
  47. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js +105 -86
  48. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js.map +1 -1
  49. package/dist/lib/custom/AIPrompts/template-selector-dialog.component.d.ts.map +1 -1
  50. package/dist/lib/custom/AIPrompts/template-selector-dialog.component.js +13 -20
  51. package/dist/lib/custom/AIPrompts/template-selector-dialog.component.js.map +1 -1
  52. package/dist/lib/custom/Actions/action-execution-log-form.component.d.ts.map +1 -1
  53. package/dist/lib/custom/Actions/action-execution-log-form.component.js +4 -7
  54. package/dist/lib/custom/Actions/action-execution-log-form.component.js.map +1 -1
  55. package/dist/lib/custom/Actions/action-form.component.d.ts.map +1 -1
  56. package/dist/lib/custom/Actions/action-form.component.js +99 -80
  57. package/dist/lib/custom/Actions/action-form.component.js.map +1 -1
  58. package/dist/lib/custom/Actions/action-test-harness.component.d.ts.map +1 -1
  59. package/dist/lib/custom/Actions/action-test-harness.component.js +24 -17
  60. package/dist/lib/custom/Actions/action-test-harness.component.js.map +1 -1
  61. package/dist/lib/custom/Queries/query-category-dialog.component.d.ts.map +1 -1
  62. package/dist/lib/custom/Queries/query-category-dialog.component.js +8 -8
  63. package/dist/lib/custom/Queries/query-category-dialog.component.js.map +1 -1
  64. package/dist/lib/custom/Queries/query-form.component.d.ts +2 -2
  65. package/dist/lib/custom/Queries/query-form.component.d.ts.map +1 -1
  66. package/dist/lib/custom/Queries/query-form.component.js +32 -44
  67. package/dist/lib/custom/Queries/query-form.component.js.map +1 -1
  68. package/dist/lib/custom/Queries/query-run-dialog.component.d.ts.map +1 -1
  69. package/dist/lib/custom/Queries/query-run-dialog.component.js +24 -22
  70. package/dist/lib/custom/Queries/query-run-dialog.component.js.map +1 -1
  71. package/dist/lib/custom/Templates/template-param-dialog.component.d.ts.map +1 -1
  72. package/dist/lib/custom/Templates/template-param-dialog.component.js +15 -21
  73. package/dist/lib/custom/Templates/template-param-dialog.component.js.map +1 -1
  74. package/dist/lib/custom/Templates/template-params-grid.component.d.ts.map +1 -1
  75. package/dist/lib/custom/Templates/template-params-grid.component.js +29 -17
  76. package/dist/lib/custom/Templates/template-params-grid.component.js.map +1 -1
  77. package/dist/lib/custom/Templates/templates-form.component.d.ts.map +1 -1
  78. package/dist/lib/custom/Templates/templates-form.component.js +25 -26
  79. package/dist/lib/custom/Templates/templates-form.component.js.map +1 -1
  80. package/dist/lib/custom/ai-agent-run/ai-agent-run-analytics.component.d.ts.map +1 -1
  81. package/dist/lib/custom/ai-agent-run/ai-agent-run-analytics.component.js +335 -274
  82. package/dist/lib/custom/ai-agent-run/ai-agent-run-analytics.component.js.map +1 -1
  83. package/dist/lib/custom/ai-agent-run/ai-agent-run-cost.service.d.ts.map +1 -1
  84. package/dist/lib/custom/ai-agent-run/ai-agent-run-cost.service.js +8 -8
  85. package/dist/lib/custom/ai-agent-run/ai-agent-run-cost.service.js.map +1 -1
  86. package/dist/lib/custom/ai-agent-run/ai-agent-run-data.service.d.ts.map +1 -1
  87. package/dist/lib/custom/ai-agent-run/ai-agent-run-data.service.js +24 -28
  88. package/dist/lib/custom/ai-agent-run/ai-agent-run-data.service.js.map +1 -1
  89. package/dist/lib/custom/ai-agent-run/ai-agent-run-timeline.component.d.ts.map +1 -1
  90. package/dist/lib/custom/ai-agent-run/ai-agent-run-timeline.component.js +25 -30
  91. package/dist/lib/custom/ai-agent-run/ai-agent-run-timeline.component.js.map +1 -1
  92. package/dist/lib/custom/ai-agent-run/ai-agent-run.component.d.ts.map +1 -1
  93. package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js +20 -21
  94. package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js.map +1 -1
  95. package/dist/lib/custom/shared/entity-selector-dialog.component.d.ts.map +1 -1
  96. package/dist/lib/custom/shared/entity-selector-dialog.component.js +6 -7
  97. package/dist/lib/custom/shared/entity-selector-dialog.component.js.map +1 -1
  98. package/dist/lib/generated/Entities/AIAgent/sections/aiagent-form-overview.component.d.ts.map +1 -1
  99. package/dist/lib/generated/Entities/AIAgent/sections/aiagent-form-overview.component.js +47 -33
  100. package/dist/lib/generated/Entities/AIAgent/sections/aiagent-form-overview.component.js.map +1 -1
  101. package/dist/lib/shared/components/template-editor.component.d.ts.map +1 -1
  102. package/dist/lib/shared/components/template-editor.component.js +26 -27
  103. package/dist/lib/shared/components/template-editor.component.js.map +1 -1
  104. package/package.json +16 -17
@@ -8,7 +8,7 @@ import { Component, inject, ViewContainerRef } from '@angular/core';
8
8
  import { RegisterClass } from '@memberjunction/global';
9
9
  import { BaseFormComponent } from '@memberjunction/ng-base-forms';
10
10
  import { SharedService } from '@memberjunction/ng-shared';
11
- import { Metadata, RunView, CompositeKey } from '@memberjunction/core';
11
+ import { Metadata, RunView, CompositeKey } from '@memberjunction/global';
12
12
  import { ActionFormComponent } from '../../generated/Entities/Action/action.form.component';
13
13
  import { DialogService } from '@progress/kendo-angular-dialog';
14
14
  import { ActionParamDialogComponent } from './action-param-dialog.component';
@@ -1076,7 +1076,7 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1076
1076
  params: true,
1077
1077
  resultCodes: true,
1078
1078
  execution: false,
1079
- configuration: false
1079
+ configuration: false,
1080
1080
  };
1081
1081
  // Test harness state
1082
1082
  this.showTestHarness = false;
@@ -1085,7 +1085,7 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1085
1085
  totalRuns: 0,
1086
1086
  successRate: 0,
1087
1087
  avgDuration: 0,
1088
- lastRun: null
1088
+ lastRun: null,
1089
1089
  };
1090
1090
  // Code editor config
1091
1091
  this.codeLanguage = 'typescript';
@@ -1103,7 +1103,7 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1103
1103
  this.loadResultCodes(),
1104
1104
  this.loadRecentExecutions(),
1105
1105
  this.loadActionLibraries(),
1106
- this.loadExecutionStats()
1106
+ this.loadExecutionStats(),
1107
1107
  ]);
1108
1108
  }
1109
1109
  }
@@ -1182,10 +1182,7 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1182
1182
  this.paramsToDelete = [];
1183
1183
  this.resultCodesToDelete = [];
1184
1184
  // Reload params and result codes to get updated data
1185
- await Promise.all([
1186
- this.loadActionParams(),
1187
- this.loadResultCodes()
1188
- ]);
1185
+ await Promise.all([this.loadActionParams(), this.loadResultCodes()]);
1189
1186
  // Show success message
1190
1187
  this.sharedService.CreateSimpleNotification('Action and related records saved successfully', 'success', 3000);
1191
1188
  }
@@ -1219,16 +1216,16 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1219
1216
  EntityName: 'Action Params',
1220
1217
  ExtraFilter: `ActionID='${this.record.ID}'`,
1221
1218
  OrderBy: 'Name',
1222
- ResultType: 'entity_object' // This ensures we get proper entity instances
1219
+ ResultType: 'entity_object', // This ensures we get proper entity instances
1223
1220
  });
1224
1221
  if (result.Success) {
1225
1222
  this.actionParams = result.Results || [];
1226
1223
  // Update cached filtered params - trim and lowercase Type values to handle any whitespace and case
1227
- this._inputParams = this.actionParams.filter(p => {
1224
+ this._inputParams = this.actionParams.filter((p) => {
1228
1225
  const type = p.Type?.trim().toLowerCase();
1229
1226
  return type === 'input' || type === 'both';
1230
1227
  });
1231
- this._outputParams = this.actionParams.filter(p => {
1228
+ this._outputParams = this.actionParams.filter((p) => {
1232
1229
  const type = p.Type?.trim().toLowerCase();
1233
1230
  return type === 'output' || type === 'both';
1234
1231
  });
@@ -1259,7 +1256,7 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1259
1256
  EntityName: 'Action Result Codes',
1260
1257
  ExtraFilter: `ActionID='${this.record.ID}'`,
1261
1258
  OrderBy: 'IsSuccess DESC, ResultCode',
1262
- ResultType: 'entity_object' // This ensures we get proper entity instances
1259
+ ResultType: 'entity_object', // This ensures we get proper entity instances
1263
1260
  });
1264
1261
  if (result.Success) {
1265
1262
  this.resultCodes = result.Results || [];
@@ -1285,7 +1282,7 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1285
1282
  EntityName: 'Action Execution Logs',
1286
1283
  ExtraFilter: `ActionID='${this.record.ID}'`,
1287
1284
  OrderBy: 'StartedAt DESC',
1288
- MaxRows: 10
1285
+ MaxRows: 10,
1289
1286
  });
1290
1287
  if (result.Success) {
1291
1288
  this.recentExecutions = result.Results || [];
@@ -1310,13 +1307,13 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1310
1307
  const result = await rv.RunView({
1311
1308
  EntityName: 'Action Libraries',
1312
1309
  ExtraFilter: `ActionID='${this.record.ID}'`,
1313
- OrderBy: 'Library'
1310
+ OrderBy: 'Library',
1314
1311
  });
1315
1312
  if (result.Success) {
1316
1313
  this.actionLibraries = result.Results || [];
1317
1314
  // Load library details
1318
1315
  if (this.actionLibraries.length > 0) {
1319
- const libraryIds = this.actionLibraries.map(al => al.LibraryID).filter(id => id);
1316
+ const libraryIds = this.actionLibraries.map((al) => al.LibraryID).filter((id) => id);
1320
1317
  const md = new Metadata();
1321
1318
  this.libraries = [];
1322
1319
  for (const libId of libraryIds) {
@@ -1343,21 +1340,20 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1343
1340
  const result = await rv.RunView({
1344
1341
  EntityName: 'Action Execution Logs',
1345
1342
  ExtraFilter: `ActionID='${this.record.ID}'`,
1346
- OrderBy: 'StartedAt DESC'
1343
+ OrderBy: 'StartedAt DESC',
1347
1344
  });
1348
1345
  if (result.Success && result.Results && result.Results.length > 0) {
1349
1346
  const allExecutions = result.Results;
1350
1347
  this.executionStats.totalRuns = allExecutions.length;
1351
1348
  // Calculate success rate based on result codes
1352
- const successfulRuns = allExecutions.filter(e => {
1353
- const resultCode = this.resultCodes.find(rc => rc.ResultCode === e.ResultCode);
1349
+ const successfulRuns = allExecutions.filter((e) => {
1350
+ const resultCode = this.resultCodes.find((rc) => rc.ResultCode === e.ResultCode);
1354
1351
  return resultCode?.IsSuccess || false;
1355
1352
  });
1356
- this.executionStats.successRate = this.executionStats.totalRuns > 0
1357
- ? (successfulRuns.length / this.executionStats.totalRuns) * 100
1358
- : 0;
1353
+ this.executionStats.successRate =
1354
+ this.executionStats.totalRuns > 0 ? (successfulRuns.length / this.executionStats.totalRuns) * 100 : 0;
1359
1355
  // Calculate average duration from ALL completed executions
1360
- const completedExecutions = allExecutions.filter(e => e.StartedAt && e.EndedAt);
1356
+ const completedExecutions = allExecutions.filter((e) => e.StartedAt && e.EndedAt);
1361
1357
  if (completedExecutions.length > 0) {
1362
1358
  const totalDuration = completedExecutions.reduce((sum, e) => {
1363
1359
  const duration = new Date(e.EndedAt).getTime() - new Date(e.StartedAt).getTime();
@@ -1377,18 +1373,26 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1377
1373
  // UI Helper Methods
1378
1374
  getStatusColor() {
1379
1375
  switch (this.record.Status) {
1380
- case 'Active': return '#28a745';
1381
- case 'Pending': return '#ffc107';
1382
- case 'Disabled': return '#dc3545';
1383
- default: return '#6c757d';
1376
+ case 'Active':
1377
+ return '#28a745';
1378
+ case 'Pending':
1379
+ return '#ffc107';
1380
+ case 'Disabled':
1381
+ return '#dc3545';
1382
+ default:
1383
+ return '#6c757d';
1384
1384
  }
1385
1385
  }
1386
1386
  getStatusIcon() {
1387
1387
  switch (this.record.Status) {
1388
- case 'Active': return 'fa-check-circle';
1389
- case 'Pending': return 'fa-clock';
1390
- case 'Disabled': return 'fa-ban';
1391
- default: return 'fa-question-circle';
1388
+ case 'Active':
1389
+ return 'fa-check-circle';
1390
+ case 'Pending':
1391
+ return 'fa-clock';
1392
+ case 'Disabled':
1393
+ return 'fa-ban';
1394
+ default:
1395
+ return 'fa-question-circle';
1392
1396
  }
1393
1397
  }
1394
1398
  getTypeColor() {
@@ -1399,34 +1403,50 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1399
1403
  }
1400
1404
  getApprovalStatusColor() {
1401
1405
  switch (this.record.CodeApprovalStatus) {
1402
- case 'Approved': return '#28a745';
1403
- case 'Pending': return '#ffc107';
1404
- case 'Rejected': return '#dc3545';
1405
- default: return '#6c757d';
1406
+ case 'Approved':
1407
+ return '#28a745';
1408
+ case 'Pending':
1409
+ return '#ffc107';
1410
+ case 'Rejected':
1411
+ return '#dc3545';
1412
+ default:
1413
+ return '#6c757d';
1406
1414
  }
1407
1415
  }
1408
1416
  getApprovalStatusIcon() {
1409
1417
  switch (this.record.CodeApprovalStatus) {
1410
- case 'Approved': return 'fa-check-circle';
1411
- case 'Pending': return 'fa-clock';
1412
- case 'Rejected': return 'fa-times-circle';
1413
- default: return 'fa-question-circle';
1418
+ case 'Approved':
1419
+ return 'fa-check-circle';
1420
+ case 'Pending':
1421
+ return 'fa-clock';
1422
+ case 'Rejected':
1423
+ return 'fa-times-circle';
1424
+ default:
1425
+ return 'fa-question-circle';
1414
1426
  }
1415
1427
  }
1416
1428
  getParamTypeIcon(type) {
1417
1429
  switch (type) {
1418
- case 'Input': return 'fa-sign-in-alt';
1419
- case 'Output': return 'fa-sign-out-alt';
1420
- case 'Both': return 'fa-exchange-alt';
1421
- default: return 'fa-question';
1430
+ case 'Input':
1431
+ return 'fa-sign-in-alt';
1432
+ case 'Output':
1433
+ return 'fa-sign-out-alt';
1434
+ case 'Both':
1435
+ return 'fa-exchange-alt';
1436
+ default:
1437
+ return 'fa-question';
1422
1438
  }
1423
1439
  }
1424
1440
  getParamTypeColor(type) {
1425
1441
  switch (type) {
1426
- case 'Input': return '#007bff';
1427
- case 'Output': return '#28a745';
1428
- case 'Both': return '#6f42c1';
1429
- default: return '#6c757d';
1442
+ case 'Input':
1443
+ return '#007bff';
1444
+ case 'Output':
1445
+ return '#28a745';
1446
+ case 'Both':
1447
+ return '#6f42c1';
1448
+ default:
1449
+ return '#6c757d';
1430
1450
  }
1431
1451
  }
1432
1452
  formatDuration(ms) {
@@ -1537,7 +1557,7 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1537
1557
  isExecutionSuccess(execution) {
1538
1558
  const code = execution.ResultCode?.toLowerCase();
1539
1559
  // First check if we have a result code definition
1540
- const resultCode = this.resultCodes.find(rc => rc.ResultCode === execution.ResultCode);
1560
+ const resultCode = this.resultCodes.find((rc) => rc.ResultCode === execution.ResultCode);
1541
1561
  if (resultCode) {
1542
1562
  return resultCode.IsSuccess;
1543
1563
  }
@@ -1577,13 +1597,13 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1577
1597
  const dialogRef = this.dialogService.open({
1578
1598
  content: ActionParamDialogComponent,
1579
1599
  width: 500,
1580
- appendTo: this.viewContainerRef
1600
+ appendTo: this.viewContainerRef,
1581
1601
  });
1582
1602
  const dialog = dialogRef.content.instance;
1583
1603
  dialog.param = newParam;
1584
1604
  dialog.isNew = true;
1585
1605
  dialog.editMode = true;
1586
- dialogRef.result.subscribe(result => {
1606
+ dialogRef.result.subscribe((result) => {
1587
1607
  if (result && result.save) {
1588
1608
  // The dialog has already modified the newParam entity directly
1589
1609
  // New entities are automatically dirty (IsSaved = false)
@@ -1592,7 +1612,7 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1592
1612
  // Add to pending records for saving
1593
1613
  this.PendingRecords.push({
1594
1614
  entityObject: newParam,
1595
- action: 'save'
1615
+ action: 'save',
1596
1616
  });
1597
1617
  // Update the filtered arrays
1598
1618
  this.updateParamArrays();
@@ -1604,22 +1624,22 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1604
1624
  const dialogRef = this.dialogService.open({
1605
1625
  content: ActionParamDialogComponent,
1606
1626
  width: 500,
1607
- appendTo: this.viewContainerRef
1627
+ appendTo: this.viewContainerRef,
1608
1628
  });
1609
1629
  const dialog = dialogRef.content.instance;
1610
1630
  dialog.param = param;
1611
1631
  dialog.isNew = false;
1612
1632
  dialog.editMode = this.EditMode;
1613
- dialogRef.result.subscribe(result => {
1633
+ dialogRef.result.subscribe((result) => {
1614
1634
  if (result && result.save && this.EditMode) {
1615
1635
  // Param will be dirty from property changes in dialog
1616
1636
  // Ensure it's in pending records if modified
1617
1637
  if (param.Dirty) {
1618
- const exists = this.PendingRecords.some(pr => pr.entityObject === param && pr.action === 'save');
1638
+ const exists = this.PendingRecords.some((pr) => pr.entityObject === param && pr.action === 'save');
1619
1639
  if (!exists) {
1620
1640
  this.PendingRecords.push({
1621
1641
  entityObject: param,
1622
- action: 'save'
1642
+ action: 'save',
1623
1643
  });
1624
1644
  }
1625
1645
  }
@@ -1640,12 +1660,12 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1640
1660
  }
1641
1661
  async updateParamArrays() {
1642
1662
  // Update cached filtered params - exclude deleted items
1643
- const activeParams = this.actionParams.filter(p => !this.paramsToDelete || !this.paramsToDelete.includes(p));
1644
- this._inputParams = activeParams.filter(p => {
1663
+ const activeParams = this.actionParams.filter((p) => !this.paramsToDelete || !this.paramsToDelete.includes(p));
1664
+ this._inputParams = activeParams.filter((p) => {
1645
1665
  const type = p.Type?.trim().toLowerCase();
1646
1666
  return type === 'input' || type === 'both';
1647
1667
  });
1648
- this._outputParams = activeParams.filter(p => {
1668
+ this._outputParams = activeParams.filter((p) => {
1649
1669
  const type = p.Type?.trim().toLowerCase();
1650
1670
  return type === 'output' || type === 'both';
1651
1671
  });
@@ -1659,9 +1679,8 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1659
1679
  // Re-add our preserved records
1660
1680
  for (const record of currentPendingRecords) {
1661
1681
  // Only re-add if it's an Action Param or Result Code (avoid duplicates)
1662
- if (record.entityObject.EntityInfo.Name === 'Action Params' ||
1663
- record.entityObject.EntityInfo.Name === 'Action Result Codes') {
1664
- const exists = this.PendingRecords.some(pr => pr.entityObject === record.entityObject);
1682
+ if (record.entityObject.EntityInfo.Name === 'Action Params' || record.entityObject.EntityInfo.Name === 'Action Result Codes') {
1683
+ const exists = this.PendingRecords.some((pr) => pr.entityObject === record.entityObject);
1665
1684
  if (!exists) {
1666
1685
  this.PendingRecords.push(record);
1667
1686
  }
@@ -1671,11 +1690,11 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1671
1690
  for (const param of this.actionParams) {
1672
1691
  if (!param.IsSaved || param.Dirty) {
1673
1692
  // Check if not already in pending records
1674
- const exists = this.PendingRecords.some(pr => pr.entityObject === param);
1693
+ const exists = this.PendingRecords.some((pr) => pr.entityObject === param);
1675
1694
  if (!exists) {
1676
1695
  this.PendingRecords.push({
1677
1696
  entityObject: param,
1678
- action: 'save'
1697
+ action: 'save',
1679
1698
  });
1680
1699
  }
1681
1700
  }
@@ -1684,11 +1703,11 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1684
1703
  for (const param of this.paramsToDelete) {
1685
1704
  if (param.IsSaved) {
1686
1705
  // Check if not already in pending records
1687
- const exists = this.PendingRecords.some(pr => pr.entityObject === param);
1706
+ const exists = this.PendingRecords.some((pr) => pr.entityObject === param);
1688
1707
  if (!exists) {
1689
1708
  this.PendingRecords.push({
1690
1709
  entityObject: param,
1691
- action: 'delete'
1710
+ action: 'delete',
1692
1711
  });
1693
1712
  }
1694
1713
  }
@@ -1697,11 +1716,11 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1697
1716
  for (const resultCode of this.resultCodes) {
1698
1717
  if (!resultCode.IsSaved || resultCode.Dirty) {
1699
1718
  // Check if not already in pending records
1700
- const exists = this.PendingRecords.some(pr => pr.entityObject === resultCode);
1719
+ const exists = this.PendingRecords.some((pr) => pr.entityObject === resultCode);
1701
1720
  if (!exists) {
1702
1721
  this.PendingRecords.push({
1703
1722
  entityObject: resultCode,
1704
- action: 'save'
1723
+ action: 'save',
1705
1724
  });
1706
1725
  }
1707
1726
  }
@@ -1710,11 +1729,11 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1710
1729
  for (const resultCode of this.resultCodesToDelete) {
1711
1730
  if (resultCode.IsSaved) {
1712
1731
  // Check if not already in pending records
1713
- const exists = this.PendingRecords.some(pr => pr.entityObject === resultCode);
1732
+ const exists = this.PendingRecords.some((pr) => pr.entityObject === resultCode);
1714
1733
  if (!exists) {
1715
1734
  this.PendingRecords.push({
1716
1735
  entityObject: resultCode,
1717
- action: 'delete'
1736
+ action: 'delete',
1718
1737
  });
1719
1738
  }
1720
1739
  }
@@ -1741,20 +1760,20 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1741
1760
  const dialogRef = this.dialogService.open({
1742
1761
  content: ActionResultCodeDialogComponent,
1743
1762
  width: 500,
1744
- appendTo: this.viewContainerRef
1763
+ appendTo: this.viewContainerRef,
1745
1764
  });
1746
1765
  const dialog = dialogRef.content.instance;
1747
1766
  dialog.resultCode = newResultCode;
1748
1767
  dialog.isNew = true;
1749
1768
  dialog.editMode = true;
1750
- dialogRef.result.subscribe(result => {
1769
+ dialogRef.result.subscribe((result) => {
1751
1770
  if (result && result.save) {
1752
1771
  // Add to local array
1753
1772
  this.resultCodes.push(newResultCode);
1754
1773
  // Add to pending records for saving
1755
1774
  this.PendingRecords.push({
1756
1775
  entityObject: newResultCode,
1757
- action: 'save'
1776
+ action: 'save',
1758
1777
  });
1759
1778
  this.cdr.detectChanges();
1760
1779
  }
@@ -1764,21 +1783,21 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1764
1783
  const dialogRef = this.dialogService.open({
1765
1784
  content: ActionResultCodeDialogComponent,
1766
1785
  width: 500,
1767
- appendTo: this.viewContainerRef
1786
+ appendTo: this.viewContainerRef,
1768
1787
  });
1769
1788
  const dialog = dialogRef.content.instance;
1770
1789
  dialog.resultCode = resultCode;
1771
1790
  dialog.isNew = false;
1772
1791
  dialog.editMode = this.EditMode;
1773
- dialogRef.result.subscribe(result => {
1792
+ dialogRef.result.subscribe((result) => {
1774
1793
  if (result && result.save && this.EditMode) {
1775
1794
  // Ensure it's in pending records if modified
1776
1795
  if (resultCode.Dirty) {
1777
- const exists = this.PendingRecords.some(pr => pr.entityObject === resultCode && pr.action === 'save');
1796
+ const exists = this.PendingRecords.some((pr) => pr.entityObject === resultCode && pr.action === 'save');
1778
1797
  if (!exists) {
1779
1798
  this.PendingRecords.push({
1780
1799
  entityObject: resultCode,
1781
- action: 'save'
1800
+ action: 'save',
1782
1801
  });
1783
1802
  }
1784
1803
  }
@@ -1813,12 +1832,12 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1813
1832
  // Add to pending records for deletion
1814
1833
  this.PendingRecords.push({
1815
1834
  entityObject: resultCode,
1816
- action: 'delete'
1835
+ action: 'delete',
1817
1836
  });
1818
1837
  }
1819
1838
  else {
1820
1839
  // For unsaved result codes, just remove from pending records
1821
- const pendingIndex = this.PendingRecords.findIndex(pr => pr.entityObject === resultCode && pr.action === 'save');
1840
+ const pendingIndex = this.PendingRecords.findIndex((pr) => pr.entityObject === resultCode && pr.action === 'save');
1822
1841
  if (pendingIndex >= 0) {
1823
1842
  this.PendingRecords.splice(pendingIndex, 1);
1824
1843
  }
@@ -1843,12 +1862,12 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
1843
1862
  // Add to pending records for deletion
1844
1863
  this.PendingRecords.push({
1845
1864
  entityObject: param,
1846
- action: 'delete'
1865
+ action: 'delete',
1847
1866
  });
1848
1867
  }
1849
1868
  else {
1850
1869
  // For unsaved params, just remove from pending records
1851
- const pendingIndex = this.PendingRecords.findIndex(pr => pr.entityObject === param && pr.action === 'save');
1870
+ const pendingIndex = this.PendingRecords.findIndex((pr) => pr.entityObject === param && pr.action === 'save');
1852
1871
  if (pendingIndex >= 0) {
1853
1872
  this.PendingRecords.splice(pendingIndex, 1);
1854
1873
  }
@@ -1878,7 +1897,7 @@ export { ActionFormComponentExtended };
1878
1897
  type: Component,
1879
1898
  args: [{ selector: 'mj-action-form', template: "<div class=\"record-form-container\">\n @if (record) {\n <form class=\"record-form\" #form=\"ngForm\">\n <mj-form-toolbar [form]=\"this\"></mj-form-toolbar>\n\n <!-- Main Content Area -->\n <div class=\"action-main-area\" style=\"display: flex; flex-direction: column; height: 100%; overflow-y: auto;\">\n \n <!-- Header Section -->\n <div class=\"action-header\" style=\"flex-shrink: 0; padding: 20px; background: #f8f9fa; border-bottom: 2px solid #e9ecef;\">\n <div style=\"display: flex; justify-content: space-between; align-items: flex-start; gap: 20px;\">\n \n <!-- Left: Action Info -->\n <div style=\"flex: 1; min-width: 0;\">\n <div style=\"display: flex; align-items: center; gap: 12px; margin-bottom: 8px;\">\n <i [class]=\"getActionIcon()\" [style.color]=\"getTypeColor()\" style=\"font-size: 1.4em;\"></i>\n @if (EditMode) {\n <kendo-textbox [(ngModel)]=\"record.Name\" \n name=\"actionName\"\n placeholder=\"Enter action name...\"\n style=\"font-size: 1.2em; font-weight: 600; min-width: 300px; flex: 1;\">\n </kendo-textbox>\n } @else {\n <h4 style=\"margin: 0; color: #495057; font-weight: 600; flex: 1;\">{{ record.Name || 'Untitled Action' }}</h4>\n <span class=\"status-badge\" [style.background-color]=\"getStatusColor()\" \n style=\"color: white; padding: 4px 10px; border-radius: 12px; font-size: 0.75em; font-weight: 500;\">\n {{ record.Status }}\n </span>\n }\n </div>\n \n <!-- Status and Type Editors when in edit mode -->\n @if (EditMode) {\n <div style=\"display: flex; gap: 16px; margin-bottom: 12px; flex-wrap: wrap;\">\n <div>\n <label style=\"display: block; margin-bottom: 4px; font-weight: 600; color: #495057; font-size: 0.9em;\">Status</label>\n <kendo-dropdownlist [(ngModel)]=\"record.Status\"\n name=\"actionStatus\"\n [data]=\"[{text: 'Active', value: 'Active'}, {text: 'Pending', value: 'Pending'}, {text: 'Disabled', value: 'Disabled'}]\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\"\n style=\"width: 150px;\">\n </kendo-dropdownlist>\n </div>\n <div>\n <label style=\"display: block; margin-bottom: 4px; font-weight: 600; color: #495057; font-size: 0.9em;\">\n Type <span style=\"color: #dc3545;\">*</span>\n </label>\n <kendo-dropdownlist [(ngModel)]=\"record.Type\"\n name=\"actionType\"\n [data]=\"[{text: 'Generated', value: 'Generated'}, {text: 'Custom', value: 'Custom'}]\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\"\n style=\"width: 150px;\">\n </kendo-dropdownlist>\n </div>\n <div>\n <label style=\"display: block; margin-bottom: 4px; font-weight: 600; color: #495057; font-size: 0.9em;\">\n Category <span style=\"color: #dc3545;\">*</span>\n </label>\n <kendo-dropdownlist [(ngModel)]=\"record.CategoryID\"\n name=\"categoryID\"\n [data]=\"[]\"\n placeholder=\"Select category...\"\n style=\"width: 200px;\">\n </kendo-dropdownlist>\n </div>\n </div>\n }\n \n @if (EditMode) {\n <kendo-textarea [(ngModel)]=\"record.Description\" \n name=\"actionDescription\"\n [rows]=\"2\"\n placeholder=\"Enter action description...\"\n style=\"width: 100%; max-width: 600px; margin-bottom: 12px;\">\n </kendo-textarea>\n } @else if (record.Description) {\n <p style=\"margin: 0 0 12px 0; color: #6c757d; font-size: 0.9em; line-height: 1.4;\">{{ record.Description }}</p>\n }\n \n <!-- Quick Config Row -->\n <div class=\"quick-config\" style=\"display: flex; align-items: center; gap: 16px; flex-wrap: wrap;\">\n @if (category) {\n <div class=\"config-item\" style=\"display: flex; align-items: center; gap: 6px; font-size: 0.85em;\">\n <i class=\"fa-solid fa-folder\" style=\"color: #6c757d;\"></i>\n <span style=\"color: #6c757d;\">Category:</span>\n <span style=\"color: #495057; font-weight: 500; cursor: pointer;\" (click)=\"navigateToCategory()\">\n {{ category.Name }}\n <i class=\"fa-solid fa-external-link\" style=\"font-size: 0.75em; margin-left: 4px;\"></i>\n </span>\n </div>\n }\n \n <div class=\"config-item\" style=\"display: flex; align-items: center; gap: 6px; font-size: 0.85em;\">\n <i class=\"fa-solid fa-cube\" style=\"color: #6c757d;\"></i>\n <span style=\"color: #6c757d;\">Type:</span>\n <span style=\"color: #495057; font-weight: 500;\">{{ record.Type }}</span>\n </div>\n \n @if (record.Type === 'Generated' && record.CodeApprovalStatus) {\n <div class=\"config-item\" style=\"display: flex; align-items: center; gap: 6px; font-size: 0.85em;\">\n <i [class]=\"'fa-solid ' + getApprovalStatusIcon()\" [style.color]=\"getApprovalStatusColor()\"></i>\n <span style=\"color: #6c757d;\">Code:</span>\n <span [style.color]=\"getApprovalStatusColor()\" style=\"font-weight: 500;\">{{ record.CodeApprovalStatus }}</span>\n </div>\n }\n \n @if (actionParams.length > 0) {\n <div class=\"config-item\" style=\"display: flex; align-items: center; gap: 6px; font-size: 0.85em;\">\n <i class=\"fa-solid fa-sliders\" style=\"color: #6c757d;\"></i>\n <span style=\"color: #495057; font-weight: 500;\">{{ actionParams.length }} Parameters</span>\n </div>\n }\n </div>\n </div>\n \n <!-- Right: Action Buttons -->\n <div class=\"action-buttons\" style=\"display: flex; flex-direction: column; gap: 8px; align-items: flex-end;\">\n <div style=\"display: flex; gap: 8px;\">\n @if (record.ID) {\n <button kendoButton themeColor=\"primary\" size=\"large\"\n (click)=\"openTestHarness()\"\n title=\"Open Run Harness\"\n [disabled]=\"record.Status !== 'Active'\">\n <i class=\"fa-solid fa-play\"></i> Run\n </button>\n }\n @if (EditMode && record.Type === 'Generated') {\n <button kendoButton themeColor=\"info\" size=\"medium\"\n (click)=\"regenerateCode()\"\n title=\"Regenerate Code\">\n <i class=\"fa-solid fa-robot\"></i> Regenerate\n </button>\n }\n </div>\n \n @if (EditMode && record.CodeApprovalStatus === 'Pending' && record.Type === 'Generated') {\n <div style=\"display: flex; gap: 8px;\">\n <button kendoButton themeColor=\"success\" size=\"small\"\n (click)=\"approveCode()\">\n <i class=\"fa-solid fa-check\"></i> Approve\n </button>\n <button kendoButton themeColor=\"error\" size=\"small\"\n (click)=\"rejectCode()\">\n <i class=\"fa-solid fa-times\"></i> Reject\n </button>\n </div>\n }\n \n @if (!EditMode && record.Status !== 'Active' && record.ID) {\n <div style=\"font-size: 0.75em; color: #dc3545; text-align: right;\">\n Action must be Active to execute\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Configuration Sections with Expansion Panels -->\n <div class=\"configuration-sections\" style=\"flex: 1; background: white; border-top: 2px solid #e9ecef; padding: 16px; min-height: 0;\">\n \n <!-- Parameters Section (FIRST) -->\n <kendo-expansionpanel \n [expanded]=\"true\"\n style=\"margin-bottom: 12px;\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span style=\"display: flex; align-items: center; gap: 8px; font-weight: 600;\">\n <i class=\"fa-solid fa-sliders\" style=\"color: #6c757d;\"></i>\n Parameters\n @if (actionParams.length > 0) {\n <span style=\"background: #17a2b8; color: white; padding: 2px 6px; border-radius: 10px; font-size: 0.7em;\">\n {{ actionParams.length }}\n </span>\n }\n </span>\n </ng-template>\n \n <div style=\"padding: 16px;\">\n @if (isLoadingParams) {\n <div class=\"loading-state\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Loading parameters...\n </div>\n } @else if (actionParams.length === 0) {\n <div class=\"empty-state\" style=\"padding: 30px; text-align: center;\">\n <i class=\"fa-solid fa-sliders\" style=\"font-size: 2em; color: #6c757d; opacity: 0.3;\"></i>\n <p style=\"margin: 12px 0 0 0; color: #6c757d;\">No parameters defined</p>\n @if (EditMode && record.IsSaved) {\n <p style=\"margin: 8px 0 0 0; font-size: 0.85em; color: #6c757d;\">Add parameters to define inputs and outputs for this action</p>\n }\n </div>\n } @else {\n <!-- Input Parameters Grid -->\n <div class=\"params-section\">\n <div class=\"params-header\">\n <h3><i class=\"fa-solid fa-sign-in-alt\"></i> Input Parameters</h3>\n @if (EditMode && record.IsSaved) {\n <button kendoButton fillMode=\"flat\" size=\"small\" (click)=\"addParameter('Input')\">\n <i class=\"fa-solid fa-plus\"></i> Add Input\n </button>\n }\n </div>\n \n @if (getInputParams().length === 0) {\n <div class=\"empty-state\" style=\"padding: 30px; text-align: center;\">\n <i class=\"fa-solid fa-inbox\" style=\"font-size: 2em; color: #6c757d; opacity: 0.3;\"></i>\n <p style=\"margin: 12px 0 0 0; color: #6c757d;\">No input parameters defined</p>\n </div>\n } @else {\n <div class=\"params-grid\">\n @for (param of getInputParams(); track param.ID) {\n <div class=\"param-card\" [class.required]=\"param.IsRequired\" \n [class.clickable]=\"true\"\n (click)=\"onParamClick(param, $event)\">\n <div class=\"param-header\">\n <span class=\"param-name\">{{ param.Name }}</span>\n <div class=\"param-badges\">\n @if (param.IsRequired) {\n <span class=\"required-badge\">Required</span>\n }\n @if (param.IsArray) {\n <span class=\"array-badge\">Array</span>\n }\n @if (EditMode) {\n <button class=\"param-edit-btn\" (click)=\"editParameter(param)\" title=\"Edit parameter\">\n <i class=\"fa-solid fa-edit\"></i>\n </button>\n <button class=\"param-delete-btn\" (click)=\"deleteParameter(param)\" title=\"Delete parameter\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n }\n </div>\n </div>\n <div class=\"param-details\">\n <div class=\"param-type\">{{ param.ValueType }}</div>\n @if (param.Description) {\n <div class=\"param-description\">{{ param.Description }}</div>\n }\n @if (param.DefaultValue) {\n <div class=\"param-default\">\n <span class=\"default-label\">Default:</span>\n <code>{{ param.DefaultValue }}</code>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Output Parameters Grid -->\n <div class=\"params-section\" style=\"margin-top: 24px;\" \n [class.params-section-compact]=\"getOutputParams().length === 0\">\n <div class=\"params-header\">\n <h3><i class=\"fa-solid fa-sign-out-alt\"></i> Output Parameters</h3>\n @if (EditMode && record.IsSaved) {\n <button kendoButton fillMode=\"flat\" size=\"small\" (click)=\"addParameter('Output')\">\n <i class=\"fa-solid fa-plus\"></i> Add Output\n </button>\n }\n </div>\n \n @if (getOutputParams().length === 0) {\n <div class=\"empty-state\" style=\"padding: 20px; text-align: center;\">\n <i class=\"fa-solid fa-inbox\" style=\"font-size: 2em; color: #6c757d; opacity: 0.3;\"></i>\n <p style=\"margin: 12px 0 0 0; color: #6c757d;\">No output parameters defined</p>\n </div>\n } @else {\n <div class=\"params-grid\">\n @for (param of getOutputParams(); track param.ID) {\n <div class=\"param-card\"\n [class.clickable]=\"true\"\n (click)=\"onParamClick(param, $event)\">\n <div class=\"param-header\">\n <span class=\"param-name\">{{ param.Name }}</span>\n <div class=\"param-badges\">\n @if (param.IsArray) {\n <span class=\"array-badge\">Array</span>\n }\n @if (EditMode) {\n <button class=\"param-edit-btn\" (click)=\"editParameter(param)\" title=\"Edit parameter\">\n <i class=\"fa-solid fa-edit\"></i>\n </button>\n <button class=\"param-delete-btn\" (click)=\"deleteParameter(param)\" title=\"Delete parameter\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n }\n </div>\n </div>\n <div class=\"param-details\">\n <div class=\"param-type\">{{ param.ValueType }}</div>\n @if (param.Description) {\n <div class=\"param-description\">{{ param.Description }}</div>\n }\n @if (param.DefaultValue) {\n <div class=\"param-default\">\n <span class=\"default-label\">Default:</span>\n <code>{{ param.DefaultValue }}</code>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n </kendo-expansionpanel>\n\n <!-- Code & Generation Section (Only for Generated type) -->\n @if (record.Type === 'Generated') {\n <kendo-expansionpanel \n [expanded]=\"expandedSections.code\"\n style=\"margin-bottom: 12px;\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span style=\"display: flex; align-items: center; gap: 8px; font-weight: 600;\">\n <i class=\"fa-solid fa-code\" style=\"color: #6c757d;\"></i>\n Code & Generation\n @if (record.CodeLocked) {\n <span style=\"background: #ffc107; color: #856404; padding: 2px 6px; border-radius: 10px; font-size: 0.7em;\">\n <i class=\"fa-solid fa-lock\"></i> Locked\n </span>\n }\n </span>\n </ng-template>\n \n <div style=\"padding: 16px;\">\n @if (EditMode) {\n <div class=\"generation-panel\">\n <h3><i class=\"fa-solid fa-robot\"></i> AI Generation</h3>\n <div class=\"prompt-section\">\n <label>User Prompt</label>\n <kendo-textarea [(ngModel)]=\"record.UserPrompt\"\n name=\"userPrompt\"\n [rows]=\"8\"\n placeholder=\"Describe what this action should do...\"\n style=\"width: 100%; min-height: 120px;\">\n </kendo-textarea>\n </div>\n <div class=\"comments-section\">\n <label>Internal Comments (not sent to AI)</label>\n <kendo-textarea [(ngModel)]=\"record.UserComments\"\n name=\"userComments\"\n [rows]=\"2\"\n placeholder=\"Internal notes...\"\n style=\"width: 100%;\">\n </kendo-textarea>\n </div>\n <div class=\"generation-controls\">\n <kendo-switch [(ngModel)]=\"record.CodeLocked\"\n name=\"codeLocked\">\n </kendo-switch>\n <label style=\"margin-left: 8px;\">Lock Code (prevent regeneration)</label>\n </div>\n </div>\n }\n \n <div class=\"code-editor-section\">\n <div class=\"code-toolbar\">\n <h3><i class=\"fa-solid fa-file-code\"></i> Action Code</h3>\n <div class=\"code-actions\">\n @if (record.CodeComments) {\n <button kendoButton fillMode=\"flat\" size=\"small\" (click)=\"toggleCodeComments()\">\n <i class=\"fa-solid fa-comment\"></i> \n {{ showCodeComments ? 'Hide' : 'Show' }} AI Comments\n </button>\n }\n <button kendoButton fillMode=\"flat\" size=\"small\" (click)=\"copyToClipboard(record.Code || '')\">\n <i class=\"fa-solid fa-copy\"></i> Copy\n </button>\n </div>\n </div>\n <mj-code-editor \n [(ngModel)]=\"record.Code\"\n name=\"actionCode\"\n [readonly]=\"!EditMode || record.CodeLocked\"\n [language]=\"codeLanguage\"\n [lineWrapping]=\"true\"\n style=\"height: 400px; width: 100%;\">\n </mj-code-editor>\n \n @if (showCodeComments && record.CodeComments) {\n <div class=\"code-comments\">\n <h4><i class=\"fa-solid fa-robot\"></i> AI Explanation</h4>\n <p>{{ record.CodeComments }}</p>\n </div>\n }\n \n @if (EditMode && record.CodeApprovalStatus === 'Rejected') {\n <div class=\"approval-comments\">\n <label>Rejection Comments</label>\n <kendo-textarea [(ngModel)]=\"record.CodeApprovalComments\"\n name=\"codeApprovalComments\"\n [rows]=\"2\"\n placeholder=\"Explain why the code was rejected...\"\n style=\"width: 100%;\">\n </kendo-textarea>\n </div>\n }\n </div>\n </div>\n </kendo-expansionpanel>\n }\n\n <!-- Result Codes Section -->\n <kendo-expansionpanel \n [expanded]=\"expandedSections.resultCodes\"\n style=\"margin-bottom: 12px;\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span style=\"display: flex; align-items: center; gap: 8px; font-weight: 600;\">\n <i class=\"fa-solid fa-flag-checkered\" style=\"color: #6c757d;\"></i>\n Result Codes\n @if (resultCodes.length > 0) {\n <span style=\"background: #28a745; color: white; padding: 2px 6px; border-radius: 10px; font-size: 0.7em;\">\n {{ resultCodes.length }}\n </span>\n }\n </span>\n </ng-template>\n \n <div style=\"padding: 16px;\">\n <!-- Add Result Code Button -->\n @if (EditMode && record.IsSaved) {\n <div style=\"display: flex; justify-content: flex-end; margin-bottom: 12px;\">\n <button kendoButton [primary]=\"true\" size=\"small\" (click)=\"addResultCode()\">\n <i class=\"fa-solid fa-plus\"></i> Add Result Code\n </button>\n </div>\n }\n \n @if (isLoadingResultCodes) {\n <div class=\"loading-state\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Loading result codes...\n </div>\n } @else if (resultCodes.length === 0) {\n <div class=\"empty-state\" style=\"padding: 30px; text-align: center;\">\n <i class=\"fa-solid fa-flag-checkered\" style=\"font-size: 2em; color: #6c757d; opacity: 0.3;\"></i>\n <p style=\"margin: 12px 0 0 0; color: #6c757d;\">No result codes defined</p>\n @if (EditMode && record.IsSaved) {\n <p style=\"margin: 8px 0 0 0; font-size: 0.85em; color: #6c757d;\">Add result codes to define possible outcomes</p>\n }\n </div>\n } @else {\n <div class=\"result-codes-grid\">\n @for (code of resultCodes; track code.ID) {\n <div class=\"result-code-card\" \n [class.success]=\"code.IsSuccess\" \n [class.failure]=\"!code.IsSuccess\"\n [class.clickable]=\"true\"\n (click)=\"onResultCodeClick(code, $event)\">\n <div class=\"result-icon\">\n <i [class]=\"code.IsSuccess ? 'fa-solid fa-check-circle' : 'fa-solid fa-times-circle'\"></i>\n </div>\n <div class=\"result-content\">\n <div class=\"result-code\">{{ code.ResultCode }}</div>\n @if (code.Description) {\n <div class=\"result-description\">{{ code.Description }}</div>\n }\n </div>\n @if (EditMode) {\n <div class=\"result-actions\">\n <button class=\"result-edit-btn\" (click)=\"editResultCode(code); $event.stopPropagation()\" title=\"Edit result code\">\n <i class=\"fa-solid fa-edit\"></i>\n </button>\n <button class=\"result-delete-btn\" (click)=\"deleteResultCode(code); $event.stopPropagation()\" title=\"Delete result code\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n </kendo-expansionpanel>\n\n <!-- Execution & Monitoring Section -->\n @if (record.IsSaved) {\n <kendo-expansionpanel \n [expanded]=\"expandedSections.execution\"\n style=\"margin-bottom: 12px;\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span style=\"display: flex; align-items: center; gap: 8px; font-weight: 600;\">\n <i class=\"fa-solid fa-chart-line\" style=\"color: #6c757d;\"></i>\n Execution & Monitoring\n </span>\n </ng-template>\n \n <div style=\"padding: 16px;\">\n @if (isLoadingExecutions) {\n <div class=\"loading-state\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Loading executions...\n </div>\n } @else if (recentExecutions.length === 0) {\n <div class=\"empty-state\" style=\"padding: 30px; text-align: center;\">\n <i class=\"fa-solid fa-chart-line\" style=\"font-size: 2em; color: #6c757d; opacity: 0.3;\"></i>\n <p style=\"margin: 12px 0 0 0; color: #6c757d;\">No executions yet</p>\n </div>\n } @else {\n <div class=\"execution-stats-row\">\n <div class=\"stat-box\">\n <i class=\"fa-solid fa-tachometer-alt\"></i>\n <div class=\"stat-info\">\n <div class=\"stat-label\" style=\"color: #212529;\">Avg Duration</div>\n <div class=\"stat-value\" style=\"color: #212529;\">{{ formatDuration(executionStats.avgDuration) }}</div>\n </div>\n </div>\n <div class=\"stat-box\">\n <i class=\"fa-solid fa-check-circle\" [style.color]=\"getSuccessRateColor()\"></i>\n <div class=\"stat-info\">\n <div class=\"stat-label\" style=\"color: #212529;\">Success Rate</div>\n <div class=\"stat-value\" [style.color]=\"getSuccessRateColor()\" style=\"font-weight: 600;\">{{ executionStats.successRate.toFixed(0) }}%</div>\n </div>\n </div>\n <div class=\"stat-box\">\n <i class=\"fa-solid fa-play-circle\"></i>\n <div class=\"stat-info\">\n <div class=\"stat-label\" style=\"color: #212529;\">Total Runs</div>\n <div class=\"stat-value\" style=\"color: #212529;\">{{ executionStats.totalRuns }}</div>\n </div>\n </div>\n </div>\n\n <h3 style=\"margin-top: 24px;\"><i class=\"fa-solid fa-history\"></i> Recent Executions</h3>\n <div class=\"executions-table\">\n <table>\n <thead>\n <tr>\n <th>Started</th>\n <th>Duration</th>\n <th>User</th>\n <th>Result</th>\n <th>Actions</th>\n </tr>\n </thead>\n <tbody>\n @for (execution of recentExecutions; track execution.ID) {\n <tr class=\"execution-row\" [class.success]=\"isExecutionSuccess(execution)\">\n <td>{{ execution.StartedAt | date:'short' }}</td>\n <td>\n @if (execution.EndedAt) {\n {{ formatDuration(getExecutionDuration(execution)) }}\n } @else {\n <span class=\"running\">Running...</span>\n }\n </td>\n <td>{{ execution.User }}</td>\n <td>\n <span class=\"result-code\" \n [class.success]=\"isExecutionSuccess(execution)\"\n [class.failure]=\"!isExecutionSuccess(execution)\">\n {{ execution.ResultCode }}\n </span>\n </td>\n <td>\n <button kendoButton fillMode=\"flat\" size=\"small\" (click)=\"navigateToExecution(execution.ID)\">\n <i class=\"fa-solid fa-external-link\"></i>\n </button>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n </kendo-expansionpanel>\n }\n\n <!-- Related Configuration Section -->\n @if (record.IsSaved) {\n <kendo-expansionpanel \n [expanded]=\"expandedSections.configuration\"\n style=\"margin-bottom: 12px;\">\n <ng-template kendoExpansionPanelTitleDirective>\n <span style=\"display: flex; align-items: center; gap: 8px; font-weight: 600;\">\n <i class=\"fa-solid fa-cogs\" style=\"color: #6c757d;\"></i>\n Related Configuration\n </span>\n </ng-template>\n \n <div style=\"padding: 16px;\">\n <!-- Libraries -->\n <div class=\"config-subsection\">\n <h3><i class=\"fa-solid fa-book\"></i> Libraries</h3>\n @if (isLoadingLibraries) {\n <div class=\"loading-state\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Loading libraries...\n </div>\n } @else if (actionLibraries.length === 0) {\n <div class=\"empty-state mini\">\n <p>No libraries configured</p>\n </div>\n } @else {\n <div class=\"library-cards\">\n @for (lib of libraries; track lib.ID; let i = $index) {\n <div class=\"library-card\" (click)=\"navigateToLibrary(lib.ID)\">\n <i class=\"fa-solid fa-book\"></i>\n <div class=\"library-info\">\n <div class=\"library-name\">{{ lib.Name }}</div>\n @if (actionLibraries[i].ItemsUsed) {\n <div class=\"library-items\">{{ actionLibraries[i].ItemsUsed }}</div>\n }\n </div>\n <i class=\"fa-solid fa-external-link\"></i>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Other Related Entities -->\n <div class=\"related-entities-grid\">\n <div class=\"related-entity-link\">\n <i class=\"fa-solid fa-shield-alt\"></i>\n <span>Authorizations</span>\n <span class=\"entity-count\">View</span>\n </div>\n <div class=\"related-entity-link\">\n <i class=\"fa-solid fa-layer-group\"></i>\n <span>Contexts</span>\n <span class=\"entity-count\">View</span>\n </div>\n <div class=\"related-entity-link\">\n <i class=\"fa-solid fa-calendar\"></i>\n <span>Scheduled Actions</span>\n <span class=\"entity-count\">View</span>\n </div>\n <div class=\"related-entity-link\">\n <i class=\"fa-solid fa-cube\"></i>\n <span>Entity Actions</span>\n <span class=\"entity-count\">View</span>\n </div>\n </div>\n </div>\n </kendo-expansionpanel>\n }\n </div>\n </div>\n </form>\n }\n</div>\n\n<!-- Action Test Harness -->\n@if (showTestHarness) {\n <kendo-window \n [width]=\"1200\" \n [height]=\"800\" \n [minWidth]=\"800\"\n [minHeight]=\"600\"\n [draggable]=\"true\"\n [resizable]=\"true\"\n [state]=\"'default'\"\n (close)=\"onTestHarnessVisibilityChanged(false)\"\n title=\"Run Action - {{ record.Name || 'Untitled' }}\">\n <mj-action-test-harness\n [action]=\"record\"\n [actionParams]=\"actionParams\"\n [isVisible]=\"showTestHarness\"\n (visibilityChange)=\"onTestHarnessVisibilityChanged($event)\">\n </mj-action-test-harness>\n </kendo-window>\n}", styles: ["/* Hero Header Section */\n.action-hero-header {\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n padding: 32px;\n margin: -20px -20px 24px -20px;\n border-radius: 0 0 16px 16px;\n box-shadow: 0 4px 20px rgba(0,0,0,0.1);\n}\n\n.hero-content {\n max-width: 1400px;\n margin: 0 auto;\n}\n\n.action-identity {\n display: flex;\n align-items: flex-start;\n gap: 24px;\n margin-bottom: 24px;\n}\n\n.action-icon-wrapper {\n width: 80px;\n height: 80px;\n border-radius: 16px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n background: rgba(255,255,255,0.2);\n backdrop-filter: blur(10px);\n}\n\n.action-icon-wrapper i {\n font-size: 36px;\n}\n\n.action-info {\n flex: 1;\n min-width: 0;\n}\n\n.action-title-row {\n display: flex;\n align-items: center;\n gap: 16px;\n margin-bottom: 12px;\n flex-wrap: wrap;\n}\n\n.action-title {\n margin: 0;\n font-size: 2em;\n font-weight: 600;\n color: white;\n}\n\n.action-name-input {\n font-size: 1.8em;\n font-weight: 600;\n background: rgba(255,255,255,0.2);\n border: 2px solid rgba(255,255,255,0.3);\n color: white;\n padding: 8px 16px;\n border-radius: 8px;\n min-width: 400px;\n}\n\n.action-name-input::placeholder {\n color: rgba(255,255,255,0.6);\n}\n\n.action-badges {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.status-badge, .type-badge, .approval-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n border-radius: 20px;\n font-size: 0.85em;\n font-weight: 500;\n background: rgba(255,255,255,0.2);\n backdrop-filter: blur(10px);\n border: 1px solid rgba(255,255,255,0.3);\n}\n\n.action-category {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n color: rgba(255,255,255,0.9);\n font-size: 0.95em;\n cursor: pointer;\n transition: all 0.2s;\n margin-bottom: 12px;\n}\n\n.action-category:hover {\n color: white;\n transform: translateX(4px);\n}\n\n.action-description {\n color: rgba(255,255,255,0.9);\n font-size: 1.05em;\n line-height: 1.5;\n margin: 0;\n}\n\n.action-description-input {\n width: 100%;\n max-width: 600px;\n background: rgba(255,255,255,0.2);\n border: 2px solid rgba(255,255,255,0.3);\n color: white;\n border-radius: 8px;\n}\n\n.action-description-input::placeholder {\n color: rgba(255,255,255,0.6);\n}\n\n/* Quick Stats */\n.action-stats {\n display: flex;\n gap: 24px;\n margin-bottom: 24px;\n flex-wrap: wrap;\n}\n\n.stat-card {\n background: rgba(255,255,255,0.1);\n backdrop-filter: blur(10px);\n border: 1px solid rgba(255,255,255,0.2);\n border-radius: 12px;\n padding: 16px 24px;\n display: flex;\n align-items: center;\n gap: 16px;\n min-width: 160px;\n}\n\n.stat-card i {\n font-size: 24px;\n color: rgba(255,255,255,0.8);\n}\n\n.stat-content {\n display: flex;\n flex-direction: column;\n}\n\n.stat-value {\n font-size: 1.4em;\n font-weight: 700;\n color: white;\n}\n\n.stat-label {\n font-size: 0.85em;\n color: rgba(255,255,255,0.7);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n/* Hero Actions */\n.hero-actions {\n display: flex;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.hero-actions kendo-button {\n backdrop-filter: blur(10px);\n}\n\n/* Main Content Sections */\n.action-content {\n padding: 0 20px 20px;\n}\n\n.content-section {\n background: white;\n border: 1px solid #e9ecef;\n border-radius: 12px;\n margin-bottom: 20px;\n overflow: hidden;\n transition: all 0.3s ease;\n}\n\n.content-section:hover {\n box-shadow: 0 4px 12px rgba(0,0,0,0.08);\n}\n\n.section-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 20px;\n background: #f8f9fa;\n cursor: pointer;\n user-select: none;\n transition: background 0.2s;\n}\n\n.section-header:hover {\n background: #e9ecef;\n}\n\n.section-header h2 {\n margin: 0;\n font-size: 1.3em;\n color: #2c3e50;\n flex: 1;\n}\n\n.section-header i:first-child {\n font-size: 1.2em;\n color: #6c757d;\n}\n\n.section-count {\n background: #007bff;\n color: white;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 0.85em;\n font-weight: 500;\n}\n\n.toggle-icon {\n color: #6c757d;\n transition: transform 0.3s;\n}\n\n.toggle-icon.rotated {\n transform: rotate(-90deg);\n}\n\n.section-content {\n padding: 24px;\n animation: slideDown 0.3s ease;\n}\n\n@keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Overview Section */\n.overview-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 20px;\n}\n\n.overview-field {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.overview-field label {\n font-weight: 600;\n color: #495057;\n font-size: 0.9em;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.required {\n color: #dc3545;\n}\n\n.full-width {\n width: 100%;\n}\n\n.overview-display {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 24px;\n}\n\n.display-field {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.display-field label {\n font-size: 0.85em;\n color: #6c757d;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.display-value {\n font-size: 1.1em;\n color: #2c3e50;\n}\n\n.display-value.code {\n font-family: 'Courier New', monospace;\n background: #f8f9fa;\n padding: 4px 8px;\n border-radius: 4px;\n}\n\n.approval-date {\n color: #6c757d;\n font-size: 0.85em;\n margin-left: 8px;\n}\n\n/* Code Section */\n.generation-panel {\n background: #f8f9fa;\n border: 1px solid #e9ecef;\n border-radius: 8px;\n padding: 20px;\n margin-bottom: 24px;\n}\n\n.generation-panel h3 {\n margin: 0 0 16px 0;\n color: #6f42c1;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.prompt-section, .comments-section {\n margin-bottom: 16px;\n}\n\n.prompt-section label, .comments-section label {\n display: block;\n margin-bottom: 8px;\n font-weight: 600;\n color: #495057;\n}\n\n.generation-controls {\n display: flex;\n align-items: center;\n gap: 12px;\n padding-top: 12px;\n border-top: 1px solid #dee2e6;\n}\n\n.code-locked-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n background: #ffc107;\n color: #856404;\n border-radius: 12px;\n font-size: 0.8em;\n font-weight: 500;\n}\n\n.code-editor-section {\n border: 1px solid #e9ecef;\n border-radius: 8px;\n overflow: hidden;\n}\n\n.code-toolbar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background: #f8f9fa;\n border-bottom: 1px solid #e9ecef;\n}\n\n.code-toolbar h3 {\n margin: 0;\n font-size: 1.1em;\n color: #495057;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.code-actions {\n display: flex;\n gap: 8px;\n}\n\n.code-comments {\n background: #e3f2fd;\n border: 1px solid #90caf9;\n border-radius: 8px;\n padding: 16px;\n margin-top: 16px;\n}\n\n.code-comments h4 {\n margin: 0 0 8px 0;\n color: #1976d2;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.code-comments p {\n margin: 0;\n color: #424242;\n line-height: 1.5;\n}\n\n.approval-comments {\n margin-top: 16px;\n}\n\n.approval-comments label {\n display: block;\n margin-bottom: 8px;\n font-weight: 600;\n color: #dc3545;\n}\n\n/* Parameters Section */\n.params-section {\n background: #f8f9fa;\n border-radius: 12px;\n padding: 20px;\n}\n\n.params-section.params-section-compact {\n padding: 12px 20px;\n}\n\n.params-section-compact .empty-state {\n padding: 12px !important;\n}\n\n.params-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n}\n\n.params-header h3 {\n margin: 0;\n color: #495057;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.params-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 16px;\n}\n\n.param-card {\n background: white;\n border: 2px solid #e9ecef;\n border-radius: 8px;\n padding: 16px;\n transition: all 0.2s;\n}\n\n.param-card:hover {\n border-color: #007bff;\n box-shadow: 0 2px 8px rgba(0,123,255,0.1);\n}\n\n.param-card.required {\n border-color: #ffc107;\n}\n\n.param-card.clickable {\n cursor: pointer;\n}\n\n.param-card.clickable:hover {\n background: #e7f3ff;\n border-color: #2196f3;\n transform: translateY(-1px);\n}\n\n.param-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n\n.param-name {\n font-weight: 600;\n color: #2c3e50;\n}\n\n.param-badges {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.param-edit-btn,\n.param-delete-btn {\n background: none;\n border: none;\n padding: 4px 8px;\n cursor: pointer;\n color: #6c757d;\n border-radius: 4px;\n transition: all 0.2s;\n}\n\n.param-edit-btn:hover {\n background: #e3f2fd;\n color: #2196f3;\n}\n\n.param-delete-btn:hover {\n background: #ffebee;\n color: #f44336;\n}\n\n.param-details {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.required-badge {\n background: #ffc107;\n color: #856404;\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 0.75em;\n font-weight: 500;\n}\n\n.array-badge {\n background: #6f42c1;\n color: white;\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 0.75em;\n font-weight: 500;\n}\n\n.param-type {\n color: #6c757d;\n font-size: 0.9em;\n margin-bottom: 8px;\n}\n\n.param-description {\n color: #495057;\n font-size: 0.9em;\n line-height: 1.4;\n margin-bottom: 8px;\n}\n\n.param-default {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 8px;\n padding-top: 8px;\n border-top: 1px solid #e9ecef;\n}\n\n.default-label {\n color: #6c757d;\n font-size: 0.85em;\n}\n\n.param-default code {\n background: #f8f9fa;\n padding: 2px 6px;\n border-radius: 4px;\n font-family: 'Courier New', monospace;\n color: #e83e8c;\n}\n\n\n/* Result Codes Section */\n.result-codes-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 16px;\n}\n\n.result-code-card {\n display: flex;\n align-items: flex-start;\n gap: 16px;\n padding: 16px;\n border: 2px solid #e9ecef;\n border-radius: 8px;\n background: white;\n transition: all 0.2s;\n position: relative;\n}\n\n.result-code-card.clickable {\n cursor: pointer;\n}\n\n.result-code-card:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px rgba(0,0,0,0.1);\n}\n\n.result-code-card.success {\n border-color: #28a745;\n background: #d4edda;\n}\n\n.result-code-card.failure {\n border-color: #dc3545;\n background: #f8d7da;\n}\n\n.result-actions {\n position: absolute;\n top: 8px;\n right: 8px;\n display: flex;\n gap: 4px;\n opacity: 0;\n transition: opacity 0.2s;\n}\n\n.result-code-card:hover .result-actions {\n opacity: 1;\n}\n\n.result-edit-btn,\n.result-delete-btn {\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n padding: 4px 8px;\n cursor: pointer;\n transition: all 0.2s;\n font-size: 0.85em;\n}\n\n.result-edit-btn:hover {\n background: #007bff;\n color: white;\n border-color: #007bff;\n}\n\n.result-delete-btn:hover {\n background: #dc3545;\n color: white;\n border-color: #dc3545;\n}\n\n.result-icon {\n font-size: 1.5em;\n flex-shrink: 0;\n}\n\n.result-code-card.success .result-icon {\n color: #28a745;\n}\n\n.result-code-card.failure .result-icon {\n color: #dc3545;\n}\n\n.result-content {\n flex: 1;\n min-width: 0;\n}\n\n.result-code {\n font-weight: 600;\n color: #2c3e50;\n margin-bottom: 4px;\n font-family: 'Courier New', monospace;\n}\n\n.result-description {\n color: #495057;\n font-size: 0.9em;\n line-height: 1.4;\n}\n\n/* Execution Section */\n.execution-stats-row {\n display: flex;\n gap: 20px;\n margin-bottom: 32px;\n flex-wrap: wrap;\n}\n\n.stat-box {\n flex: 1;\n min-width: 200px;\n background: #f8f9fa;\n border: 1px solid #e9ecef;\n border-radius: 8px;\n padding: 20px;\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.stat-box i {\n font-size: 2em;\n color: #6c757d;\n}\n\n.stat-info {\n flex: 1;\n}\n\n.executions-table {\n overflow-x: auto;\n border: 1px solid #e9ecef;\n border-radius: 8px;\n}\n\n.executions-table table {\n width: 100%;\n border-collapse: collapse;\n}\n\n.executions-table th {\n background: #f8f9fa;\n padding: 12px;\n text-align: left;\n font-weight: 600;\n color: #495057;\n border-bottom: 2px solid #e9ecef;\n}\n\n.executions-table td {\n padding: 12px;\n border-bottom: 1px solid #e9ecef;\n}\n\n.execution-row {\n transition: background 0.2s;\n}\n\n.execution-row:hover {\n background: #f8f9fa;\n}\n\n.execution-row.success {\n background: #d4edda20;\n}\n\n.running {\n color: #ffc107;\n font-style: italic;\n}\n\n.result-code {\n display: inline-block;\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 0.85em;\n font-weight: 500;\n font-family: 'Courier New', monospace;\n}\n\n.result-code.success {\n background: #d4edda;\n color: #155724;\n}\n\n.result-code.failure {\n background: #f8d7da;\n color: #721c24;\n}\n\n/* Configuration Section */\n.config-subsection {\n margin-bottom: 32px;\n}\n\n.config-subsection h3 {\n margin: 0 0 16px 0;\n color: #495057;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.library-cards {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.library-card {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 16px;\n background: #f8f9fa;\n border: 1px solid #e9ecef;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.library-card:hover {\n background: #e9ecef;\n transform: translateX(4px);\n}\n\n.library-card i:first-child {\n font-size: 1.5em;\n color: #6c757d;\n}\n\n.library-info {\n flex: 1;\n min-width: 0;\n}\n\n.library-name {\n font-weight: 600;\n color: #2c3e50;\n margin-bottom: 4px;\n}\n\n.library-items {\n color: #6c757d;\n font-size: 0.9em;\n font-family: 'Courier New', monospace;\n}\n\n.related-entities-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 12px;\n}\n\n.related-entity-link {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px;\n background: #f8f9fa;\n border: 1px solid #e9ecef;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.related-entity-link:hover {\n background: #e9ecef;\n border-color: #007bff;\n}\n\n.related-entity-link i {\n font-size: 1.2em;\n color: #6c757d;\n}\n\n.related-entity-link span:first-of-type {\n flex: 1;\n font-weight: 500;\n color: #495057;\n}\n\n.entity-count {\n color: #007bff;\n font-size: 0.9em;\n}\n\n/* Common States */\n.loading-state {\n text-align: center;\n padding: 60px;\n color: #6c757d;\n}\n\n.loading-state i {\n font-size: 2em;\n margin-bottom: 12px;\n}\n\n.empty-state {\n text-align: center;\n padding: 60px;\n color: #6c757d;\n}\n\n.empty-state.mini {\n padding: 20px;\n}\n\n.empty-state i {\n font-size: 3em;\n margin-bottom: 16px;\n opacity: 0.3;\n}\n\n.empty-state p {\n margin: 0;\n font-size: 1.1em;\n}\n\n.empty-hint {\n margin-top: 8px !important;\n font-size: 0.9em !important;\n opacity: 0.7;\n}\n\n.no-params {\n text-align: center;\n padding: 20px;\n color: #6c757d;\n font-style: italic;\n}\n\n.no-params p {\n margin: 0;\n}\n\n/* Responsive Design */\n@media (max-width: 768px) {\n .action-hero-header {\n padding: 20px;\n }\n \n .action-identity {\n flex-direction: column;\n text-align: center;\n }\n \n .action-icon-wrapper {\n margin: 0 auto;\n }\n \n .action-title-row {\n justify-content: center;\n }\n \n .action-stats {\n justify-content: center;\n }\n \n .params-grid {\n grid-template-columns: 1fr;\n }\n}"] }]
1880
1899
  }], () => [{ type: i0.ElementRef }, { type: i1.SharedService }, { type: i2.Router }, { type: i2.ActivatedRoute }, { type: i0.ChangeDetectorRef }], null); })();
1881
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ActionFormComponentExtended, { className: "ActionFormComponentExtended", filePath: "src/lib/custom/Actions/action-form.component.ts", lineNumber: 19 }); })();
1900
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ActionFormComponentExtended, { className: "ActionFormComponentExtended", filePath: "src/lib/custom/Actions/action-form.component.ts", lineNumber: 27 }); })();
1882
1901
  // Loader function required for the component to be properly registered
1883
1902
  export function LoadActionFormComponentExtended() {
1884
1903
  // This function is called to ensure the form is loaded and registered