@memberjunction/ng-core-entity-forms 2.112.0 → 2.113.1
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 +10 -10
- package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-diagram.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-diagram.component.js +45 -45
- package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-diagram.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-form-section.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-form-section.component.js +7 -6
- package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-form-section.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/FlowAgentType/mj-integrated-flow-editor.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/FlowAgentType/mj-integrated-flow-editor.component.js +32 -17
- package/dist/lib/custom/AIAgents/FlowAgentType/mj-integrated-flow-editor.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/add-action-dialog.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/add-action-dialog.component.js +36 -37
- package/dist/lib/custom/AIAgents/add-action-dialog.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/agent-advanced-settings-dialog.component.js +2 -2
- package/dist/lib/custom/AIAgents/agent-advanced-settings-dialog.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/agent-permissions-dialog.component.d.ts +1 -1
- package/dist/lib/custom/AIAgents/agent-permissions-dialog.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/agent-permissions-dialog.component.js +25 -18
- package/dist/lib/custom/AIAgents/agent-permissions-dialog.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/agent-prompt-advanced-settings-dialog.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/agent-prompt-advanced-settings-dialog.component.js +11 -10
- package/dist/lib/custom/AIAgents/agent-prompt-advanced-settings-dialog.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/ai-agent-form.component.js +147 -159
- package/dist/lib/custom/AIAgents/ai-agent-form.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/create-prompt-dialog.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/create-prompt-dialog.component.js +10 -11
- package/dist/lib/custom/AIAgents/create-prompt-dialog.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/create-sub-agent-dialog.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/create-sub-agent-dialog.component.js +32 -36
- package/dist/lib/custom/AIAgents/create-sub-agent-dialog.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/new-agent-dialog.component.js +5 -5
- package/dist/lib/custom/AIAgents/new-agent-dialog.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/prompt-selector-dialog.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/prompt-selector-dialog.component.js +13 -15
- package/dist/lib/custom/AIAgents/prompt-selector-dialog.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/sub-agent-advanced-settings-dialog.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/sub-agent-advanced-settings-dialog.component.js +15 -13
- package/dist/lib/custom/AIAgents/sub-agent-advanced-settings-dialog.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.js +23 -28
- package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.js.map +1 -1
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.d.ts.map +1 -1
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js +12 -15
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js.map +1 -1
- package/dist/lib/custom/AIPrompts/ai-prompt-form.component.d.ts.map +1 -1
- package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js +86 -105
- package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js.map +1 -1
- package/dist/lib/custom/AIPrompts/template-selector-dialog.component.d.ts.map +1 -1
- package/dist/lib/custom/AIPrompts/template-selector-dialog.component.js +20 -13
- package/dist/lib/custom/AIPrompts/template-selector-dialog.component.js.map +1 -1
- package/dist/lib/custom/Actions/action-execution-log-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Actions/action-execution-log-form.component.js +7 -4
- package/dist/lib/custom/Actions/action-execution-log-form.component.js.map +1 -1
- package/dist/lib/custom/Actions/action-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Actions/action-form.component.js +80 -99
- package/dist/lib/custom/Actions/action-form.component.js.map +1 -1
- package/dist/lib/custom/Actions/action-test-harness.component.d.ts.map +1 -1
- package/dist/lib/custom/Actions/action-test-harness.component.js +17 -24
- package/dist/lib/custom/Actions/action-test-harness.component.js.map +1 -1
- package/dist/lib/custom/Queries/query-category-dialog.component.d.ts.map +1 -1
- package/dist/lib/custom/Queries/query-category-dialog.component.js +8 -8
- package/dist/lib/custom/Queries/query-category-dialog.component.js.map +1 -1
- package/dist/lib/custom/Queries/query-form.component.d.ts +2 -2
- package/dist/lib/custom/Queries/query-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Queries/query-form.component.js +44 -32
- package/dist/lib/custom/Queries/query-form.component.js.map +1 -1
- package/dist/lib/custom/Queries/query-run-dialog.component.d.ts.map +1 -1
- package/dist/lib/custom/Queries/query-run-dialog.component.js +22 -24
- package/dist/lib/custom/Queries/query-run-dialog.component.js.map +1 -1
- package/dist/lib/custom/Templates/template-param-dialog.component.d.ts.map +1 -1
- package/dist/lib/custom/Templates/template-param-dialog.component.js +21 -15
- package/dist/lib/custom/Templates/template-param-dialog.component.js.map +1 -1
- package/dist/lib/custom/Templates/template-params-grid.component.d.ts.map +1 -1
- package/dist/lib/custom/Templates/template-params-grid.component.js +17 -29
- package/dist/lib/custom/Templates/template-params-grid.component.js.map +1 -1
- package/dist/lib/custom/Templates/templates-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Templates/templates-form.component.js +26 -25
- package/dist/lib/custom/Templates/templates-form.component.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-analytics.component.d.ts.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-analytics.component.js +274 -335
- package/dist/lib/custom/ai-agent-run/ai-agent-run-analytics.component.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-cost.service.d.ts.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-cost.service.js +8 -8
- package/dist/lib/custom/ai-agent-run/ai-agent-run-cost.service.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-data.service.d.ts.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-data.service.js +28 -24
- package/dist/lib/custom/ai-agent-run/ai-agent-run-data.service.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-timeline.component.d.ts.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-timeline.component.js +30 -25
- package/dist/lib/custom/ai-agent-run/ai-agent-run-timeline.component.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.d.ts.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js +21 -20
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js.map +1 -1
- package/dist/lib/custom/shared/entity-selector-dialog.component.d.ts.map +1 -1
- package/dist/lib/custom/shared/entity-selector-dialog.component.js +7 -6
- package/dist/lib/custom/shared/entity-selector-dialog.component.js.map +1 -1
- package/dist/lib/generated/Entities/AIAgent/sections/aiagent-form-overview.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/AIAgent/sections/aiagent-form-overview.component.js +33 -47
- package/dist/lib/generated/Entities/AIAgent/sections/aiagent-form-overview.component.js.map +1 -1
- package/dist/lib/generated/Entities/AIAgent/sections/details.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/AIAgent/sections/details.component.js +31 -4
- package/dist/lib/generated/Entities/AIAgent/sections/details.component.js.map +1 -1
- package/dist/lib/generated/Entities/AIAgentExample/sections/details.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/AIAgentExample/sections/details.component.js +33 -4
- package/dist/lib/generated/Entities/AIAgentExample/sections/details.component.js.map +1 -1
- package/dist/lib/generated/Entities/AIAgentNote/sections/details.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/AIAgentNote/sections/details.component.js +33 -4
- package/dist/lib/generated/Entities/AIAgentNote/sections/details.component.js.map +1 -1
- package/dist/lib/generated/Entities/AIAgentRelationship/sections/details.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/AIAgentRelationship/sections/details.component.js +22 -4
- package/dist/lib/generated/Entities/AIAgentRelationship/sections/details.component.js.map +1 -1
- package/dist/lib/generated/Entities/AIAgentRun/aiagentrun.form.component.js +6 -6
- package/dist/lib/generated/Entities/AIAgentRun/aiagentrun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/AIConfiguration/aiconfiguration.form.component.js +8 -8
- package/dist/lib/generated/Entities/AIConfiguration/aiconfiguration.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/AIModel/aimodel.form.component.js +34 -14
- package/dist/lib/generated/Entities/AIModel/aimodel.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/ArtifactUse/artifactuse.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/ArtifactUse/artifactuse.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/ArtifactUse/artifactuse.form.component.js +59 -0
- package/dist/lib/generated/Entities/ArtifactUse/artifactuse.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/ArtifactUse/sections/details.component.d.ts +11 -0
- package/dist/lib/generated/Entities/ArtifactUse/sections/details.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/ArtifactUse/sections/details.component.js +129 -0
- package/dist/lib/generated/Entities/ArtifactUse/sections/details.component.js.map +1 -0
- package/dist/lib/generated/Entities/ArtifactVersion/artifactversion.form.component.js +24 -4
- package/dist/lib/generated/Entities/ArtifactVersion/artifactversion.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/CollectionArtifact/sections/details.component.js +10 -10
- package/dist/lib/generated/Entities/CollectionArtifact/sections/details.component.js.map +1 -1
- package/dist/lib/generated/Entities/ConversationArtifact/conversationartifact.form.component.js +6 -6
- package/dist/lib/generated/Entities/ConversationArtifact/conversationartifact.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/ConversationDetail/conversationdetail.form.component.js +18 -8
- package/dist/lib/generated/Entities/ConversationDetail/conversationdetail.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/ConversationDetailRating/conversationdetailrating.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/ConversationDetailRating/conversationdetailrating.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/ConversationDetailRating/conversationdetailrating.form.component.js +59 -0
- package/dist/lib/generated/Entities/ConversationDetailRating/conversationdetailrating.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/ConversationDetailRating/sections/details.component.d.ts +11 -0
- package/dist/lib/generated/Entities/ConversationDetailRating/sections/details.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/ConversationDetailRating/sections/details.component.js +120 -0
- package/dist/lib/generated/Entities/ConversationDetailRating/sections/details.component.js.map +1 -0
- package/dist/lib/generated/Entities/User/user.form.component.js +49 -29
- package/dist/lib/generated/Entities/User/user.form.component.js.map +1 -1
- package/dist/lib/generated/generated-forms.module.d.ts +336 -327
- package/dist/lib/generated/generated-forms.module.d.ts.map +1 -1
- package/dist/lib/generated/generated-forms.module.js +199 -126
- package/dist/lib/generated/generated-forms.module.js.map +1 -1
- package/dist/lib/shared/components/template-editor.component.d.ts.map +1 -1
- package/dist/lib/shared/components/template-editor.component.js +27 -26
- package/dist/lib/shared/components/template-editor.component.js.map +1 -1
- package/package.json +17 -16
|
@@ -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/
|
|
11
|
+
import { Metadata, RunView, CompositeKey } from '@memberjunction/core';
|
|
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,7 +1182,10 @@ 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([
|
|
1185
|
+
await Promise.all([
|
|
1186
|
+
this.loadActionParams(),
|
|
1187
|
+
this.loadResultCodes()
|
|
1188
|
+
]);
|
|
1186
1189
|
// Show success message
|
|
1187
1190
|
this.sharedService.CreateSimpleNotification('Action and related records saved successfully', 'success', 3000);
|
|
1188
1191
|
}
|
|
@@ -1216,16 +1219,16 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1216
1219
|
EntityName: 'Action Params',
|
|
1217
1220
|
ExtraFilter: `ActionID='${this.record.ID}'`,
|
|
1218
1221
|
OrderBy: 'Name',
|
|
1219
|
-
ResultType: 'entity_object'
|
|
1222
|
+
ResultType: 'entity_object' // This ensures we get proper entity instances
|
|
1220
1223
|
});
|
|
1221
1224
|
if (result.Success) {
|
|
1222
1225
|
this.actionParams = result.Results || [];
|
|
1223
1226
|
// Update cached filtered params - trim and lowercase Type values to handle any whitespace and case
|
|
1224
|
-
this._inputParams = this.actionParams.filter(
|
|
1227
|
+
this._inputParams = this.actionParams.filter(p => {
|
|
1225
1228
|
const type = p.Type?.trim().toLowerCase();
|
|
1226
1229
|
return type === 'input' || type === 'both';
|
|
1227
1230
|
});
|
|
1228
|
-
this._outputParams = this.actionParams.filter(
|
|
1231
|
+
this._outputParams = this.actionParams.filter(p => {
|
|
1229
1232
|
const type = p.Type?.trim().toLowerCase();
|
|
1230
1233
|
return type === 'output' || type === 'both';
|
|
1231
1234
|
});
|
|
@@ -1256,7 +1259,7 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1256
1259
|
EntityName: 'Action Result Codes',
|
|
1257
1260
|
ExtraFilter: `ActionID='${this.record.ID}'`,
|
|
1258
1261
|
OrderBy: 'IsSuccess DESC, ResultCode',
|
|
1259
|
-
ResultType: 'entity_object'
|
|
1262
|
+
ResultType: 'entity_object' // This ensures we get proper entity instances
|
|
1260
1263
|
});
|
|
1261
1264
|
if (result.Success) {
|
|
1262
1265
|
this.resultCodes = result.Results || [];
|
|
@@ -1282,7 +1285,7 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1282
1285
|
EntityName: 'Action Execution Logs',
|
|
1283
1286
|
ExtraFilter: `ActionID='${this.record.ID}'`,
|
|
1284
1287
|
OrderBy: 'StartedAt DESC',
|
|
1285
|
-
MaxRows: 10
|
|
1288
|
+
MaxRows: 10
|
|
1286
1289
|
});
|
|
1287
1290
|
if (result.Success) {
|
|
1288
1291
|
this.recentExecutions = result.Results || [];
|
|
@@ -1307,13 +1310,13 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1307
1310
|
const result = await rv.RunView({
|
|
1308
1311
|
EntityName: 'Action Libraries',
|
|
1309
1312
|
ExtraFilter: `ActionID='${this.record.ID}'`,
|
|
1310
|
-
OrderBy: 'Library'
|
|
1313
|
+
OrderBy: 'Library'
|
|
1311
1314
|
});
|
|
1312
1315
|
if (result.Success) {
|
|
1313
1316
|
this.actionLibraries = result.Results || [];
|
|
1314
1317
|
// Load library details
|
|
1315
1318
|
if (this.actionLibraries.length > 0) {
|
|
1316
|
-
const libraryIds = this.actionLibraries.map(
|
|
1319
|
+
const libraryIds = this.actionLibraries.map(al => al.LibraryID).filter(id => id);
|
|
1317
1320
|
const md = new Metadata();
|
|
1318
1321
|
this.libraries = [];
|
|
1319
1322
|
for (const libId of libraryIds) {
|
|
@@ -1340,20 +1343,21 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1340
1343
|
const result = await rv.RunView({
|
|
1341
1344
|
EntityName: 'Action Execution Logs',
|
|
1342
1345
|
ExtraFilter: `ActionID='${this.record.ID}'`,
|
|
1343
|
-
OrderBy: 'StartedAt DESC'
|
|
1346
|
+
OrderBy: 'StartedAt DESC'
|
|
1344
1347
|
});
|
|
1345
1348
|
if (result.Success && result.Results && result.Results.length > 0) {
|
|
1346
1349
|
const allExecutions = result.Results;
|
|
1347
1350
|
this.executionStats.totalRuns = allExecutions.length;
|
|
1348
1351
|
// Calculate success rate based on result codes
|
|
1349
|
-
const successfulRuns = allExecutions.filter(
|
|
1350
|
-
const resultCode = this.resultCodes.find(
|
|
1352
|
+
const successfulRuns = allExecutions.filter(e => {
|
|
1353
|
+
const resultCode = this.resultCodes.find(rc => rc.ResultCode === e.ResultCode);
|
|
1351
1354
|
return resultCode?.IsSuccess || false;
|
|
1352
1355
|
});
|
|
1353
|
-
this.executionStats.successRate =
|
|
1354
|
-
|
|
1356
|
+
this.executionStats.successRate = this.executionStats.totalRuns > 0
|
|
1357
|
+
? (successfulRuns.length / this.executionStats.totalRuns) * 100
|
|
1358
|
+
: 0;
|
|
1355
1359
|
// Calculate average duration from ALL completed executions
|
|
1356
|
-
const completedExecutions = allExecutions.filter(
|
|
1360
|
+
const completedExecutions = allExecutions.filter(e => e.StartedAt && e.EndedAt);
|
|
1357
1361
|
if (completedExecutions.length > 0) {
|
|
1358
1362
|
const totalDuration = completedExecutions.reduce((sum, e) => {
|
|
1359
1363
|
const duration = new Date(e.EndedAt).getTime() - new Date(e.StartedAt).getTime();
|
|
@@ -1373,26 +1377,18 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1373
1377
|
// UI Helper Methods
|
|
1374
1378
|
getStatusColor() {
|
|
1375
1379
|
switch (this.record.Status) {
|
|
1376
|
-
case 'Active':
|
|
1377
|
-
|
|
1378
|
-
case '
|
|
1379
|
-
|
|
1380
|
-
case 'Disabled':
|
|
1381
|
-
return '#dc3545';
|
|
1382
|
-
default:
|
|
1383
|
-
return '#6c757d';
|
|
1380
|
+
case 'Active': return '#28a745';
|
|
1381
|
+
case 'Pending': return '#ffc107';
|
|
1382
|
+
case 'Disabled': return '#dc3545';
|
|
1383
|
+
default: return '#6c757d';
|
|
1384
1384
|
}
|
|
1385
1385
|
}
|
|
1386
1386
|
getStatusIcon() {
|
|
1387
1387
|
switch (this.record.Status) {
|
|
1388
|
-
case 'Active':
|
|
1389
|
-
|
|
1390
|
-
case '
|
|
1391
|
-
|
|
1392
|
-
case 'Disabled':
|
|
1393
|
-
return 'fa-ban';
|
|
1394
|
-
default:
|
|
1395
|
-
return 'fa-question-circle';
|
|
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';
|
|
1396
1392
|
}
|
|
1397
1393
|
}
|
|
1398
1394
|
getTypeColor() {
|
|
@@ -1403,50 +1399,34 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1403
1399
|
}
|
|
1404
1400
|
getApprovalStatusColor() {
|
|
1405
1401
|
switch (this.record.CodeApprovalStatus) {
|
|
1406
|
-
case 'Approved':
|
|
1407
|
-
|
|
1408
|
-
case '
|
|
1409
|
-
|
|
1410
|
-
case 'Rejected':
|
|
1411
|
-
return '#dc3545';
|
|
1412
|
-
default:
|
|
1413
|
-
return '#6c757d';
|
|
1402
|
+
case 'Approved': return '#28a745';
|
|
1403
|
+
case 'Pending': return '#ffc107';
|
|
1404
|
+
case 'Rejected': return '#dc3545';
|
|
1405
|
+
default: return '#6c757d';
|
|
1414
1406
|
}
|
|
1415
1407
|
}
|
|
1416
1408
|
getApprovalStatusIcon() {
|
|
1417
1409
|
switch (this.record.CodeApprovalStatus) {
|
|
1418
|
-
case 'Approved':
|
|
1419
|
-
|
|
1420
|
-
case '
|
|
1421
|
-
|
|
1422
|
-
case 'Rejected':
|
|
1423
|
-
return 'fa-times-circle';
|
|
1424
|
-
default:
|
|
1425
|
-
return 'fa-question-circle';
|
|
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';
|
|
1426
1414
|
}
|
|
1427
1415
|
}
|
|
1428
1416
|
getParamTypeIcon(type) {
|
|
1429
1417
|
switch (type) {
|
|
1430
|
-
case 'Input':
|
|
1431
|
-
|
|
1432
|
-
case '
|
|
1433
|
-
|
|
1434
|
-
case 'Both':
|
|
1435
|
-
return 'fa-exchange-alt';
|
|
1436
|
-
default:
|
|
1437
|
-
return 'fa-question';
|
|
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';
|
|
1438
1422
|
}
|
|
1439
1423
|
}
|
|
1440
1424
|
getParamTypeColor(type) {
|
|
1441
1425
|
switch (type) {
|
|
1442
|
-
case 'Input':
|
|
1443
|
-
|
|
1444
|
-
case '
|
|
1445
|
-
|
|
1446
|
-
case 'Both':
|
|
1447
|
-
return '#6f42c1';
|
|
1448
|
-
default:
|
|
1449
|
-
return '#6c757d';
|
|
1426
|
+
case 'Input': return '#007bff';
|
|
1427
|
+
case 'Output': return '#28a745';
|
|
1428
|
+
case 'Both': return '#6f42c1';
|
|
1429
|
+
default: return '#6c757d';
|
|
1450
1430
|
}
|
|
1451
1431
|
}
|
|
1452
1432
|
formatDuration(ms) {
|
|
@@ -1557,7 +1537,7 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1557
1537
|
isExecutionSuccess(execution) {
|
|
1558
1538
|
const code = execution.ResultCode?.toLowerCase();
|
|
1559
1539
|
// First check if we have a result code definition
|
|
1560
|
-
const resultCode = this.resultCodes.find(
|
|
1540
|
+
const resultCode = this.resultCodes.find(rc => rc.ResultCode === execution.ResultCode);
|
|
1561
1541
|
if (resultCode) {
|
|
1562
1542
|
return resultCode.IsSuccess;
|
|
1563
1543
|
}
|
|
@@ -1597,13 +1577,13 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1597
1577
|
const dialogRef = this.dialogService.open({
|
|
1598
1578
|
content: ActionParamDialogComponent,
|
|
1599
1579
|
width: 500,
|
|
1600
|
-
appendTo: this.viewContainerRef
|
|
1580
|
+
appendTo: this.viewContainerRef
|
|
1601
1581
|
});
|
|
1602
1582
|
const dialog = dialogRef.content.instance;
|
|
1603
1583
|
dialog.param = newParam;
|
|
1604
1584
|
dialog.isNew = true;
|
|
1605
1585
|
dialog.editMode = true;
|
|
1606
|
-
dialogRef.result.subscribe(
|
|
1586
|
+
dialogRef.result.subscribe(result => {
|
|
1607
1587
|
if (result && result.save) {
|
|
1608
1588
|
// The dialog has already modified the newParam entity directly
|
|
1609
1589
|
// New entities are automatically dirty (IsSaved = false)
|
|
@@ -1612,7 +1592,7 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1612
1592
|
// Add to pending records for saving
|
|
1613
1593
|
this.PendingRecords.push({
|
|
1614
1594
|
entityObject: newParam,
|
|
1615
|
-
action: 'save'
|
|
1595
|
+
action: 'save'
|
|
1616
1596
|
});
|
|
1617
1597
|
// Update the filtered arrays
|
|
1618
1598
|
this.updateParamArrays();
|
|
@@ -1624,22 +1604,22 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1624
1604
|
const dialogRef = this.dialogService.open({
|
|
1625
1605
|
content: ActionParamDialogComponent,
|
|
1626
1606
|
width: 500,
|
|
1627
|
-
appendTo: this.viewContainerRef
|
|
1607
|
+
appendTo: this.viewContainerRef
|
|
1628
1608
|
});
|
|
1629
1609
|
const dialog = dialogRef.content.instance;
|
|
1630
1610
|
dialog.param = param;
|
|
1631
1611
|
dialog.isNew = false;
|
|
1632
1612
|
dialog.editMode = this.EditMode;
|
|
1633
|
-
dialogRef.result.subscribe(
|
|
1613
|
+
dialogRef.result.subscribe(result => {
|
|
1634
1614
|
if (result && result.save && this.EditMode) {
|
|
1635
1615
|
// Param will be dirty from property changes in dialog
|
|
1636
1616
|
// Ensure it's in pending records if modified
|
|
1637
1617
|
if (param.Dirty) {
|
|
1638
|
-
const exists = this.PendingRecords.some(
|
|
1618
|
+
const exists = this.PendingRecords.some(pr => pr.entityObject === param && pr.action === 'save');
|
|
1639
1619
|
if (!exists) {
|
|
1640
1620
|
this.PendingRecords.push({
|
|
1641
1621
|
entityObject: param,
|
|
1642
|
-
action: 'save'
|
|
1622
|
+
action: 'save'
|
|
1643
1623
|
});
|
|
1644
1624
|
}
|
|
1645
1625
|
}
|
|
@@ -1660,12 +1640,12 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1660
1640
|
}
|
|
1661
1641
|
async updateParamArrays() {
|
|
1662
1642
|
// Update cached filtered params - exclude deleted items
|
|
1663
|
-
const activeParams = this.actionParams.filter(
|
|
1664
|
-
this._inputParams = activeParams.filter(
|
|
1643
|
+
const activeParams = this.actionParams.filter(p => !this.paramsToDelete || !this.paramsToDelete.includes(p));
|
|
1644
|
+
this._inputParams = activeParams.filter(p => {
|
|
1665
1645
|
const type = p.Type?.trim().toLowerCase();
|
|
1666
1646
|
return type === 'input' || type === 'both';
|
|
1667
1647
|
});
|
|
1668
|
-
this._outputParams = activeParams.filter(
|
|
1648
|
+
this._outputParams = activeParams.filter(p => {
|
|
1669
1649
|
const type = p.Type?.trim().toLowerCase();
|
|
1670
1650
|
return type === 'output' || type === 'both';
|
|
1671
1651
|
});
|
|
@@ -1679,8 +1659,9 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1679
1659
|
// Re-add our preserved records
|
|
1680
1660
|
for (const record of currentPendingRecords) {
|
|
1681
1661
|
// Only re-add if it's an Action Param or Result Code (avoid duplicates)
|
|
1682
|
-
if (record.entityObject.EntityInfo.Name === 'Action Params' ||
|
|
1683
|
-
|
|
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);
|
|
1684
1665
|
if (!exists) {
|
|
1685
1666
|
this.PendingRecords.push(record);
|
|
1686
1667
|
}
|
|
@@ -1690,11 +1671,11 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1690
1671
|
for (const param of this.actionParams) {
|
|
1691
1672
|
if (!param.IsSaved || param.Dirty) {
|
|
1692
1673
|
// Check if not already in pending records
|
|
1693
|
-
const exists = this.PendingRecords.some(
|
|
1674
|
+
const exists = this.PendingRecords.some(pr => pr.entityObject === param);
|
|
1694
1675
|
if (!exists) {
|
|
1695
1676
|
this.PendingRecords.push({
|
|
1696
1677
|
entityObject: param,
|
|
1697
|
-
action: 'save'
|
|
1678
|
+
action: 'save'
|
|
1698
1679
|
});
|
|
1699
1680
|
}
|
|
1700
1681
|
}
|
|
@@ -1703,11 +1684,11 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1703
1684
|
for (const param of this.paramsToDelete) {
|
|
1704
1685
|
if (param.IsSaved) {
|
|
1705
1686
|
// Check if not already in pending records
|
|
1706
|
-
const exists = this.PendingRecords.some(
|
|
1687
|
+
const exists = this.PendingRecords.some(pr => pr.entityObject === param);
|
|
1707
1688
|
if (!exists) {
|
|
1708
1689
|
this.PendingRecords.push({
|
|
1709
1690
|
entityObject: param,
|
|
1710
|
-
action: 'delete'
|
|
1691
|
+
action: 'delete'
|
|
1711
1692
|
});
|
|
1712
1693
|
}
|
|
1713
1694
|
}
|
|
@@ -1716,11 +1697,11 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1716
1697
|
for (const resultCode of this.resultCodes) {
|
|
1717
1698
|
if (!resultCode.IsSaved || resultCode.Dirty) {
|
|
1718
1699
|
// Check if not already in pending records
|
|
1719
|
-
const exists = this.PendingRecords.some(
|
|
1700
|
+
const exists = this.PendingRecords.some(pr => pr.entityObject === resultCode);
|
|
1720
1701
|
if (!exists) {
|
|
1721
1702
|
this.PendingRecords.push({
|
|
1722
1703
|
entityObject: resultCode,
|
|
1723
|
-
action: 'save'
|
|
1704
|
+
action: 'save'
|
|
1724
1705
|
});
|
|
1725
1706
|
}
|
|
1726
1707
|
}
|
|
@@ -1729,11 +1710,11 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1729
1710
|
for (const resultCode of this.resultCodesToDelete) {
|
|
1730
1711
|
if (resultCode.IsSaved) {
|
|
1731
1712
|
// Check if not already in pending records
|
|
1732
|
-
const exists = this.PendingRecords.some(
|
|
1713
|
+
const exists = this.PendingRecords.some(pr => pr.entityObject === resultCode);
|
|
1733
1714
|
if (!exists) {
|
|
1734
1715
|
this.PendingRecords.push({
|
|
1735
1716
|
entityObject: resultCode,
|
|
1736
|
-
action: 'delete'
|
|
1717
|
+
action: 'delete'
|
|
1737
1718
|
});
|
|
1738
1719
|
}
|
|
1739
1720
|
}
|
|
@@ -1760,20 +1741,20 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1760
1741
|
const dialogRef = this.dialogService.open({
|
|
1761
1742
|
content: ActionResultCodeDialogComponent,
|
|
1762
1743
|
width: 500,
|
|
1763
|
-
appendTo: this.viewContainerRef
|
|
1744
|
+
appendTo: this.viewContainerRef
|
|
1764
1745
|
});
|
|
1765
1746
|
const dialog = dialogRef.content.instance;
|
|
1766
1747
|
dialog.resultCode = newResultCode;
|
|
1767
1748
|
dialog.isNew = true;
|
|
1768
1749
|
dialog.editMode = true;
|
|
1769
|
-
dialogRef.result.subscribe(
|
|
1750
|
+
dialogRef.result.subscribe(result => {
|
|
1770
1751
|
if (result && result.save) {
|
|
1771
1752
|
// Add to local array
|
|
1772
1753
|
this.resultCodes.push(newResultCode);
|
|
1773
1754
|
// Add to pending records for saving
|
|
1774
1755
|
this.PendingRecords.push({
|
|
1775
1756
|
entityObject: newResultCode,
|
|
1776
|
-
action: 'save'
|
|
1757
|
+
action: 'save'
|
|
1777
1758
|
});
|
|
1778
1759
|
this.cdr.detectChanges();
|
|
1779
1760
|
}
|
|
@@ -1783,21 +1764,21 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1783
1764
|
const dialogRef = this.dialogService.open({
|
|
1784
1765
|
content: ActionResultCodeDialogComponent,
|
|
1785
1766
|
width: 500,
|
|
1786
|
-
appendTo: this.viewContainerRef
|
|
1767
|
+
appendTo: this.viewContainerRef
|
|
1787
1768
|
});
|
|
1788
1769
|
const dialog = dialogRef.content.instance;
|
|
1789
1770
|
dialog.resultCode = resultCode;
|
|
1790
1771
|
dialog.isNew = false;
|
|
1791
1772
|
dialog.editMode = this.EditMode;
|
|
1792
|
-
dialogRef.result.subscribe(
|
|
1773
|
+
dialogRef.result.subscribe(result => {
|
|
1793
1774
|
if (result && result.save && this.EditMode) {
|
|
1794
1775
|
// Ensure it's in pending records if modified
|
|
1795
1776
|
if (resultCode.Dirty) {
|
|
1796
|
-
const exists = this.PendingRecords.some(
|
|
1777
|
+
const exists = this.PendingRecords.some(pr => pr.entityObject === resultCode && pr.action === 'save');
|
|
1797
1778
|
if (!exists) {
|
|
1798
1779
|
this.PendingRecords.push({
|
|
1799
1780
|
entityObject: resultCode,
|
|
1800
|
-
action: 'save'
|
|
1781
|
+
action: 'save'
|
|
1801
1782
|
});
|
|
1802
1783
|
}
|
|
1803
1784
|
}
|
|
@@ -1832,12 +1813,12 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1832
1813
|
// Add to pending records for deletion
|
|
1833
1814
|
this.PendingRecords.push({
|
|
1834
1815
|
entityObject: resultCode,
|
|
1835
|
-
action: 'delete'
|
|
1816
|
+
action: 'delete'
|
|
1836
1817
|
});
|
|
1837
1818
|
}
|
|
1838
1819
|
else {
|
|
1839
1820
|
// For unsaved result codes, just remove from pending records
|
|
1840
|
-
const pendingIndex = this.PendingRecords.findIndex(
|
|
1821
|
+
const pendingIndex = this.PendingRecords.findIndex(pr => pr.entityObject === resultCode && pr.action === 'save');
|
|
1841
1822
|
if (pendingIndex >= 0) {
|
|
1842
1823
|
this.PendingRecords.splice(pendingIndex, 1);
|
|
1843
1824
|
}
|
|
@@ -1862,12 +1843,12 @@ let ActionFormComponentExtended = class ActionFormComponentExtended extends Acti
|
|
|
1862
1843
|
// Add to pending records for deletion
|
|
1863
1844
|
this.PendingRecords.push({
|
|
1864
1845
|
entityObject: param,
|
|
1865
|
-
action: 'delete'
|
|
1846
|
+
action: 'delete'
|
|
1866
1847
|
});
|
|
1867
1848
|
}
|
|
1868
1849
|
else {
|
|
1869
1850
|
// For unsaved params, just remove from pending records
|
|
1870
|
-
const pendingIndex = this.PendingRecords.findIndex(
|
|
1851
|
+
const pendingIndex = this.PendingRecords.findIndex(pr => pr.entityObject === param && pr.action === 'save');
|
|
1871
1852
|
if (pendingIndex >= 0) {
|
|
1872
1853
|
this.PendingRecords.splice(pendingIndex, 1);
|
|
1873
1854
|
}
|
|
@@ -1897,7 +1878,7 @@ export { ActionFormComponentExtended };
|
|
|
1897
1878
|
type: Component,
|
|
1898
1879
|
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}"] }]
|
|
1899
1880
|
}], () => [{ type: i0.ElementRef }, { type: i1.SharedService }, { type: i2.Router }, { type: i2.ActivatedRoute }, { type: i0.ChangeDetectorRef }], null); })();
|
|
1900
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ActionFormComponentExtended, { className: "ActionFormComponentExtended", filePath: "src/lib/custom/Actions/action-form.component.ts", lineNumber:
|
|
1881
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ActionFormComponentExtended, { className: "ActionFormComponentExtended", filePath: "src/lib/custom/Actions/action-form.component.ts", lineNumber: 19 }); })();
|
|
1901
1882
|
// Loader function required for the component to be properly registered
|
|
1902
1883
|
export function LoadActionFormComponentExtended() {
|
|
1903
1884
|
// This function is called to ensure the form is loaded and registered
|