@memberjunction/ng-core-entity-forms 6.2.0-edge.4 → 6.2.0-edge.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts +7 -0
- package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/ai-agent-form.component.js +31 -17
- package/dist/lib/custom/AIAgents/ai-agent-form.component.js.map +1 -1
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.d.ts +7 -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 +191 -178
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js.map +1 -1
- package/dist/lib/custom/AIPromptRuns/prompt-run-data-capture-note.component.d.ts +48 -0
- package/dist/lib/custom/AIPromptRuns/prompt-run-data-capture-note.component.d.ts.map +1 -0
- package/dist/lib/custom/AIPromptRuns/prompt-run-data-capture-note.component.js +195 -0
- package/dist/lib/custom/AIPromptRuns/prompt-run-data-capture-note.component.js.map +1 -0
- package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js +324 -322
- package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js.map +1 -1
- package/dist/lib/custom/RecordProcesses/record-process-form.component.d.ts.map +1 -1
- package/dist/lib/custom/RecordProcesses/record-process-form.component.js +6 -3
- package/dist/lib/custom/RecordProcesses/record-process-form.component.js.map +1 -1
- package/dist/lib/custom/SearchScopes/searchscope-form.component.d.ts +3 -3
- package/dist/lib/custom/SearchScopes/searchscope-form.component.d.ts.map +1 -1
- package/dist/lib/custom/SearchScopes/searchscope-form.component.js +5 -7
- package/dist/lib/custom/SearchScopes/searchscope-form.component.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 +8 -8
- 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-step-detail.component.d.ts +37 -5
- package/dist/lib/custom/ai-agent-run/ai-agent-run-step-detail.component.d.ts.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-step-detail.component.js +155 -79
- package/dist/lib/custom/ai-agent-run/ai-agent-run-step-detail.component.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run-timeline.component.d.ts +8 -0
- 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 +59 -8
- 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 +34 -9
- 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 +164 -43
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/run-tree-timeline-projection.js +3 -1
- package/dist/lib/custom/ai-agent-run/run-tree-timeline-projection.js.map +1 -1
- package/dist/lib/custom/custom-forms.module.d.ts +82 -80
- package/dist/lib/custom/custom-forms.module.d.ts.map +1 -1
- package/dist/lib/custom/custom-forms.module.js +10 -0
- package/dist/lib/custom/custom-forms.module.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgent/mjaiagent.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgent/mjaiagent.form.component.js +65 -47
- package/dist/lib/generated/Entities/MJAIAgent/mjaiagent.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.js +115 -117
- package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentRunStep/mjaiagentrunstep.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentRunStep/mjaiagentrunstep.form.component.js +64 -24
- package/dist/lib/generated/Entities/MJAIAgentRunStep/mjaiagentrunstep.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentSession/mjaiagentsession.form.component.js +74 -52
- package/dist/lib/generated/Entities/MJAIAgentSession/mjaiagentsession.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentSessionRecordingShard/mjaiagentsessionrecordingshard.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJAIAgentSessionRecordingShard/mjaiagentsessionrecordingshard.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJAIAgentSessionRecordingShard/mjaiagentsessionrecordingshard.form.component.js +86 -0
- package/dist/lib/generated/Entities/MJAIAgentSessionRecordingShard/mjaiagentsessionrecordingshard.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJAIAgentUserPolicy/mjaiagentuserpolicy.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJAIAgentUserPolicy/mjaiagentuserpolicy.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJAIAgentUserPolicy/mjaiagentuserpolicy.form.component.js +132 -0
- package/dist/lib/generated/Entities/MJAIAgentUserPolicy/mjaiagentuserpolicy.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJAIBridgeAgentIdentity/mjaibridgeagentidentity.form.component.js +12 -10
- package/dist/lib/generated/Entities/MJAIBridgeAgentIdentity/mjaibridgeagentidentity.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIModel/mjaimodel.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIModel/mjaimodel.form.component.js +86 -32
- package/dist/lib/generated/Entities/MJAIModel/mjaimodel.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIPersona/mjaipersona.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIPersona/mjaipersona.form.component.js +25 -7
- package/dist/lib/generated/Entities/MJAIPersona/mjaipersona.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIPrompt/mjaiprompt.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIPrompt/mjaiprompt.form.component.js +180 -160
- package/dist/lib/generated/Entities/MJAIPrompt/mjaiprompt.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJActionParam/mjactionparam.form.component.js +16 -14
- package/dist/lib/generated/Entities/MJActionParam/mjactionparam.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJArchiveConfiguration/mjarchiveconfiguration.form.component.js +23 -21
- package/dist/lib/generated/Entities/MJArchiveConfiguration/mjarchiveconfiguration.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJArchiveRun/mjarchiverun.form.component.js +21 -19
- package/dist/lib/generated/Entities/MJArchiveRun/mjarchiverun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJCommunicationProvider/mjcommunicationprovider.form.component.js +30 -20
- package/dist/lib/generated/Entities/MJCommunicationProvider/mjcommunicationprovider.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJConversationDetail/mjconversationdetail.form.component.js +69 -75
- package/dist/lib/generated/Entities/MJConversationDetail/mjconversationdetail.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJCredential/mjcredential.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJCredential/mjcredential.form.component.js +35 -17
- package/dist/lib/generated/Entities/MJCredential/mjcredential.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJFeaturePipelineVersion/mjfeaturepipelineversion.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJFeaturePipelineVersion/mjfeaturepipelineversion.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJFeaturePipelineVersion/mjfeaturepipelineversion.form.component.js +130 -0
- package/dist/lib/generated/Entities/MJFeaturePipelineVersion/mjfeaturepipelineversion.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJFeatureValue/mjfeaturevalue.form.component.js +26 -14
- package/dist/lib/generated/Entities/MJFeatureValue/mjfeaturevalue.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJFeatureValueCache/mjfeaturevaluecache.form.component.js +23 -19
- package/dist/lib/generated/Entities/MJFeatureValueCache/mjfeaturevaluecache.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJProcessRun/mjprocessrun.form.component.js +29 -27
- package/dist/lib/generated/Entities/MJProcessRun/mjprocessrun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJProcessRunDetail/mjprocessrundetail.form.component.js +17 -15
- package/dist/lib/generated/Entities/MJProcessRunDetail/mjprocessrundetail.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJRecordProcess/mjrecordprocess.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJRecordProcess/mjrecordprocess.form.component.js +27 -9
- package/dist/lib/generated/Entities/MJRecordProcess/mjrecordprocess.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJTest/mjtest.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJTest/mjtest.form.component.js +24 -6
- package/dist/lib/generated/Entities/MJTest/mjtest.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJTestRun/mjtestrun.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJTestRun/mjtestrun.form.component.js +29 -11
- package/dist/lib/generated/Entities/MJTestRun/mjtestrun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJTheme/mjtheme.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJTheme/mjtheme.form.component.js +13 -3
- package/dist/lib/generated/Entities/MJTheme/mjtheme.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJUser/mjuser.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJUser/mjuser.form.component.js +176 -122
- package/dist/lib/generated/Entities/MJUser/mjuser.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJUserRoutine/mjuserroutine.form.component.js +31 -25
- package/dist/lib/generated/Entities/MJUserRoutine/mjuserroutine.form.component.js.map +1 -1
- package/dist/lib/generated/generated-forms.module.d.ts +129 -126
- package/dist/lib/generated/generated-forms.module.d.ts.map +1 -1
- package/dist/lib/generated/generated-forms.module.js +9 -0
- package/dist/lib/generated/generated-forms.module.js.map +1 -1
- package/dist/lib/panels/feature-values/feature-values.logic.d.ts +55 -0
- package/dist/lib/panels/feature-values/feature-values.logic.d.ts.map +1 -0
- package/dist/lib/panels/feature-values/feature-values.logic.js +88 -0
- package/dist/lib/panels/feature-values/feature-values.logic.js.map +1 -0
- package/dist/lib/panels/feature-values/feature-values.panel.d.ts +39 -0
- package/dist/lib/panels/feature-values/feature-values.panel.d.ts.map +1 -0
- package/dist/lib/panels/feature-values/feature-values.panel.js +303 -0
- package/dist/lib/panels/feature-values/feature-values.panel.js.map +1 -0
- package/dist/lib/shared/components/template-editor.component.js +2 -2
- package/dist/lib/shared/components/template-editor.component.js.map +1 -1
- package/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +48 -48
|
@@ -8,6 +8,8 @@ import { Component, ViewChild, inject } from '@angular/core';
|
|
|
8
8
|
import { Subject } from 'rxjs';
|
|
9
9
|
import { BaseEntity, CompositeKey, LogError, ResolveEntityEventRow } from '@memberjunction/core';
|
|
10
10
|
import { LoadAgentRunTree, MAX_AGENT_RUN_TREE_DEPTH, WalkAgentRunTree, } from '@memberjunction/ai-core-plus';
|
|
11
|
+
import { WorkflowSaveOperation } from '@memberjunction/core-entities';
|
|
12
|
+
import { AIEngineBase } from '@memberjunction/ai-engine-base';
|
|
11
13
|
import { BaseFormComponent } from '@memberjunction/ng-base-forms';
|
|
12
14
|
import { MJGlobal, MJEventType, RegisterClass, UUIDsEqual } from '@memberjunction/global';
|
|
13
15
|
import { SharedService, NavigationService } from '@memberjunction/ng-shared';
|
|
@@ -215,20 +217,20 @@ function MJAIAgentRunFormComponentExtended_Conditional_40_Template(rf, ctx) { if
|
|
|
215
217
|
function MJAIAgentRunFormComponentExtended_Conditional_55_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
216
218
|
const _r7 = i0.ɵɵgetCurrentView();
|
|
217
219
|
i0.ɵɵelementStart(0, "as-split-area", 53)(1, "mj-ai-agent-run-step-detail", 55);
|
|
218
|
-
i0.ɵɵlistener("closePanel", function MJAIAgentRunFormComponentExtended_Conditional_55_Conditional_4_Template_mj_ai_agent_run_step_detail_closePanel_1_listener() { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.closeJsonPanel()); })("navigateToActionLog", function MJAIAgentRunFormComponentExtended_Conditional_55_Conditional_4_Template_mj_ai_agent_run_step_detail_navigateToActionLog_1_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.navigateToActionLog($event)); })("copyToClipboard", function MJAIAgentRunFormComponentExtended_Conditional_55_Conditional_4_Template_mj_ai_agent_run_step_detail_copyToClipboard_1_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.copyToClipboard($event)); });
|
|
220
|
+
i0.ɵɵlistener("closePanel", function MJAIAgentRunFormComponentExtended_Conditional_55_Conditional_4_Template_mj_ai_agent_run_step_detail_closePanel_1_listener() { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.closeJsonPanel()); })("navigateToActionLog", function MJAIAgentRunFormComponentExtended_Conditional_55_Conditional_4_Template_mj_ai_agent_run_step_detail_navigateToActionLog_1_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.navigateToActionLog($event)); })("copyToClipboard", function MJAIAgentRunFormComponentExtended_Conditional_55_Conditional_4_Template_mj_ai_agent_run_step_detail_copyToClipboard_1_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.copyToClipboard($event)); })("SaveAsWorkflowRequested", function MJAIAgentRunFormComponentExtended_Conditional_55_Conditional_4_Template_mj_ai_agent_run_step_detail_SaveAsWorkflowRequested_1_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.OnSaveAsWorkflowRequested($event)); });
|
|
219
221
|
i0.ɵɵelementEnd()();
|
|
220
222
|
} if (rf & 2) {
|
|
221
223
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
222
224
|
i0.ɵɵproperty("size", 45);
|
|
223
225
|
i0.ɵɵadvance();
|
|
224
|
-
i0.ɵɵproperty("selectedTimelineItem", ctx_r0.selectedTimelineItem)("Provider", ctx_r0.ProviderToUse);
|
|
226
|
+
i0.ɵɵproperty("selectedTimelineItem", ctx_r0.selectedTimelineItem)("Provider", ctx_r0.ProviderToUse)("SavingWorkflow", ctx_r0.SavingWorkflow);
|
|
225
227
|
} }
|
|
226
228
|
function MJAIAgentRunFormComponentExtended_Conditional_55_Template(rf, ctx) { if (rf & 1) {
|
|
227
229
|
const _r6 = i0.ɵɵgetCurrentView();
|
|
228
230
|
i0.ɵɵelementStart(0, "div", 35)(1, "as-split", 52)(2, "as-split-area", 53)(3, "mj-ai-agent-run-timeline", 54);
|
|
229
231
|
i0.ɵɵlistener("itemSelected", function MJAIAgentRunFormComponentExtended_Conditional_55_Template_mj_ai_agent_run_timeline_itemSelected_3_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.selectTimelineItem($event)); })("navigateToEntity", function MJAIAgentRunFormComponentExtended_Conditional_55_Template_mj_ai_agent_run_timeline_navigateToEntity_3_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.navigateToEntityRecord($event)); });
|
|
230
232
|
i0.ɵɵelementEnd()();
|
|
231
|
-
i0.ɵɵconditionalCreate(4, MJAIAgentRunFormComponentExtended_Conditional_55_Conditional_4_Template, 2,
|
|
233
|
+
i0.ɵɵconditionalCreate(4, MJAIAgentRunFormComponentExtended_Conditional_55_Conditional_4_Template, 2, 4, "as-split-area", 53);
|
|
232
234
|
i0.ɵɵelementEnd()();
|
|
233
235
|
} if (rf & 2) {
|
|
234
236
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -739,7 +741,7 @@ function MJAIAgentRunFormComponentExtended_Conditional_58_Template(rf, ctx) { if
|
|
|
739
741
|
i0.ɵɵadvance(6);
|
|
740
742
|
i0.ɵɵtextInterpolate(ctx_r0.record.TotalPromptIterations != null ? i0.ɵɵpipeBind2(102, 45, ctx_r0.record.TotalPromptIterations, "1.0-0") : "N/A");
|
|
741
743
|
i0.ɵɵadvance(2);
|
|
742
|
-
i0.ɵɵconditional(ctx_r0.
|
|
744
|
+
i0.ɵɵconditional(ctx_r0.ShowResultPanel ? 103 : -1);
|
|
743
745
|
i0.ɵɵadvance();
|
|
744
746
|
i0.ɵɵconditional(ctx_r0.record.StartingPayload ? 104 : -1);
|
|
745
747
|
i0.ɵɵadvance();
|
|
@@ -790,6 +792,18 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
790
792
|
this._cachedParsedStartingPayload = null;
|
|
791
793
|
this._cachedParsedFinalPayload = null;
|
|
792
794
|
this._cachedParsedData = null;
|
|
795
|
+
this._cachedStartingPayloadRaw = undefined;
|
|
796
|
+
this._cachedStartingPayloadObject = null;
|
|
797
|
+
this._cachedFinalPayloadRaw = undefined;
|
|
798
|
+
this._cachedFinalPayloadObject = null;
|
|
799
|
+
this._cachedStepStartRaw = undefined;
|
|
800
|
+
this._cachedStepStartItem = null;
|
|
801
|
+
this._cachedStepPayloadAtStartObject = null;
|
|
802
|
+
this._cachedStepEndRaw = undefined;
|
|
803
|
+
this._cachedStepEndItem = null;
|
|
804
|
+
this._cachedStepPayloadAtEndObject = null;
|
|
805
|
+
this._lastRunTreeForWorkflowRunning = null;
|
|
806
|
+
this._cachedWorkflowStillRunning = false;
|
|
793
807
|
// Simple parsing state - true when all parsing is complete
|
|
794
808
|
this._allParsingComplete = false;
|
|
795
809
|
// Field injections
|
|
@@ -812,6 +826,8 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
812
826
|
this.RunTreeLoading = false;
|
|
813
827
|
/** Why the tree could not be loaded, or null. Surfaced rather than swallowed. */
|
|
814
828
|
this.RunTreeError = null;
|
|
829
|
+
/** True while a workflow is being saved via `WorkflowSaveOperation`. */
|
|
830
|
+
this.SavingWorkflow = false;
|
|
815
831
|
}
|
|
816
832
|
/** @deprecated Use {@link ActiveTab}. */
|
|
817
833
|
get activeTab() {
|
|
@@ -969,13 +985,20 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
969
985
|
get WorkflowStillRunning() {
|
|
970
986
|
if (!this.RunTree)
|
|
971
987
|
return false;
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
988
|
+
if (this._lastRunTreeForWorkflowRunning !== this.RunTree) {
|
|
989
|
+
this._lastRunTreeForWorkflowRunning = this.RunTree;
|
|
990
|
+
let stillRunning = false;
|
|
991
|
+
for (const node of WalkAgentRunTree(this.RunTree)) {
|
|
992
|
+
if (node.NodeType !== 'Task' && node.NodeType !== 'TaskGraph')
|
|
993
|
+
continue;
|
|
994
|
+
if (!TERMINAL_TASK_STATUSES.has(node.Status)) {
|
|
995
|
+
stillRunning = true;
|
|
996
|
+
break;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
this._cachedWorkflowStillRunning = stillRunning;
|
|
977
1000
|
}
|
|
978
|
-
return
|
|
1001
|
+
return this._cachedWorkflowStillRunning;
|
|
979
1002
|
}
|
|
980
1003
|
/**
|
|
981
1004
|
* Re-reads the tree while a detached workflow is still moving, and stops when it settles.
|
|
@@ -1005,10 +1028,12 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
1005
1028
|
async ngOnInit() {
|
|
1006
1029
|
await super.ngOnInit();
|
|
1007
1030
|
if (this.record && this.record.ID) {
|
|
1008
|
-
await
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1031
|
+
await Promise.all([
|
|
1032
|
+
this.DataHelper.loadAgentRunData(this.record.ID),
|
|
1033
|
+
this.loadRunTree(),
|
|
1034
|
+
this.loadAgent(),
|
|
1035
|
+
this.loadCostMetrics()
|
|
1036
|
+
]);
|
|
1012
1037
|
// Parse all JSON fields on form load for instant access later
|
|
1013
1038
|
this.parseAllFields();
|
|
1014
1039
|
// If the run is in progress, subscribe to BaseEntity events so we
|
|
@@ -1190,6 +1215,12 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
1190
1215
|
if (!this.record?.AgentID)
|
|
1191
1216
|
return;
|
|
1192
1217
|
try {
|
|
1218
|
+
const cachedAgent = AIEngineBase.Instance?.Agents?.find(a => UUIDsEqual(a.ID, this.record.AgentID));
|
|
1219
|
+
if (cachedAgent) {
|
|
1220
|
+
this.Agent = cachedAgent;
|
|
1221
|
+
this.cdr.detectChanges();
|
|
1222
|
+
return;
|
|
1223
|
+
}
|
|
1193
1224
|
const md = this.ProviderToUse;
|
|
1194
1225
|
const agent = await md.GetEntityObject('MJ: AI Agents');
|
|
1195
1226
|
if (agent && await agent.Load(this.record.AgentID)) {
|
|
@@ -1379,6 +1410,44 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
1379
1410
|
async copyToClipboard(text) {
|
|
1380
1411
|
return this.CopyToClipboard(text);
|
|
1381
1412
|
}
|
|
1413
|
+
/**
|
|
1414
|
+
* Persists the selected `TaskGraph` step's `TaskGraphSpec` as a Draft Flow Agent workflow
|
|
1415
|
+
* via `WorkflowSaveOperation` and opens the resulting `MJ: AI Agents` record.
|
|
1416
|
+
*/
|
|
1417
|
+
async OnSaveAsWorkflowRequested(spec) {
|
|
1418
|
+
if (!spec || this.SavingWorkflow) {
|
|
1419
|
+
return;
|
|
1420
|
+
}
|
|
1421
|
+
this.SavingWorkflow = true;
|
|
1422
|
+
try {
|
|
1423
|
+
const name = spec.workflowName?.trim() ||
|
|
1424
|
+
this.SelectedTimelineItem?.title?.trim() ||
|
|
1425
|
+
(this.Agent?.Name ? `${this.Agent.Name} Workflow` : 'Saved Workflow');
|
|
1426
|
+
const workflowSpec = {
|
|
1427
|
+
name,
|
|
1428
|
+
description: `Saved from AI Agent Run ${this.record?.ID ?? ''}`.trim(),
|
|
1429
|
+
status: 'Draft',
|
|
1430
|
+
graph: { ...spec, workflowName: name },
|
|
1431
|
+
triggers: [],
|
|
1432
|
+
};
|
|
1433
|
+
const op = new WorkflowSaveOperation();
|
|
1434
|
+
const result = await op.Execute({ spec: workflowSpec }, { provider: this.ProviderToUse, user: this.ProviderToUse.CurrentUser });
|
|
1435
|
+
const output = result.Output;
|
|
1436
|
+
if (!result.Success || !output?.success || !output.agentID) {
|
|
1437
|
+
SharedService.Instance.CreateSimpleNotification(output?.errorMessage ?? result.ErrorMessage ?? 'Could not save workflow.', 'error', 5000);
|
|
1438
|
+
return;
|
|
1439
|
+
}
|
|
1440
|
+
SharedService.Instance.CreateSimpleNotification(`Saved workflow "${name}". Opening Flow Agent record…`, 'success', 3500);
|
|
1441
|
+
this.navigationService.OpenEntityRecord('MJ: AI Agents', CompositeKey.FromID(output.agentID));
|
|
1442
|
+
}
|
|
1443
|
+
catch (err) {
|
|
1444
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1445
|
+
SharedService.Instance.CreateSimpleNotification(`Failed to save workflow: ${msg}`, 'error', 5000);
|
|
1446
|
+
}
|
|
1447
|
+
finally {
|
|
1448
|
+
this.SavingWorkflow = false;
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1382
1451
|
/**
|
|
1383
1452
|
* Get the Result field with recursive JSON parsing applied
|
|
1384
1453
|
*/
|
|
@@ -1557,18 +1626,23 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
1557
1626
|
* Get parsed Starting Payload as an object for deep diff
|
|
1558
1627
|
*/
|
|
1559
1628
|
get StartingPayloadObject() {
|
|
1560
|
-
|
|
1629
|
+
const raw = this.record?.StartingPayload;
|
|
1630
|
+
if (!raw)
|
|
1561
1631
|
return null;
|
|
1632
|
+
if (this._cachedStartingPayloadRaw === raw && this._cachedStartingPayloadObject !== null) {
|
|
1633
|
+
return this._cachedStartingPayloadObject;
|
|
1634
|
+
}
|
|
1635
|
+
this._cachedStartingPayloadRaw = raw;
|
|
1562
1636
|
try {
|
|
1563
1637
|
// First, check if StartingPayload is a JSON string that needs to be parsed
|
|
1564
|
-
let payloadData =
|
|
1638
|
+
let payloadData = raw;
|
|
1565
1639
|
try {
|
|
1566
1640
|
// If StartingPayload is a JSON string, parse it first
|
|
1567
|
-
payloadData = JSON.parse(
|
|
1641
|
+
payloadData = JSON.parse(raw);
|
|
1568
1642
|
}
|
|
1569
1643
|
catch {
|
|
1570
1644
|
// If it's not valid JSON, use it as-is
|
|
1571
|
-
payloadData =
|
|
1645
|
+
payloadData = raw;
|
|
1572
1646
|
}
|
|
1573
1647
|
const parseOptions = {
|
|
1574
1648
|
extractInlineJson: true,
|
|
@@ -1576,9 +1650,11 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
1576
1650
|
debug: false
|
|
1577
1651
|
};
|
|
1578
1652
|
// Re-enabled ParseJSONRecursive with performance optimizations
|
|
1579
|
-
|
|
1653
|
+
this._cachedStartingPayloadObject = ParseJSONRecursive(payloadData, parseOptions);
|
|
1654
|
+
return this._cachedStartingPayloadObject;
|
|
1580
1655
|
}
|
|
1581
|
-
catch
|
|
1656
|
+
catch {
|
|
1657
|
+
this._cachedStartingPayloadObject = null;
|
|
1582
1658
|
return null;
|
|
1583
1659
|
}
|
|
1584
1660
|
}
|
|
@@ -1590,18 +1666,23 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
1590
1666
|
* Get parsed Final Payload as an object for deep diff
|
|
1591
1667
|
*/
|
|
1592
1668
|
get FinalPayloadObject() {
|
|
1593
|
-
|
|
1669
|
+
const raw = this.record?.FinalPayload;
|
|
1670
|
+
if (!raw)
|
|
1594
1671
|
return null;
|
|
1672
|
+
if (this._cachedFinalPayloadRaw === raw && this._cachedFinalPayloadObject !== null) {
|
|
1673
|
+
return this._cachedFinalPayloadObject;
|
|
1674
|
+
}
|
|
1675
|
+
this._cachedFinalPayloadRaw = raw;
|
|
1595
1676
|
try {
|
|
1596
1677
|
// First, check if FinalPayload is a JSON string that needs to be parsed
|
|
1597
|
-
let payloadData =
|
|
1678
|
+
let payloadData = raw;
|
|
1598
1679
|
try {
|
|
1599
1680
|
// If FinalPayload is a JSON string, parse it first
|
|
1600
|
-
payloadData = JSON.parse(
|
|
1681
|
+
payloadData = JSON.parse(raw);
|
|
1601
1682
|
}
|
|
1602
1683
|
catch {
|
|
1603
1684
|
// If it's not valid JSON, use it as-is
|
|
1604
|
-
payloadData =
|
|
1685
|
+
payloadData = raw;
|
|
1605
1686
|
}
|
|
1606
1687
|
const parseOptions = {
|
|
1607
1688
|
extractInlineJson: true,
|
|
@@ -1609,9 +1690,11 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
1609
1690
|
debug: false
|
|
1610
1691
|
};
|
|
1611
1692
|
// Re-enabled ParseJSONRecursive with performance optimizations
|
|
1612
|
-
|
|
1693
|
+
this._cachedFinalPayloadObject = ParseJSONRecursive(payloadData, parseOptions);
|
|
1694
|
+
return this._cachedFinalPayloadObject;
|
|
1613
1695
|
}
|
|
1614
|
-
catch
|
|
1696
|
+
catch {
|
|
1697
|
+
this._cachedFinalPayloadObject = null;
|
|
1615
1698
|
return null;
|
|
1616
1699
|
}
|
|
1617
1700
|
}
|
|
@@ -1627,6 +1710,17 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
1627
1710
|
this._cachedParsedStartingPayload = null;
|
|
1628
1711
|
this._cachedParsedFinalPayload = null;
|
|
1629
1712
|
this._cachedParsedData = null;
|
|
1713
|
+
this._cachedStartingPayloadRaw = undefined;
|
|
1714
|
+
this._cachedStartingPayloadObject = null;
|
|
1715
|
+
this._cachedFinalPayloadRaw = undefined;
|
|
1716
|
+
this._cachedFinalPayloadObject = null;
|
|
1717
|
+
this._cachedStepStartRaw = undefined;
|
|
1718
|
+
this._cachedStepStartItem = null;
|
|
1719
|
+
this._cachedStepPayloadAtStartObject = null;
|
|
1720
|
+
this._cachedStepEndRaw = undefined;
|
|
1721
|
+
this._cachedStepEndItem = null;
|
|
1722
|
+
this._cachedStepPayloadAtEndObject = null;
|
|
1723
|
+
this._lastRunTreeForWorkflowRunning = null;
|
|
1630
1724
|
this._allParsingComplete = false;
|
|
1631
1725
|
}
|
|
1632
1726
|
/**
|
|
@@ -1635,8 +1729,8 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
1635
1729
|
parseAllFields() {
|
|
1636
1730
|
try {
|
|
1637
1731
|
let parsedCount = 0;
|
|
1638
|
-
// Parse
|
|
1639
|
-
if (this.
|
|
1732
|
+
// Parse each field whose panel is shown
|
|
1733
|
+
if (this.ShowResultPanel) {
|
|
1640
1734
|
this.ParsedResult; // Triggers parsing and caching
|
|
1641
1735
|
parsedCount++;
|
|
1642
1736
|
}
|
|
@@ -1678,6 +1772,13 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
1678
1772
|
get showPayloadDiff() {
|
|
1679
1773
|
return this.ShowPayloadDiff;
|
|
1680
1774
|
}
|
|
1775
|
+
/**
|
|
1776
|
+
* True for an older run that has `Result` but no `FinalPayload`. When `FinalPayload` is set it
|
|
1777
|
+
* holds the same JSON and has its own panel.
|
|
1778
|
+
*/
|
|
1779
|
+
get ShowResultPanel() {
|
|
1780
|
+
return !!this.record?.Result && !this.record?.FinalPayload;
|
|
1781
|
+
}
|
|
1681
1782
|
/**
|
|
1682
1783
|
* Check if selected timeline item is a step with payload changes
|
|
1683
1784
|
*/
|
|
@@ -1706,16 +1807,24 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
1706
1807
|
return null;
|
|
1707
1808
|
}
|
|
1708
1809
|
const stepData = this.SelectedTimelineItem.data;
|
|
1709
|
-
|
|
1810
|
+
const raw = stepData?.PayloadAtStart;
|
|
1811
|
+
if (!raw) {
|
|
1710
1812
|
return null;
|
|
1711
1813
|
}
|
|
1814
|
+
if (this._cachedStepStartItem === this.SelectedTimelineItem &&
|
|
1815
|
+
this._cachedStepStartRaw === raw &&
|
|
1816
|
+
this._cachedStepPayloadAtStartObject !== null) {
|
|
1817
|
+
return this._cachedStepPayloadAtStartObject;
|
|
1818
|
+
}
|
|
1819
|
+
this._cachedStepStartItem = this.SelectedTimelineItem;
|
|
1820
|
+
this._cachedStepStartRaw = raw;
|
|
1712
1821
|
try {
|
|
1713
|
-
let payloadData =
|
|
1822
|
+
let payloadData = raw;
|
|
1714
1823
|
try {
|
|
1715
|
-
payloadData = JSON.parse(
|
|
1824
|
+
payloadData = JSON.parse(raw);
|
|
1716
1825
|
}
|
|
1717
1826
|
catch {
|
|
1718
|
-
payloadData =
|
|
1827
|
+
payloadData = raw;
|
|
1719
1828
|
}
|
|
1720
1829
|
const parseOptions = {
|
|
1721
1830
|
extractInlineJson: true,
|
|
@@ -1723,9 +1832,11 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
1723
1832
|
debug: false
|
|
1724
1833
|
};
|
|
1725
1834
|
// Re-enabled ParseJSONRecursive with performance optimizations
|
|
1726
|
-
|
|
1835
|
+
this._cachedStepPayloadAtStartObject = ParseJSONRecursive(payloadData, parseOptions);
|
|
1836
|
+
return this._cachedStepPayloadAtStartObject;
|
|
1727
1837
|
}
|
|
1728
|
-
catch
|
|
1838
|
+
catch {
|
|
1839
|
+
this._cachedStepPayloadAtStartObject = null;
|
|
1729
1840
|
return null;
|
|
1730
1841
|
}
|
|
1731
1842
|
}
|
|
@@ -1741,16 +1852,24 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
1741
1852
|
return null;
|
|
1742
1853
|
}
|
|
1743
1854
|
const stepData = this.SelectedTimelineItem.data;
|
|
1744
|
-
|
|
1855
|
+
const raw = stepData?.PayloadAtEnd;
|
|
1856
|
+
if (!raw) {
|
|
1745
1857
|
return null;
|
|
1746
1858
|
}
|
|
1859
|
+
if (this._cachedStepEndItem === this.SelectedTimelineItem &&
|
|
1860
|
+
this._cachedStepEndRaw === raw &&
|
|
1861
|
+
this._cachedStepPayloadAtEndObject !== null) {
|
|
1862
|
+
return this._cachedStepPayloadAtEndObject;
|
|
1863
|
+
}
|
|
1864
|
+
this._cachedStepEndItem = this.SelectedTimelineItem;
|
|
1865
|
+
this._cachedStepEndRaw = raw;
|
|
1747
1866
|
try {
|
|
1748
|
-
let payloadData =
|
|
1867
|
+
let payloadData = raw;
|
|
1749
1868
|
try {
|
|
1750
|
-
payloadData = JSON.parse(
|
|
1869
|
+
payloadData = JSON.parse(raw);
|
|
1751
1870
|
}
|
|
1752
1871
|
catch {
|
|
1753
|
-
payloadData =
|
|
1872
|
+
payloadData = raw;
|
|
1754
1873
|
}
|
|
1755
1874
|
const parseOptions = {
|
|
1756
1875
|
extractInlineJson: true,
|
|
@@ -1758,9 +1877,11 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
1758
1877
|
debug: false
|
|
1759
1878
|
};
|
|
1760
1879
|
// Re-enabled ParseJSONRecursive with performance optimizations
|
|
1761
|
-
|
|
1880
|
+
this._cachedStepPayloadAtEndObject = ParseJSONRecursive(payloadData, parseOptions);
|
|
1881
|
+
return this._cachedStepPayloadAtEndObject;
|
|
1762
1882
|
}
|
|
1763
|
-
catch
|
|
1883
|
+
catch {
|
|
1884
|
+
this._cachedStepPayloadAtEndObject = null;
|
|
1764
1885
|
return null;
|
|
1765
1886
|
}
|
|
1766
1887
|
}
|
|
@@ -1775,7 +1896,7 @@ let MJAIAgentRunFormComponentExtended = class MJAIAgentRunFormComponentExtended
|
|
|
1775
1896
|
let _t;
|
|
1776
1897
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.TimelineComponent = _t.first);
|
|
1777
1898
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.AnalyticsComponent = _t.first);
|
|
1778
|
-
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 59, vars: 35, consts: [["analyticsComponent", ""], [1, "record-form-container", "ai-agent-run-form"], [1, "record-form"], [1, "header"], [1, "header-content"], [1, "header-left"], [1, "icon-wrapper"], [1, "agent-logo", 3, "src", "alt"], [1, "fas", 3, "ngClass"], [1, "fas", "fa-robot"], [1, "header-info"], [1, "meta-info"], [1, "agent-name"], [1, "run-id"], [1, "parent-run"], ["title", "Open conversation in Chat app", 1, "conversation-pill"], [1, "header-right"], ["title", "This run executed in Plan Mode \u2014 the agent presented a plan for human approval before executing actions or sub-agents", 1, "plan-mode-badge"], [1, "status-badge"], ["title", "This run submitted a workflow that runs on the dispatcher. The run finished when the workflow was submitted; the workflow itself is still going. This view refreshes on its own.", 1, "workflow-running-badge"], [1, "header-actions"], ["title", "Refresh", 1, "btn-icon", 3, "click"], [1, "fas", "fa-sync-alt"], [1, "header-stats"], [1, "stat"], [1, "label"], [1, "value"], [1, "configuration-bar"], [1, "tabs"], [1, "tab", 3, "click"], [1, "fas", "fa-stream"], [1, "fas", "fa-diagram-project"], [1, "fas", "fa-chart-line"], [1, "fas", "fa-info-circle"], [1, "content-area"], [1, "tab-content", 2, "height", "100%"], [1, "tab-content"], ["href", "javascript:void(0)", 1, "entity-link", 3, "click"], [1, "fas", "fa-level-up-alt"], [1, "parent-link", 3, "click"], ["title", "Open conversation in Chat app", 1, "conversation-pill", 3, "click"], [1, "fas", "fa-comments"], [1, "fas", "fa-external-link-alt", "pill-action"], [1, "fas", "fa-clipboard-check"], [1, "fas", "fa-circle-notch", "fa-spin"], [1, "value", "loading"], [1, "fas", "fa-spinner", "fa-spin"], [1, "config-item"], [1, "fas", "fa-cog"], [1, "config-content"], [1, "config-label"], [1, "config-value"], ["direction", "horizontal", 2, "height", "100%"], [3, "size"], [3, "itemSelected", "navigateToEntity", "aiAgentRunId", "dataHelper", "RunTree"], [3, "closePanel", "navigateToActionLog", "copyToClipboard", "selectedTimelineItem", "Provider"], [3, "aiAgentRunId", "dataHelper", "agentName", "runStatus", "agentIconClass", "agentLogoUrl", "RunTree"], [3, "agentRunId", "RunTree"], [3, "Expanded"], ["mjAccordionTitle", ""], [1, "details-grid"], [1, "detail-item"], ["href", "javascript:void(0)", 1, "entity-link"], [1, "success"], [1, "error-message"], [1, "detail-item", "full-width"], [1, "fas", "fa-cogs"], [1, "fas", "fa-tasks"], [1, "message"], [1, "fas", "fa-dollar-sign"], [1, "result-viewer"], [2, "height", "300px", "width", "100%", 3, "ngModel", "language", "readonly"], [2, "padding", "20px", "text-align", "center", "color", "var(--mj-text-muted)"], [1, "fas", "fa-code"], [1, "fas", "fa-upload"], [1, "fas", "fa-database"], [1, "fas", "fa-download"], [2, "padding", "20px", "background", "var(--mj-bg-surface-card)"], [3, "oldValue", "newValue", "title", "showSummary", "showUnchanged", "expandAll", "maxDepth", "maxStringLength", "treatNullAsUndefined"], [1, "fas", "fa-code-compare"]], template: function MJAIAgentRunFormComponentExtended_Template(rf, ctx) { if (rf & 1) {
|
|
1899
|
+
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 59, vars: 35, consts: [["analyticsComponent", ""], [1, "record-form-container", "ai-agent-run-form"], [1, "record-form"], [1, "header"], [1, "header-content"], [1, "header-left"], [1, "icon-wrapper"], [1, "agent-logo", 3, "src", "alt"], [1, "fas", 3, "ngClass"], [1, "fas", "fa-robot"], [1, "header-info"], [1, "meta-info"], [1, "agent-name"], [1, "run-id"], [1, "parent-run"], ["title", "Open conversation in Chat app", 1, "conversation-pill"], [1, "header-right"], ["title", "This run executed in Plan Mode \u2014 the agent presented a plan for human approval before executing actions or sub-agents", 1, "plan-mode-badge"], [1, "status-badge"], ["title", "This run submitted a workflow that runs on the dispatcher. The run finished when the workflow was submitted; the workflow itself is still going. This view refreshes on its own.", 1, "workflow-running-badge"], [1, "header-actions"], ["title", "Refresh", 1, "btn-icon", 3, "click"], [1, "fas", "fa-sync-alt"], [1, "header-stats"], [1, "stat"], [1, "label"], [1, "value"], [1, "configuration-bar"], [1, "tabs"], [1, "tab", 3, "click"], [1, "fas", "fa-stream"], [1, "fas", "fa-diagram-project"], [1, "fas", "fa-chart-line"], [1, "fas", "fa-info-circle"], [1, "content-area"], [1, "tab-content", 2, "height", "100%"], [1, "tab-content"], ["href", "javascript:void(0)", 1, "entity-link", 3, "click"], [1, "fas", "fa-level-up-alt"], [1, "parent-link", 3, "click"], ["title", "Open conversation in Chat app", 1, "conversation-pill", 3, "click"], [1, "fas", "fa-comments"], [1, "fas", "fa-external-link-alt", "pill-action"], [1, "fas", "fa-clipboard-check"], [1, "fas", "fa-circle-notch", "fa-spin"], [1, "value", "loading"], [1, "fas", "fa-spinner", "fa-spin"], [1, "config-item"], [1, "fas", "fa-cog"], [1, "config-content"], [1, "config-label"], [1, "config-value"], ["direction", "horizontal", 2, "height", "100%"], [3, "size"], [3, "itemSelected", "navigateToEntity", "aiAgentRunId", "dataHelper", "RunTree"], [3, "closePanel", "navigateToActionLog", "copyToClipboard", "SaveAsWorkflowRequested", "selectedTimelineItem", "Provider", "SavingWorkflow"], [3, "aiAgentRunId", "dataHelper", "agentName", "runStatus", "agentIconClass", "agentLogoUrl", "RunTree"], [3, "agentRunId", "RunTree"], [3, "Expanded"], ["mjAccordionTitle", ""], [1, "details-grid"], [1, "detail-item"], ["href", "javascript:void(0)", 1, "entity-link"], [1, "success"], [1, "error-message"], [1, "detail-item", "full-width"], [1, "fas", "fa-cogs"], [1, "fas", "fa-tasks"], [1, "message"], [1, "fas", "fa-dollar-sign"], [1, "result-viewer"], [2, "height", "300px", "width", "100%", 3, "ngModel", "language", "readonly"], [2, "padding", "20px", "text-align", "center", "color", "var(--mj-text-muted)"], [1, "fas", "fa-code"], [1, "fas", "fa-upload"], [1, "fas", "fa-database"], [1, "fas", "fa-download"], [2, "padding", "20px", "background", "var(--mj-bg-surface-card)"], [3, "oldValue", "newValue", "title", "showSummary", "showUnchanged", "expandAll", "maxDepth", "maxStringLength", "treatNullAsUndefined"], [1, "fas", "fa-code-compare"]], template: function MJAIAgentRunFormComponentExtended_Template(rf, ctx) { if (rf & 1) {
|
|
1779
1900
|
i0.ɵɵelementStart(0, "div", 1)(1, "div", 2)(2, "div", 3)(3, "div", 4)(4, "div", 5)(5, "div", 6);
|
|
1780
1901
|
i0.ɵɵconditionalCreate(6, MJAIAgentRunFormComponentExtended_Conditional_6_Template, 1, 2, "img", 7);
|
|
1781
1902
|
i0.ɵɵconditionalCreate(7, MJAIAgentRunFormComponentExtended_Conditional_7_Template, 1, 1, "i", 8);
|
|
@@ -1910,7 +2031,7 @@ MJAIAgentRunFormComponentExtended = __decorate([
|
|
|
1910
2031
|
export { MJAIAgentRunFormComponentExtended };
|
|
1911
2032
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJAIAgentRunFormComponentExtended, [{
|
|
1912
2033
|
type: Component,
|
|
1913
|
-
args: [{ standalone: false, selector: 'mj-ai-agent-run-form', template: "<div class=\"record-form-container ai-agent-run-form\">\n <div class=\"record-form\">\n <!-- Header -->\n <div class=\"header\">\n <div class=\"header-content\">\n <div class=\"header-left\">\n <div class=\"icon-wrapper\">\n @if (agent && agent.LogoURL) {\n <img [src]=\"agent.LogoURL\" [alt]=\"agent.Name || 'Agent'\" class=\"agent-logo\" />\n }\n @if (agent && !agent.LogoURL && agent.IconClass) {\n <i class=\"fas\" [ngClass]=\"agent.IconClass\"></i>\n }\n @if (!agent || (!agent.LogoURL && !agent.IconClass)) {\n <i class=\"fas fa-robot\"></i>\n }\n </div>\n <div class=\"header-info\">\n <h2>AI Agent Run</h2>\n <div class=\"meta-info\">\n @if (agent) {\n <span class=\"agent-name\">\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: AI Agents', record.AgentID)\">\n {{ agent.Name }}\n </a>\n </span>\n }\n <span class=\"run-id\">{{ record.ID }}</span>\n @if (record.ParentRunID) {\n <span class=\"parent-run\">\n <i class=\"fas fa-level-up-alt\"></i>\n <a (click)=\"navigateToParentRun()\" class=\"parent-link\">Parent Run</a>\n </span>\n }\n <!-- Conversation Link Pill -->\n @if (record.ConversationID) {\n <span class=\"conversation-pill\" (click)=\"navigateToConversation()\" title=\"Open conversation in Chat app\">\n <i class=\"fas fa-comments\"></i>\n <span>Conversation</span>\n <i class=\"fas fa-external-link-alt pill-action\"></i>\n </span>\n }\n </div>\n </div>\n </div>\n <div class=\"header-right\">\n @if (record.PlanMode) {\n <div class=\"plan-mode-badge\" title=\"This run executed in Plan Mode \u2014 the agent presented a plan for human approval before executing actions or sub-agents\">\n <i class=\"fas fa-clipboard-check\"></i>\n Plan Mode\n </div>\n }\n <div class=\"status-badge\" [attr.data-status]=\"record.Status\">\n <i class=\"fas\" [ngClass]=\"getStatusIcon(record.Status || '')\"></i>\n {{ record.Status }}\n </div>\n <!-- A workflow outlives the run that submitted it, so a Completed run can still have work\n in flight. Said beside the status rather than instead of it \u2014 both are true. -->\n @if (WorkflowStillRunning) {\n <div class=\"workflow-running-badge\"\n title=\"This run submitted a workflow that runs on the dispatcher. The run finished when the workflow was submitted; the workflow itself is still going. This view refreshes on its own.\">\n <i class=\"fas fa-circle-notch fa-spin\"></i>\n Workflow still running\n </div>\n }\n <div class=\"header-actions\">\n <button class=\"btn-icon\" (click)=\"refreshData()\" title=\"Refresh\">\n <i class=\"fas fa-sync-alt\"></i>\n </button>\n </div>\n </div>\n </div>\n <div class=\"header-stats\">\n <div class=\"stat\">\n <span class=\"label\">Started</span>\n <span class=\"value\">{{ record.StartedAt | date:'medium' }}</span>\n </div>\n @if (record.CompletedAt) {\n <div class=\"stat\">\n <span class=\"label\">Completed</span>\n <span class=\"value\">{{ record.CompletedAt | date:'medium' }}</span>\n </div>\n }\n @if (record.CompletedAt) {\n <div class=\"stat\">\n <span class=\"label\">Duration</span>\n <span class=\"value\">{{ calculateDuration(record.StartedAt, record.CompletedAt) }}</span>\n </div>\n }\n @if (record.Success !== null && record.CompletedAt !== null) {\n <div class=\"stat\">\n <span class=\"label\">Result</span>\n <span class=\"value\" [class.success]=\"record.Success\" [class.error]=\"!record.Success\">\n {{ record.Success ? 'Success' : 'Failed' }}\n </span>\n </div>\n }\n @if (costMetrics && (costMetrics.totalTokensInput + costMetrics.totalTokensOutput) > 0) {\n <div class=\"stat\">\n <span class=\"label\">Tokens</span>\n @if (!costMetrics.isLoading) {\n <span class=\"value\">{{ (costMetrics.totalTokensInput + costMetrics.totalTokensOutput) | number:'1.0-0' }}</span>\n }\n @if (costMetrics.isLoading) {\n <span class=\"value loading\"><i class=\"fas fa-spinner fa-spin\"></i></span>\n }\n </div>\n }\n @if (costMetrics && costMetrics.totalCost > 0) {\n <div class=\"stat\">\n <span class=\"label\">Cost</span>\n @if (!costMetrics.isLoading) {\n <span class=\"value\">${{ costMetrics.totalCost | number:'1.2-4' }}</span>\n }\n @if (costMetrics.isLoading) {\n <span class=\"value loading\"><i class=\"fas fa-spinner fa-spin\"></i></span>\n }\n </div>\n }\n @if (record.EffortLevel) {\n <div class=\"stat\">\n <span class=\"label\">Effort Level</span>\n <span class=\"value\">{{ record.EffortLevel }}</span>\n </div>\n }\n </div>\n\n <!-- Configuration Bar (shown below header stats when ConfigurationID exists) -->\n @if (record.ConfigurationID) {\n <div class=\"configuration-bar\">\n <div class=\"config-item\">\n <i class=\"fas fa-cog\"></i>\n <div class=\"config-content\">\n <div class=\"config-label\">Configuration</div>\n <div class=\"config-value\">\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: AI Configurations', record.ConfigurationID)\">\n {{ record.Configuration || 'Unknown' }}\n </a>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Tabs -->\n <div class=\"tabs\">\n <button class=\"tab\" [class.active]=\"activeTab === 'timeline'\" (click)=\"changeTab('timeline')\">\n <i class=\"fas fa-stream\"></i> Timeline\n </button>\n <button class=\"tab\" [class.active]=\"activeTab === 'visualization'\" (click)=\"changeTab('visualization')\">\n <i class=\"fas fa-diagram-project\"></i> Visualization\n </button>\n <button class=\"tab\" [class.active]=\"activeTab === 'analytics'\" (click)=\"changeTab('analytics')\">\n <i class=\"fas fa-chart-line\"></i> Analytics\n </button>\n <button class=\"tab\" [class.active]=\"activeTab === 'details'\" (click)=\"changeTab('details')\">\n <i class=\"fas fa-info-circle\"></i> Details\n </button>\n </div>\n\n <!-- Content -->\n <div class=\"content-area\">\n <!-- Timeline Tab -->\n @if (activeTab === 'timeline') {\n <div class=\"tab-content\" style=\"height: 100%;\">\n <as-split direction=\"horizontal\" style=\"height: 100%;\">\n <!-- Timeline Pane -->\n <as-split-area [size]=\"selectedTimelineItem ? 55 : 100\">\n <mj-ai-agent-run-timeline\n [aiAgentRunId]=\"record.ID\"\n [dataHelper]=\"dataHelper\"\n [RunTree]=\"runTree\"\n (itemSelected)=\"selectTimelineItem($event)\"\n (navigateToEntity)=\"navigateToEntityRecord($event)\">\n </mj-ai-agent-run-timeline>\n </as-split-area>\n <!-- JSON Detail Pane -->\n @if (selectedTimelineItem) {\n <as-split-area [size]=\"45\">\n <mj-ai-agent-run-step-detail\n [selectedTimelineItem]=\"selectedTimelineItem\"\n [Provider]=\"ProviderToUse\"\n (closePanel)=\"closeJsonPanel()\"\n (navigateToActionLog)=\"navigateToActionLog($event)\"\n (copyToClipboard)=\"copyToClipboard($event)\">\n </mj-ai-agent-run-step-detail>\n </as-split-area>\n }\n </as-split>\n </div>\n }\n\n <!-- Visualization Tab (animated flow views + static flowchart) -->\n @if (activeTab === 'visualization') {\n <div class=\"tab-content\" style=\"height: 100%;\">\n @if (visualizationLoaded) {\n <mj-ai-agent-run-flow\n [aiAgentRunId]=\"record.ID\"\n [dataHelper]=\"dataHelper\"\n [agentName]=\"agent?.Name || null\"\n [runStatus]=\"record.Status || ''\"\n [agentIconClass]=\"agent?.IconClass || null\"\n [agentLogoUrl]=\"agent?.LogoURL || null\"\n [RunTree]=\"runTree\">\n </mj-ai-agent-run-flow>\n }\n </div>\n }\n\n <!-- Analytics Tab -->\n @if (activeTab === 'analytics') {\n <div class=\"tab-content\" style=\"height: 100%;\">\n @if (analyticsLoaded) {\n <mj-ai-agent-run-analytics\n #analyticsComponent\n [agentRunId]=\"record.ID\"\n [RunTree]=\"runTree\"\n >\n </mj-ai-agent-run-analytics>\n }\n </div>\n }\n\n <!-- Details Tab -->\n @if (activeTab === 'details') {\n <div class=\"tab-content\">\n <mj-accordion-panel [Expanded]=\"true\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-info-circle\"></i> General Information\n </ng-template>\n <div class=\"details-grid\">\n <div class=\"detail-item\">\n <label>Agent</label>\n <span>\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: AI Agents', record.AgentID)\">\n {{ agent?.Name || 'N/A' }}\n </a>\n </span>\n </div>\n <div class=\"detail-item\">\n <label>Parent Run ID</label>\n <span>\n @if (record.ParentRunID) {\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: AI Agent Runs', record.ParentRunID)\">\n {{ record.ParentRunID }}\n </a>\n }\n @if (!record.ParentRunID) {\n <span>None (Root)</span>\n }\n </span>\n </div>\n <div class=\"detail-item\">\n <label>Last Run ID</label>\n <span>\n @if (record.LastRunID) {\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: AI Agent Runs', record.LastRunID)\">\n {{ record.LastRunID }}\n </a>\n }\n @if (!record.LastRunID) {\n <span>None</span>\n }\n </span>\n </div>\n <div class=\"detail-item\">\n <label>Conversation ID</label>\n <span>\n @if (record.ConversationID) {\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: Conversations', record.ConversationID)\">\n {{ record.ConversationID }}\n </a>\n }\n @if (!record.ConversationID) {\n <span>N/A</span>\n }\n </span>\n </div>\n <div class=\"detail-item\">\n <label>User</label>\n <span>\n @if (record.UserID) {\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: Users', record.UserID)\">\n {{ record.User || 'N/A' }}\n </a>\n }\n @if (!record.UserID) {\n <span>N/A</span>\n }\n </span>\n </div>\n </div>\n </mj-accordion-panel>\n <mj-accordion-panel [Expanded]=\"false\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-cogs\"></i> Execution Settings\n </ng-template>\n <div class=\"details-grid\">\n <div class=\"detail-item\">\n <label>Override Model</label>\n <span>\n @if (record.OverrideModelID) {\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: AI Models', record.OverrideModelID)\">\n {{ record.OverrideModel || 'N/A' }}\n </a>\n }\n @if (!record.OverrideModelID) {\n <span>N/A</span>\n }\n </span>\n </div>\n <div class=\"detail-item\">\n <label>Override Vendor</label>\n <span>\n @if (record.OverrideVendorID) {\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: AI Vendors', record.OverrideVendorID)\">\n {{ record.OverrideVendor || 'N/A' }}\n </a>\n }\n @if (!record.OverrideVendorID) {\n <span>N/A</span>\n }\n </span>\n </div>\n <div class=\"detail-item\">\n <label>Verbose Logging</label>\n <span>{{ record.Verbose ? 'Yes' : 'No' }}</span>\n </div>\n </div>\n </mj-accordion-panel>\n <mj-accordion-panel [Expanded]=\"false\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-tasks\"></i> Execution Status\n </ng-template>\n <div class=\"details-grid\">\n <div class=\"detail-item\">\n <label>Status</label>\n <span class=\"status-badge\" [attr.data-status]=\"record.Status\">\n {{ record.Status }}\n </span>\n </div>\n <div class=\"detail-item\">\n <label>Success</label>\n @if (record.Success === null) {\n <span>In Progress</span>\n }\n @else if (record.Success) {\n <span class=\"success\">Yes</span>\n }\n @else {\n <span class=\"error-message\">No</span>\n }\n </div>\n @if (record.Message) {\n <div class=\"detail-item full-width\">\n <label>Message</label>\n <div class=\"message\">{{ record.Message }}</div>\n </div>\n }\n @if (record.ErrorMessage) {\n <div class=\"detail-item full-width\">\n <label>Error Message</label>\n <div class=\"error-message\">{{ record.ErrorMessage }}</div>\n </div>\n }\n </div>\n </mj-accordion-panel>\n <mj-accordion-panel [Expanded]=\"false\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-dollar-sign\"></i> Usage & Cost\n </ng-template>\n <div class=\"details-grid\">\n <div class=\"detail-item\">\n <label>Total Tokens Used</label>\n <span>{{ record.TotalTokensUsed ? (record.TotalTokensUsed | number:'1.0-0') : 'N/A' }}</span>\n </div>\n <div class=\"detail-item\">\n <label>Prompt Tokens</label>\n <span>{{ record.TotalPromptTokensUsed ? (record.TotalPromptTokensUsed | number:'1.0-0') : 'N/A' }}</span>\n </div>\n <div class=\"detail-item\">\n <label>Completion Tokens</label>\n <span>{{ record.TotalCompletionTokensUsed ? (record.TotalCompletionTokensUsed | number:'1.0-0') : 'N/A' }}</span>\n </div>\n <div class=\"detail-item\">\n <label>Total Cost</label>\n <span>{{ record.TotalCost != null ? ('$' + (record.TotalCost | number:'1.2-4')) : 'N/A' }}</span>\n </div>\n <div class=\"detail-item\">\n <label>Total Prompt Iterations</label>\n <span>{{ record.TotalPromptIterations != null ? (record.TotalPromptIterations | number:'1.0-0') : 'N/A' }}</span>\n </div>\n </div>\n </mj-accordion-panel>\n @if (record.Result) {\n <mj-accordion-panel [Expanded]=\"false\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-code\"></i> Result\n </ng-template>\n <div class=\"result-viewer\">\n @if (isParsingComplete) {\n <mj-code-editor\n [ngModel]=\"parsedResult\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n style=\"height: 300px; width: 100%;\">\n </mj-code-editor>\n } @else {\n <div style=\"padding: 20px; text-align: center; color: var(--mj-text-muted);\">\n <i class=\"fas fa-spinner fa-spin\"></i> Loading result data...\n </div>\n }\n </div>\n </mj-accordion-panel>\n }\n @if (record.StartingPayload) {\n <mj-accordion-panel [Expanded]=\"false\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-upload\"></i> Starting Payload\n </ng-template>\n <div class=\"result-viewer\">\n @if (isParsingComplete) {\n <mj-code-editor\n [ngModel]=\"parsedStartingPayload\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n style=\"height: 300px; width: 100%;\">\n </mj-code-editor>\n } @else {\n <div style=\"padding: 20px; text-align: center; color: var(--mj-text-muted);\">\n <i class=\"fas fa-spinner fa-spin\"></i> Loading payload data...\n </div>\n }\n </div>\n </mj-accordion-panel>\n }\n @if (record.Data) {\n <mj-accordion-panel [Expanded]=\"false\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-database\"></i> Execution Data\n </ng-template>\n <div class=\"result-viewer\">\n @if (isParsingComplete) {\n <mj-code-editor\n [ngModel]=\"parsedData\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n style=\"height: 300px; width: 100%;\">\n </mj-code-editor>\n } @else {\n <div style=\"padding: 20px; text-align: center; color: var(--mj-text-muted);\">\n <i class=\"fas fa-spinner fa-spin\"></i> Loading execution data...\n </div>\n }\n </div>\n </mj-accordion-panel>\n }\n @if (record.FinalPayload) {\n <mj-accordion-panel [Expanded]=\"false\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-download\"></i> Final Payload\n </ng-template>\n <div class=\"result-viewer\">\n @if (isParsingComplete) {\n <mj-code-editor\n [ngModel]=\"parsedFinalPayload\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n style=\"height: 300px; width: 100%;\">\n </mj-code-editor>\n } @else {\n <div style=\"padding: 20px; text-align: center; color: var(--mj-text-muted);\">\n <i class=\"fas fa-spinner fa-spin\"></i> Loading final payload data...\n </div>\n }\n </div>\n </mj-accordion-panel>\n }\n @if (showPayloadDiff) {\n <mj-accordion-panel [Expanded]=\"false\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-code-compare\"></i> Payload Diff\n </ng-template>\n <div style=\"padding: 20px; background: var(--mj-bg-surface-card);\">\n @if (isParsingComplete) {\n <mj-deep-diff\n [oldValue]=\"startingPayloadObject\"\n [newValue]=\"finalPayloadObject\"\n [title]=\"''\"\n [showSummary]=\"true\"\n [showUnchanged]=\"false\"\n [expandAll]=\"false\"\n [maxDepth]=\"10\"\n [maxStringLength]=\"200\"\n [treatNullAsUndefined]=\"true\">\n </mj-deep-diff>\n } @else {\n <div style=\"padding: 20px; text-align: center; color: var(--mj-text-muted);\">\n <i class=\"fas fa-spinner fa-spin\"></i> Loading payload diff...\n </div>\n }\n </div>\n </mj-accordion-panel>\n }\n </div>\n }\n</div>\n</div>\n</div>", styles: [".ai-agent-run-form {\n height: 100%;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.record-form-container.ai-agent-run-form > .record-form,\n.ai-agent-run-form > .record-form {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n\n/* Header Styles */\n.header {\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n padding: 20px;\n box-shadow: var(--mj-shadow-sm);\n flex-shrink: 0;\n}\n\n.header-content {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 16px;\n}\n\n.header-left {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.icon-wrapper {\n width: 48px;\n height: 48px;\n background: var(--mj-brand-primary);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-inverse);\n font-size: 20px;\n overflow: hidden;\n}\n\n.agent-logo {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.header-info h2 {\n margin: 0;\n font-size: 24px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.meta-info {\n display: flex;\n gap: 12px;\n margin-top: 4px;\n font-size: 14px;\n color: var(--mj-text-muted);\n}\n\n.parent-run {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.parent-link {\n color: var(--mj-status-error);\n text-decoration: none;\n cursor: pointer;\n transition: color 0.2s;\n}\n\n.parent-link:hover {\n color: var(--mj-status-error);\n text-decoration: underline;\n}\n\n.agent-name {\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.run-id {\n font-family: monospace;\n font-size: 12px;\n opacity: 0.7;\n}\n\n/* Conversation Link Pill */\n.conversation-pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n border-radius: 16px;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-brand-primary);\n cursor: pointer;\n transition: all 0.2s ease;\n white-space: nowrap;\n}\n\n.conversation-pill:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n transform: translateY(-1px);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.conversation-pill i:first-child {\n font-size: 11px;\n opacity: 0.9;\n}\n\n.conversation-pill .pill-action {\n font-size: 9px;\n opacity: 0.6;\n transition: opacity 0.2s ease;\n}\n\n.conversation-pill:hover .pill-action {\n opacity: 1;\n}\n\n.header-right {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.status-badge {\n padding: 6px 16px;\n border-radius: 20px;\n font-size: 13px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n}\n\n.status-badge[data-status=\"Running\"] {\n background: color-mix(in srgb, var(--mj-status-info) 15%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n}\n\n.status-badge[data-status=\"Completed\"] {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.status-badge[data-status=\"Failed\"] {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.status-badge[data-status=\"Cancelled\"] {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.status-badge[data-status=\"Paused\"] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.status-badge.small {\n padding: 4px 12px;\n font-size: 11px;\n}\n\n/* Plan Mode chip \u2014 shown next to the status badge when AIAgentRun.PlanMode = 1 */\n.plan-mode-badge {\n padding: 6px 16px;\n border-radius: 20px;\n font-size: 13px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n}\n\n.header-actions {\n display: flex;\n gap: 8px;\n}\n\n.btn-icon {\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.2s ease;\n color: var(--mj-text-muted);\n}\n\n.btn-icon:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-secondary);\n}\n\n.header-stats {\n display: flex;\n gap: 24px;\n padding-top: 12px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n/* Configuration Bar */\n.configuration-bar {\n display: flex;\n gap: 24px;\n padding-top: 16px;\n border-top: 1px solid var(--mj-border-default);\n margin-top: 16px;\n}\n\n.config-item {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.config-item > i {\n font-size: 1.2em;\n color: var(--mj-text-muted);\n width: 24px;\n text-align: center;\n}\n\n.config-content {\n display: flex;\n flex-direction: column;\n}\n\n.config-label {\n font-size: 12px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.config-value {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.config-value .entity-link {\n color: var(--mj-brand-primary);\n text-decoration: none;\n cursor: pointer;\n transition: color 0.2s;\n}\n\n.config-value .entity-link:hover {\n color: var(--mj-brand-primary-hover);\n text-decoration: underline;\n}\n\n.stat {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.stat .label {\n font-size: 12px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.stat .value {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.stat .value.success {\n color: var(--mj-status-success);\n}\n\n.stat .value.error {\n color: var(--mj-status-error);\n}\n\n/* Tabs */\n.tabs {\n display: flex;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.tab {\n padding: 12px 24px;\n border: none;\n background: transparent;\n cursor: pointer;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n gap: 8px;\n transition: all 0.2s ease;\n border-bottom: 3px solid transparent;\n}\n\n.tab:hover {\n color: var(--mj-text-secondary);\n background: color-mix(in srgb, var(--mj-text-primary) 2%, var(--mj-bg-surface));\n}\n\n.tab.active {\n color: var(--mj-brand-primary);\n border-bottom-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n/* Content Area */\n.content-area {\n position: relative;\n flex: 1;\n min-height: 0;\n overflow: auto;\n background: var(--mj-bg-surface);\n}\n\n.tab-content {\n height: 100%;\n min-height: 0;\n overflow: auto;\n}\n\n/* Details tab accordion panels */\n.tab-content mj-accordion-panel {\n display: block;\n margin-bottom: 8px;\n}\n\n/* JSON Detail Pane */\n.json-detail-pane {\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-sunken);\n border-left: 1px solid var(--mj-border-default);\n}\n\n.json-pane-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.json-pane-header h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.json-pane-header h3 i {\n color: var(--mj-text-muted);\n font-size: 14px;\n}\n\n.json-pane-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: auto;\n padding: 16px;\n}\n\n.json-meta {\n display: flex;\n gap: 20px;\n margin-bottom: 16px;\n flex-wrap: wrap;\n}\n\n.json-meta .meta-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.json-meta .meta-item label {\n font-size: 11px;\n text-transform: uppercase;\n color: var(--mj-text-muted);\n font-weight: 600;\n letter-spacing: 0.5px;\n}\n\n.json-meta .meta-item span {\n font-size: 14px;\n color: var(--mj-text-primary);\n font-weight: 500;\n}\n\n.action-link {\n margin-bottom: 12px;\n}\n\n.action-link .btn-link {\n background: none;\n border: none;\n color: var(--mj-brand-primary);\n font-size: 14px;\n cursor: pointer;\n padding: 6px 12px;\n border-radius: 4px;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n}\n\n.action-link .btn-link:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary-hover);\n}\n\n.json-viewer {\n flex: 1;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n border-radius: 8px;\n border: 1px solid var(--mj-border-default);\n overflow: auto;\n padding: 20px;\n gap: 10px;\n min-height: 0;\n margin-bottom: 45px;\n}\n\n\n.json-toolbar {\n display: flex;\n justify-content: flex-end;\n padding: 8px 12px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n/* Timeline Styles */\n.timeline-container {\n height: 100%;\n overflow-y: auto;\n padding: 20px;\n}\n\n.timeline-container > .timeline {\n max-width: 900px;\n margin: 0 auto;\n}\n\n.timeline {\n position: relative;\n padding-left: 40px;\n}\n\n.timeline::before {\n content: '';\n position: absolute;\n left: 20px;\n top: 0;\n bottom: 0;\n width: 2px;\n background: var(--mj-border-default);\n}\n\n.timeline-item {\n position: relative;\n margin-bottom: 24px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.timeline-item:hover {\n transform: translateX(4px);\n}\n\n.timeline-item.selected {\n transform: translateX(8px);\n}\n\n.timeline-item.selected .timeline-content {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n}\n\n.timeline-marker {\n position: absolute;\n left: -30px;\n top: 0;\n width: 40px;\n height: 40px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-surface);\n border: 3px solid var(--mj-border-default);\n z-index: 1;\n transition: all 0.2s ease;\n}\n\n.timeline-marker[data-color=\"success\"] {\n border-color: var(--mj-status-success);\n color: var(--mj-status-success);\n}\n\n.timeline-marker[data-color=\"error\"] {\n border-color: var(--mj-status-error);\n color: var(--mj-status-error);\n}\n\n.timeline-marker[data-color=\"info\"] {\n border-color: var(--mj-status-info);\n color: var(--mj-status-info);\n}\n\n.timeline-marker[data-color=\"warning\"] {\n border-color: var(--mj-status-warning);\n color: var(--mj-status-warning);\n}\n\n.timeline-marker[data-color=\"secondary\"] {\n border-color: var(--mj-text-muted);\n color: var(--mj-text-muted);\n}\n\n.timeline-marker.small {\n width: 28px;\n height: 28px;\n font-size: 12px;\n}\n\n.timeline-content {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 16px 20px;\n margin-left: 20px;\n box-shadow: var(--mj-shadow-sm);\n transition: all 0.2s ease;\n}\n\n.timeline-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n\n.timeline-header h4 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.timeline-header h5 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.timeline-time {\n font-size: 12px;\n color: var(--mj-text-muted);\n font-family: monospace;\n}\n\n.timeline-subtitle {\n font-size: 13px;\n color: var(--mj-text-muted);\n margin-bottom: 8px;\n}\n\n.timeline-meta {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.timeline-meta .status {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.timeline-meta .status[data-status=\"Completed\"] {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.timeline-meta .status[data-status=\"Failed\"] {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.timeline-meta .status[data-status=\"Running\"] {\n background: color-mix(in srgb, var(--mj-status-info) 15%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n}\n\n.timeline-meta .status[data-status=\"Paused\"] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.duration {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.timeline-actions {\n position: absolute;\n right: 20px;\n top: 50%;\n transform: translateY(-50%);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.btn-link {\n background: none;\n border: none;\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-size: 12px;\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.2s ease;\n}\n\n.btn-link:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.btn-expand {\n width: 24px;\n height: 24px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.2s ease;\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n.btn-expand:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-secondary);\n}\n\n/* Timeline Children */\n.timeline-children {\n position: relative;\n margin-top: 12px;\n margin-bottom: 12px;\n}\n\n.timeline-children::before {\n content: '';\n position: absolute;\n left: -10px;\n top: -12px;\n bottom: 0;\n width: 2px;\n background: var(--mj-border-default);\n}\n\n.child-item {\n margin-bottom: 12px;\n}\n\n.child-item .timeline-content {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-default);\n}\n\n/* Sub-run timeline styles */\n.sub-run-timeline {\n background: color-mix(in srgb, var(--mj-brand-primary) 2%, var(--mj-bg-surface));\n border-left: 2px solid color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n margin-left: 20px;\n padding-left: 20px;\n margin-top: 8px;\n margin-bottom: 8px;\n}\n\n.sub-run-item .timeline-marker {\n border-width: 2px;\n}\n\n.sub-run-item .timeline-content {\n transition: all 0.2s ease;\n}\n\n/* JSON Detail Pane (in splitter) */\n.json-detail-pane {\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n}\n\n.json-pane-header {\n padding: 16px 20px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-shrink: 0;\n}\n\n.json-pane-header h3 {\n margin: 0;\n font-size: 16px;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 10px;\n font-weight: 600;\n}\n\n.json-pane-content {\n flex: 1;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n}\n\n.json-meta {\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n gap: 20px;\n flex-wrap: wrap;\n flex-shrink: 0;\n}\n\n.json-meta .meta-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.json-meta label {\n font-size: 11px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.json-meta span {\n font-size: 14px;\n color: var(--mj-text-primary);\n font-weight: 500;\n}\n\n.action-link {\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.action-link .btn-link {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-brand-primary);\n text-decoration: none;\n font-size: 14px;\n padding: 8px 12px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n border-radius: 4px;\n transition: all 0.2s;\n cursor: pointer;\n}\n\n.action-link .btn-link:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n text-decoration: none;\n}\n\n\n.json-toolbar {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n margin-bottom: 8px;\n}\n\n/* Details Tab */\n.details-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 20px;\n padding: 20px;\n}\n\n.detail-item {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.detail-item.full-width {\n grid-column: 1 / -1;\n}\n\n.detail-item label {\n font-size: 12px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.detail-item span {\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.error-message {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n padding: 12px;\n border-radius: 8px;\n font-size: 13px;\n}\n\n.result-viewer,\n.state-viewer {\n padding: 20px;\n max-height: 450px;\n overflow: auto;\n display: flex;\n flex-direction: column;\n}\n\n.result-viewer mj-code-editor,\n.state-viewer mj-code-editor {\n flex: 1;\n min-height: 0;\n}\n\n/* Empty States */\n.empty-state,\n.loading-state,\n.error-state {\n text-align: center;\n padding: 60px 20px;\n color: var(--mj-text-muted);\n}\n\n.empty-state i,\n.loading-state i,\n.error-state i {\n opacity: 0.3;\n margin-bottom: 16px;\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .header-content {\n flex-direction: column;\n gap: 16px;\n }\n \n .header-stats {\n flex-wrap: wrap;\n }\n \n .json-detail-pane {\n width: 100%;\n }\n \n .timeline {\n padding-left: 30px;\n }\n \n .timeline-marker {\n left: -25px;\n width: 32px;\n height: 32px;\n }\n \n .timeline-content {\n margin-left: 10px;\n }\n}\n\n/* Entity Link Styles */\n.entity-link {\n color: var(--mj-brand-primary);\n text-decoration: none;\n transition: all 0.2s ease;\n border-bottom: 1px solid transparent;\n display: inline-block;\n}\n\n.entity-link:hover {\n color: var(--mj-brand-primary-hover);\n border-bottom-color: var(--mj-brand-primary-hover);\n}\n\n.entity-link:active {\n color: var(--mj-brand-primary-hover);\n}\n\n/* Detail Pane Tabs */\n.detail-pane-tabs {\n display: flex;\n gap: 8px;\n margin: 8px 0 0 0;\n border-bottom: 1px solid var(--mj-border-default);\n padding: 0 16px;\n}\n\n.detail-tab {\n padding: 10px 16px;\n background: none;\n border: none;\n border-bottom: 3px solid transparent;\n color: var(--mj-text-muted);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.detail-tab:hover {\n color: var(--mj-text-secondary);\n background: color-mix(in srgb, var(--mj-text-primary) 2%, var(--mj-bg-surface));\n}\n\n.detail-tab.active {\n color: var(--mj-brand-primary);\n border-bottom-color: var(--mj-brand-primary);\n}\n\n.detail-tab i {\n font-size: 14px;\n}\n\n/* Detail Pane Content */\n.detail-pane-content {\n flex: 1;\n overflow-y: auto;\n min-height: 0;\n margin-bottom: 35px;\n}\n\n.detail-pane-content.with-tabs {\n /* When tabs are shown, content starts right after tabs */\n margin-top: 0;\n}\n\n/* Step Payload Diff */\n.step-payload-diff {\n height: 100%;\n overflow-y: auto;\n padding: 16px;\n}\n\n.step-payload-diff mj-deep-diff {\n display: block;\n height: 100%;\n}\n\n/* JSON Viewer adjustments when no tabs */\n.detail-pane-content:not(.with-tabs) .json-viewer {\n margin-top: 16px;\n}\n/* A detached workflow still executing after its run completed. Blue rather than green or amber: it\n is neither finished nor wrong, it is the same \"workflow\" provenance the timeline uses. */\n.workflow-running-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 12px;\n border-radius: var(--mj-radius-full, 999px);\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n white-space: nowrap;\n}\n"] }]
|
|
2034
|
+
args: [{ standalone: false, selector: 'mj-ai-agent-run-form', template: "<div class=\"record-form-container ai-agent-run-form\">\n <div class=\"record-form\">\n <!-- Header -->\n <div class=\"header\">\n <div class=\"header-content\">\n <div class=\"header-left\">\n <div class=\"icon-wrapper\">\n @if (agent && agent.LogoURL) {\n <img [src]=\"agent.LogoURL\" [alt]=\"agent.Name || 'Agent'\" class=\"agent-logo\" />\n }\n @if (agent && !agent.LogoURL && agent.IconClass) {\n <i class=\"fas\" [ngClass]=\"agent.IconClass\"></i>\n }\n @if (!agent || (!agent.LogoURL && !agent.IconClass)) {\n <i class=\"fas fa-robot\"></i>\n }\n </div>\n <div class=\"header-info\">\n <h2>AI Agent Run</h2>\n <div class=\"meta-info\">\n @if (agent) {\n <span class=\"agent-name\">\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: AI Agents', record.AgentID)\">\n {{ agent.Name }}\n </a>\n </span>\n }\n <span class=\"run-id\">{{ record.ID }}</span>\n @if (record.ParentRunID) {\n <span class=\"parent-run\">\n <i class=\"fas fa-level-up-alt\"></i>\n <a (click)=\"navigateToParentRun()\" class=\"parent-link\">Parent Run</a>\n </span>\n }\n <!-- Conversation Link Pill -->\n @if (record.ConversationID) {\n <span class=\"conversation-pill\" (click)=\"navigateToConversation()\" title=\"Open conversation in Chat app\">\n <i class=\"fas fa-comments\"></i>\n <span>Conversation</span>\n <i class=\"fas fa-external-link-alt pill-action\"></i>\n </span>\n }\n </div>\n </div>\n </div>\n <div class=\"header-right\">\n @if (record.PlanMode) {\n <div class=\"plan-mode-badge\" title=\"This run executed in Plan Mode \u2014 the agent presented a plan for human approval before executing actions or sub-agents\">\n <i class=\"fas fa-clipboard-check\"></i>\n Plan Mode\n </div>\n }\n <div class=\"status-badge\" [attr.data-status]=\"record.Status\">\n <i class=\"fas\" [ngClass]=\"getStatusIcon(record.Status || '')\"></i>\n {{ record.Status }}\n </div>\n <!-- A workflow outlives the run that submitted it, so a Completed run can still have work\n in flight. Said beside the status rather than instead of it \u2014 both are true. -->\n @if (WorkflowStillRunning) {\n <div class=\"workflow-running-badge\"\n title=\"This run submitted a workflow that runs on the dispatcher. The run finished when the workflow was submitted; the workflow itself is still going. This view refreshes on its own.\">\n <i class=\"fas fa-circle-notch fa-spin\"></i>\n Workflow still running\n </div>\n }\n <div class=\"header-actions\">\n <button class=\"btn-icon\" (click)=\"refreshData()\" title=\"Refresh\">\n <i class=\"fas fa-sync-alt\"></i>\n </button>\n </div>\n </div>\n </div>\n <div class=\"header-stats\">\n <div class=\"stat\">\n <span class=\"label\">Started</span>\n <span class=\"value\">{{ record.StartedAt | date:'medium' }}</span>\n </div>\n @if (record.CompletedAt) {\n <div class=\"stat\">\n <span class=\"label\">Completed</span>\n <span class=\"value\">{{ record.CompletedAt | date:'medium' }}</span>\n </div>\n }\n @if (record.CompletedAt) {\n <div class=\"stat\">\n <span class=\"label\">Duration</span>\n <span class=\"value\">{{ calculateDuration(record.StartedAt, record.CompletedAt) }}</span>\n </div>\n }\n @if (record.Success !== null && record.CompletedAt !== null) {\n <div class=\"stat\">\n <span class=\"label\">Result</span>\n <span class=\"value\" [class.success]=\"record.Success\" [class.error]=\"!record.Success\">\n {{ record.Success ? 'Success' : 'Failed' }}\n </span>\n </div>\n }\n @if (costMetrics && (costMetrics.totalTokensInput + costMetrics.totalTokensOutput) > 0) {\n <div class=\"stat\">\n <span class=\"label\">Tokens</span>\n @if (!costMetrics.isLoading) {\n <span class=\"value\">{{ (costMetrics.totalTokensInput + costMetrics.totalTokensOutput) | number:'1.0-0' }}</span>\n }\n @if (costMetrics.isLoading) {\n <span class=\"value loading\"><i class=\"fas fa-spinner fa-spin\"></i></span>\n }\n </div>\n }\n @if (costMetrics && costMetrics.totalCost > 0) {\n <div class=\"stat\">\n <span class=\"label\">Cost</span>\n @if (!costMetrics.isLoading) {\n <span class=\"value\">${{ costMetrics.totalCost | number:'1.2-4' }}</span>\n }\n @if (costMetrics.isLoading) {\n <span class=\"value loading\"><i class=\"fas fa-spinner fa-spin\"></i></span>\n }\n </div>\n }\n @if (record.EffortLevel) {\n <div class=\"stat\">\n <span class=\"label\">Effort Level</span>\n <span class=\"value\">{{ record.EffortLevel }}</span>\n </div>\n }\n </div>\n\n <!-- Configuration Bar (shown below header stats when ConfigurationID exists) -->\n @if (record.ConfigurationID) {\n <div class=\"configuration-bar\">\n <div class=\"config-item\">\n <i class=\"fas fa-cog\"></i>\n <div class=\"config-content\">\n <div class=\"config-label\">Configuration</div>\n <div class=\"config-value\">\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: AI Configurations', record.ConfigurationID)\">\n {{ record.Configuration || 'Unknown' }}\n </a>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Tabs -->\n <div class=\"tabs\">\n <button class=\"tab\" [class.active]=\"activeTab === 'timeline'\" (click)=\"changeTab('timeline')\">\n <i class=\"fas fa-stream\"></i> Timeline\n </button>\n <button class=\"tab\" [class.active]=\"activeTab === 'visualization'\" (click)=\"changeTab('visualization')\">\n <i class=\"fas fa-diagram-project\"></i> Visualization\n </button>\n <button class=\"tab\" [class.active]=\"activeTab === 'analytics'\" (click)=\"changeTab('analytics')\">\n <i class=\"fas fa-chart-line\"></i> Analytics\n </button>\n <button class=\"tab\" [class.active]=\"activeTab === 'details'\" (click)=\"changeTab('details')\">\n <i class=\"fas fa-info-circle\"></i> Details\n </button>\n </div>\n\n <!-- Content -->\n <div class=\"content-area\">\n <!-- Timeline Tab -->\n @if (activeTab === 'timeline') {\n <div class=\"tab-content\" style=\"height: 100%;\">\n <as-split direction=\"horizontal\" style=\"height: 100%;\">\n <!-- Timeline Pane -->\n <as-split-area [size]=\"selectedTimelineItem ? 55 : 100\">\n <mj-ai-agent-run-timeline\n [aiAgentRunId]=\"record.ID\"\n [dataHelper]=\"dataHelper\"\n [RunTree]=\"runTree\"\n (itemSelected)=\"selectTimelineItem($event)\"\n (navigateToEntity)=\"navigateToEntityRecord($event)\">\n </mj-ai-agent-run-timeline>\n </as-split-area>\n <!-- JSON Detail Pane -->\n @if (selectedTimelineItem) {\n <as-split-area [size]=\"45\">\n <mj-ai-agent-run-step-detail\n [selectedTimelineItem]=\"selectedTimelineItem\"\n [Provider]=\"ProviderToUse\"\n [SavingWorkflow]=\"SavingWorkflow\"\n (closePanel)=\"closeJsonPanel()\"\n (navigateToActionLog)=\"navigateToActionLog($event)\"\n (copyToClipboard)=\"copyToClipboard($event)\"\n (SaveAsWorkflowRequested)=\"OnSaveAsWorkflowRequested($event)\">\n </mj-ai-agent-run-step-detail>\n </as-split-area>\n }\n </as-split>\n </div>\n }\n\n <!-- Visualization Tab (animated flow views + static flowchart) -->\n @if (activeTab === 'visualization') {\n <div class=\"tab-content\" style=\"height: 100%;\">\n @if (visualizationLoaded) {\n <mj-ai-agent-run-flow\n [aiAgentRunId]=\"record.ID\"\n [dataHelper]=\"dataHelper\"\n [agentName]=\"agent?.Name || null\"\n [runStatus]=\"record.Status || ''\"\n [agentIconClass]=\"agent?.IconClass || null\"\n [agentLogoUrl]=\"agent?.LogoURL || null\"\n [RunTree]=\"runTree\">\n </mj-ai-agent-run-flow>\n }\n </div>\n }\n\n <!-- Analytics Tab -->\n @if (activeTab === 'analytics') {\n <div class=\"tab-content\" style=\"height: 100%;\">\n @if (analyticsLoaded) {\n <mj-ai-agent-run-analytics\n #analyticsComponent\n [agentRunId]=\"record.ID\"\n [RunTree]=\"runTree\"\n >\n </mj-ai-agent-run-analytics>\n }\n </div>\n }\n\n <!-- Details Tab -->\n @if (activeTab === 'details') {\n <div class=\"tab-content\">\n <mj-accordion-panel [Expanded]=\"true\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-info-circle\"></i> General Information\n </ng-template>\n <div class=\"details-grid\">\n <div class=\"detail-item\">\n <label>Agent</label>\n <span>\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: AI Agents', record.AgentID)\">\n {{ agent?.Name || 'N/A' }}\n </a>\n </span>\n </div>\n <div class=\"detail-item\">\n <label>Parent Run ID</label>\n <span>\n @if (record.ParentRunID) {\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: AI Agent Runs', record.ParentRunID)\">\n {{ record.ParentRunID }}\n </a>\n }\n @if (!record.ParentRunID) {\n <span>None (Root)</span>\n }\n </span>\n </div>\n <div class=\"detail-item\">\n <label>Last Run ID</label>\n <span>\n @if (record.LastRunID) {\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: AI Agent Runs', record.LastRunID)\">\n {{ record.LastRunID }}\n </a>\n }\n @if (!record.LastRunID) {\n <span>None</span>\n }\n </span>\n </div>\n <div class=\"detail-item\">\n <label>Conversation ID</label>\n <span>\n @if (record.ConversationID) {\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: Conversations', record.ConversationID)\">\n {{ record.ConversationID }}\n </a>\n }\n @if (!record.ConversationID) {\n <span>N/A</span>\n }\n </span>\n </div>\n <div class=\"detail-item\">\n <label>User</label>\n <span>\n @if (record.UserID) {\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: Users', record.UserID)\">\n {{ record.User || 'N/A' }}\n </a>\n }\n @if (!record.UserID) {\n <span>N/A</span>\n }\n </span>\n </div>\n </div>\n </mj-accordion-panel>\n <mj-accordion-panel [Expanded]=\"false\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-cogs\"></i> Execution Settings\n </ng-template>\n <div class=\"details-grid\">\n <div class=\"detail-item\">\n <label>Override Model</label>\n <span>\n @if (record.OverrideModelID) {\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: AI Models', record.OverrideModelID)\">\n {{ record.OverrideModel || 'N/A' }}\n </a>\n }\n @if (!record.OverrideModelID) {\n <span>N/A</span>\n }\n </span>\n </div>\n <div class=\"detail-item\">\n <label>Override Vendor</label>\n <span>\n @if (record.OverrideVendorID) {\n <a href=\"javascript:void(0)\" class=\"entity-link\" (click)=\"openEntityRecord('MJ: AI Vendors', record.OverrideVendorID)\">\n {{ record.OverrideVendor || 'N/A' }}\n </a>\n }\n @if (!record.OverrideVendorID) {\n <span>N/A</span>\n }\n </span>\n </div>\n <div class=\"detail-item\">\n <label>Verbose Logging</label>\n <span>{{ record.Verbose ? 'Yes' : 'No' }}</span>\n </div>\n </div>\n </mj-accordion-panel>\n <mj-accordion-panel [Expanded]=\"false\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-tasks\"></i> Execution Status\n </ng-template>\n <div class=\"details-grid\">\n <div class=\"detail-item\">\n <label>Status</label>\n <span class=\"status-badge\" [attr.data-status]=\"record.Status\">\n {{ record.Status }}\n </span>\n </div>\n <div class=\"detail-item\">\n <label>Success</label>\n @if (record.Success === null) {\n <span>In Progress</span>\n }\n @else if (record.Success) {\n <span class=\"success\">Yes</span>\n }\n @else {\n <span class=\"error-message\">No</span>\n }\n </div>\n @if (record.Message) {\n <div class=\"detail-item full-width\">\n <label>Message</label>\n <div class=\"message\">{{ record.Message }}</div>\n </div>\n }\n @if (record.ErrorMessage) {\n <div class=\"detail-item full-width\">\n <label>Error Message</label>\n <div class=\"error-message\">{{ record.ErrorMessage }}</div>\n </div>\n }\n </div>\n </mj-accordion-panel>\n <mj-accordion-panel [Expanded]=\"false\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-dollar-sign\"></i> Usage & Cost\n </ng-template>\n <div class=\"details-grid\">\n <div class=\"detail-item\">\n <label>Total Tokens Used</label>\n <span>{{ record.TotalTokensUsed ? (record.TotalTokensUsed | number:'1.0-0') : 'N/A' }}</span>\n </div>\n <div class=\"detail-item\">\n <label>Prompt Tokens</label>\n <span>{{ record.TotalPromptTokensUsed ? (record.TotalPromptTokensUsed | number:'1.0-0') : 'N/A' }}</span>\n </div>\n <div class=\"detail-item\">\n <label>Completion Tokens</label>\n <span>{{ record.TotalCompletionTokensUsed ? (record.TotalCompletionTokensUsed | number:'1.0-0') : 'N/A' }}</span>\n </div>\n <div class=\"detail-item\">\n <label>Total Cost</label>\n <span>{{ record.TotalCost != null ? ('$' + (record.TotalCost | number:'1.2-4')) : 'N/A' }}</span>\n </div>\n <div class=\"detail-item\">\n <label>Total Prompt Iterations</label>\n <span>{{ record.TotalPromptIterations != null ? (record.TotalPromptIterations | number:'1.0-0') : 'N/A' }}</span>\n </div>\n </div>\n </mj-accordion-panel>\n @if (ShowResultPanel) {\n <mj-accordion-panel [Expanded]=\"false\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-code\"></i> Result\n </ng-template>\n <div class=\"result-viewer\">\n @if (isParsingComplete) {\n <mj-code-editor\n [ngModel]=\"parsedResult\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n style=\"height: 300px; width: 100%;\">\n </mj-code-editor>\n } @else {\n <div style=\"padding: 20px; text-align: center; color: var(--mj-text-muted);\">\n <i class=\"fas fa-spinner fa-spin\"></i> Loading result data...\n </div>\n }\n </div>\n </mj-accordion-panel>\n }\n @if (record.StartingPayload) {\n <mj-accordion-panel [Expanded]=\"false\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-upload\"></i> Starting Payload\n </ng-template>\n <div class=\"result-viewer\">\n @if (isParsingComplete) {\n <mj-code-editor\n [ngModel]=\"parsedStartingPayload\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n style=\"height: 300px; width: 100%;\">\n </mj-code-editor>\n } @else {\n <div style=\"padding: 20px; text-align: center; color: var(--mj-text-muted);\">\n <i class=\"fas fa-spinner fa-spin\"></i> Loading payload data...\n </div>\n }\n </div>\n </mj-accordion-panel>\n }\n @if (record.Data) {\n <mj-accordion-panel [Expanded]=\"false\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-database\"></i> Execution Data\n </ng-template>\n <div class=\"result-viewer\">\n @if (isParsingComplete) {\n <mj-code-editor\n [ngModel]=\"parsedData\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n style=\"height: 300px; width: 100%;\">\n </mj-code-editor>\n } @else {\n <div style=\"padding: 20px; text-align: center; color: var(--mj-text-muted);\">\n <i class=\"fas fa-spinner fa-spin\"></i> Loading execution data...\n </div>\n }\n </div>\n </mj-accordion-panel>\n }\n @if (record.FinalPayload) {\n <mj-accordion-panel [Expanded]=\"false\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-download\"></i> Final Payload\n </ng-template>\n <div class=\"result-viewer\">\n @if (isParsingComplete) {\n <mj-code-editor\n [ngModel]=\"parsedFinalPayload\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n style=\"height: 300px; width: 100%;\">\n </mj-code-editor>\n } @else {\n <div style=\"padding: 20px; text-align: center; color: var(--mj-text-muted);\">\n <i class=\"fas fa-spinner fa-spin\"></i> Loading final payload data...\n </div>\n }\n </div>\n </mj-accordion-panel>\n }\n @if (showPayloadDiff) {\n <mj-accordion-panel [Expanded]=\"false\">\n <ng-template mjAccordionTitle>\n <i class=\"fas fa-code-compare\"></i> Payload Diff\n </ng-template>\n <div style=\"padding: 20px; background: var(--mj-bg-surface-card);\">\n @if (isParsingComplete) {\n <mj-deep-diff\n [oldValue]=\"startingPayloadObject\"\n [newValue]=\"finalPayloadObject\"\n [title]=\"''\"\n [showSummary]=\"true\"\n [showUnchanged]=\"false\"\n [expandAll]=\"false\"\n [maxDepth]=\"10\"\n [maxStringLength]=\"200\"\n [treatNullAsUndefined]=\"true\">\n </mj-deep-diff>\n } @else {\n <div style=\"padding: 20px; text-align: center; color: var(--mj-text-muted);\">\n <i class=\"fas fa-spinner fa-spin\"></i> Loading payload diff...\n </div>\n }\n </div>\n </mj-accordion-panel>\n }\n </div>\n }\n</div>\n</div>\n</div>", styles: [".ai-agent-run-form {\n height: 100%;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.record-form-container.ai-agent-run-form > .record-form,\n.ai-agent-run-form > .record-form {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n}\n\n/* Header Styles */\n.header {\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n padding: 20px;\n box-shadow: var(--mj-shadow-sm);\n flex-shrink: 0;\n}\n\n.header-content {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 16px;\n}\n\n.header-left {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.icon-wrapper {\n width: 48px;\n height: 48px;\n background: var(--mj-brand-primary);\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-inverse);\n font-size: 20px;\n overflow: hidden;\n}\n\n.agent-logo {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.header-info h2 {\n margin: 0;\n font-size: 24px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.meta-info {\n display: flex;\n gap: 12px;\n margin-top: 4px;\n font-size: 14px;\n color: var(--mj-text-muted);\n}\n\n.parent-run {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.parent-link {\n color: var(--mj-status-error);\n text-decoration: none;\n cursor: pointer;\n transition: color 0.2s;\n}\n\n.parent-link:hover {\n color: var(--mj-status-error);\n text-decoration: underline;\n}\n\n.agent-name {\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.run-id {\n font-family: monospace;\n font-size: 12px;\n opacity: 0.7;\n}\n\n/* Conversation Link Pill */\n.conversation-pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n border-radius: 16px;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-brand-primary);\n cursor: pointer;\n transition: all 0.2s ease;\n white-space: nowrap;\n}\n\n.conversation-pill:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n transform: translateY(-1px);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.conversation-pill i:first-child {\n font-size: 11px;\n opacity: 0.9;\n}\n\n.conversation-pill .pill-action {\n font-size: 9px;\n opacity: 0.6;\n transition: opacity 0.2s ease;\n}\n\n.conversation-pill:hover .pill-action {\n opacity: 1;\n}\n\n.header-right {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.status-badge {\n padding: 6px 16px;\n border-radius: 20px;\n font-size: 13px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n}\n\n.status-badge[data-status=\"Running\"] {\n background: color-mix(in srgb, var(--mj-status-info) 15%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n}\n\n.status-badge[data-status=\"Completed\"] {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.status-badge[data-status=\"Failed\"] {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.status-badge[data-status=\"Cancelled\"] {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.status-badge[data-status=\"Paused\"] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.status-badge.small {\n padding: 4px 12px;\n font-size: 11px;\n}\n\n/* Plan Mode chip \u2014 shown next to the status badge when AIAgentRun.PlanMode = 1 */\n.plan-mode-badge {\n padding: 6px 16px;\n border-radius: 20px;\n font-size: 13px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n}\n\n.header-actions {\n display: flex;\n gap: 8px;\n}\n\n.btn-icon {\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.2s ease;\n color: var(--mj-text-muted);\n}\n\n.btn-icon:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-secondary);\n}\n\n.header-stats {\n display: flex;\n gap: 24px;\n padding-top: 12px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n/* Configuration Bar */\n.configuration-bar {\n display: flex;\n gap: 24px;\n padding-top: 16px;\n border-top: 1px solid var(--mj-border-default);\n margin-top: 16px;\n}\n\n.config-item {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.config-item > i {\n font-size: 1.2em;\n color: var(--mj-text-muted);\n width: 24px;\n text-align: center;\n}\n\n.config-content {\n display: flex;\n flex-direction: column;\n}\n\n.config-label {\n font-size: 12px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.config-value {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.config-value .entity-link {\n color: var(--mj-brand-primary);\n text-decoration: none;\n cursor: pointer;\n transition: color 0.2s;\n}\n\n.config-value .entity-link:hover {\n color: var(--mj-brand-primary-hover);\n text-decoration: underline;\n}\n\n.stat {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.stat .label {\n font-size: 12px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.stat .value {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.stat .value.success {\n color: var(--mj-status-success);\n}\n\n.stat .value.error {\n color: var(--mj-status-error);\n}\n\n/* Tabs */\n.tabs {\n display: flex;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.tab {\n padding: 12px 24px;\n border: none;\n background: transparent;\n cursor: pointer;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n gap: 8px;\n transition: all 0.2s ease;\n border-bottom: 3px solid transparent;\n}\n\n.tab:hover {\n color: var(--mj-text-secondary);\n background: color-mix(in srgb, var(--mj-text-primary) 2%, var(--mj-bg-surface));\n}\n\n.tab.active {\n color: var(--mj-brand-primary);\n border-bottom-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n/* Content Area */\n.content-area {\n position: relative;\n flex: 1;\n min-height: 0;\n overflow: auto;\n background: var(--mj-bg-surface);\n}\n\n.tab-content {\n height: 100%;\n min-height: 0;\n overflow: auto;\n}\n\n/* Details tab accordion panels */\n.tab-content mj-accordion-panel {\n display: block;\n margin-bottom: 8px;\n}\n\n/* JSON Detail Pane */\n.json-detail-pane {\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-sunken);\n border-left: 1px solid var(--mj-border-default);\n}\n\n.json-pane-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.json-pane-header h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.json-pane-header h3 i {\n color: var(--mj-text-muted);\n font-size: 14px;\n}\n\n.json-pane-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: auto;\n padding: 16px;\n}\n\n.json-meta {\n display: flex;\n gap: 20px;\n margin-bottom: 16px;\n flex-wrap: wrap;\n}\n\n.json-meta .meta-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.json-meta .meta-item label {\n font-size: 11px;\n text-transform: uppercase;\n color: var(--mj-text-muted);\n font-weight: 600;\n letter-spacing: 0.5px;\n}\n\n.json-meta .meta-item span {\n font-size: 14px;\n color: var(--mj-text-primary);\n font-weight: 500;\n}\n\n.action-link {\n margin-bottom: 12px;\n}\n\n.action-link .btn-link {\n background: none;\n border: none;\n color: var(--mj-brand-primary);\n font-size: 14px;\n cursor: pointer;\n padding: 6px 12px;\n border-radius: 4px;\n transition: all 0.2s;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n}\n\n.action-link .btn-link:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary-hover);\n}\n\n.json-viewer {\n flex: 1;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n border-radius: 8px;\n border: 1px solid var(--mj-border-default);\n overflow: auto;\n padding: 20px;\n gap: 10px;\n min-height: 0;\n margin-bottom: 45px;\n}\n\n\n.json-toolbar {\n display: flex;\n justify-content: flex-end;\n padding: 8px 12px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n/* Timeline Styles */\n.timeline-container {\n height: 100%;\n overflow-y: auto;\n padding: 20px;\n}\n\n.timeline-container > .timeline {\n max-width: 900px;\n margin: 0 auto;\n}\n\n.timeline {\n position: relative;\n padding-left: 40px;\n}\n\n.timeline::before {\n content: '';\n position: absolute;\n left: 20px;\n top: 0;\n bottom: 0;\n width: 2px;\n background: var(--mj-border-default);\n}\n\n.timeline-item {\n position: relative;\n margin-bottom: 24px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.timeline-item:hover {\n transform: translateX(4px);\n}\n\n.timeline-item.selected {\n transform: translateX(8px);\n}\n\n.timeline-item.selected .timeline-content {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n}\n\n.timeline-marker {\n position: absolute;\n left: -30px;\n top: 0;\n width: 40px;\n height: 40px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-surface);\n border: 3px solid var(--mj-border-default);\n z-index: 1;\n transition: all 0.2s ease;\n}\n\n.timeline-marker[data-color=\"success\"] {\n border-color: var(--mj-status-success);\n color: var(--mj-status-success);\n}\n\n.timeline-marker[data-color=\"error\"] {\n border-color: var(--mj-status-error);\n color: var(--mj-status-error);\n}\n\n.timeline-marker[data-color=\"info\"] {\n border-color: var(--mj-status-info);\n color: var(--mj-status-info);\n}\n\n.timeline-marker[data-color=\"warning\"] {\n border-color: var(--mj-status-warning);\n color: var(--mj-status-warning);\n}\n\n.timeline-marker[data-color=\"secondary\"] {\n border-color: var(--mj-text-muted);\n color: var(--mj-text-muted);\n}\n\n.timeline-marker.small {\n width: 28px;\n height: 28px;\n font-size: 12px;\n}\n\n.timeline-content {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n padding: 16px 20px;\n margin-left: 20px;\n box-shadow: var(--mj-shadow-sm);\n transition: all 0.2s ease;\n}\n\n.timeline-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n\n.timeline-header h4 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.timeline-header h5 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.timeline-time {\n font-size: 12px;\n color: var(--mj-text-muted);\n font-family: monospace;\n}\n\n.timeline-subtitle {\n font-size: 13px;\n color: var(--mj-text-muted);\n margin-bottom: 8px;\n}\n\n.timeline-meta {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.timeline-meta .status {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.timeline-meta .status[data-status=\"Completed\"] {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.timeline-meta .status[data-status=\"Failed\"] {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.timeline-meta .status[data-status=\"Running\"] {\n background: color-mix(in srgb, var(--mj-status-info) 15%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n}\n\n.timeline-meta .status[data-status=\"Paused\"] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.duration {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.timeline-actions {\n position: absolute;\n right: 20px;\n top: 50%;\n transform: translateY(-50%);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.btn-link {\n background: none;\n border: none;\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-size: 12px;\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.2s ease;\n}\n\n.btn-link:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.btn-expand {\n width: 24px;\n height: 24px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.2s ease;\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n.btn-expand:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-secondary);\n}\n\n/* Timeline Children */\n.timeline-children {\n position: relative;\n margin-top: 12px;\n margin-bottom: 12px;\n}\n\n.timeline-children::before {\n content: '';\n position: absolute;\n left: -10px;\n top: -12px;\n bottom: 0;\n width: 2px;\n background: var(--mj-border-default);\n}\n\n.child-item {\n margin-bottom: 12px;\n}\n\n.child-item .timeline-content {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-default);\n}\n\n/* Sub-run timeline styles */\n.sub-run-timeline {\n background: color-mix(in srgb, var(--mj-brand-primary) 2%, var(--mj-bg-surface));\n border-left: 2px solid color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n margin-left: 20px;\n padding-left: 20px;\n margin-top: 8px;\n margin-bottom: 8px;\n}\n\n.sub-run-item .timeline-marker {\n border-width: 2px;\n}\n\n.sub-run-item .timeline-content {\n transition: all 0.2s ease;\n}\n\n/* JSON Detail Pane (in splitter) */\n.json-detail-pane {\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n}\n\n.json-pane-header {\n padding: 16px 20px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-shrink: 0;\n}\n\n.json-pane-header h3 {\n margin: 0;\n font-size: 16px;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 10px;\n font-weight: 600;\n}\n\n.json-pane-content {\n flex: 1;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n}\n\n.json-meta {\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n gap: 20px;\n flex-wrap: wrap;\n flex-shrink: 0;\n}\n\n.json-meta .meta-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.json-meta label {\n font-size: 11px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.json-meta span {\n font-size: 14px;\n color: var(--mj-text-primary);\n font-weight: 500;\n}\n\n.action-link {\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.action-link .btn-link {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-brand-primary);\n text-decoration: none;\n font-size: 14px;\n padding: 8px 12px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n border-radius: 4px;\n transition: all 0.2s;\n cursor: pointer;\n}\n\n.action-link .btn-link:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-color: color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n text-decoration: none;\n}\n\n\n.json-toolbar {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n margin-bottom: 8px;\n}\n\n/* Details Tab */\n.details-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 20px;\n padding: 20px;\n}\n\n.detail-item {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.detail-item.full-width {\n grid-column: 1 / -1;\n}\n\n.detail-item label {\n font-size: 12px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.detail-item span {\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.error-message {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n padding: 12px;\n border-radius: 8px;\n font-size: 13px;\n}\n\n.result-viewer,\n.state-viewer {\n padding: 20px;\n max-height: 450px;\n overflow: auto;\n display: flex;\n flex-direction: column;\n}\n\n.result-viewer mj-code-editor,\n.state-viewer mj-code-editor {\n flex: 1;\n min-height: 0;\n}\n\n/* Empty States */\n.empty-state,\n.loading-state,\n.error-state {\n text-align: center;\n padding: 60px 20px;\n color: var(--mj-text-muted);\n}\n\n.empty-state i,\n.loading-state i,\n.error-state i {\n opacity: 0.3;\n margin-bottom: 16px;\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .header-content {\n flex-direction: column;\n gap: 16px;\n }\n \n .header-stats {\n flex-wrap: wrap;\n }\n \n .json-detail-pane {\n width: 100%;\n }\n \n .timeline {\n padding-left: 30px;\n }\n \n .timeline-marker {\n left: -25px;\n width: 32px;\n height: 32px;\n }\n \n .timeline-content {\n margin-left: 10px;\n }\n}\n\n/* Entity Link Styles */\n.entity-link {\n color: var(--mj-brand-primary);\n text-decoration: none;\n transition: all 0.2s ease;\n border-bottom: 1px solid transparent;\n display: inline-block;\n}\n\n.entity-link:hover {\n color: var(--mj-brand-primary-hover);\n border-bottom-color: var(--mj-brand-primary-hover);\n}\n\n.entity-link:active {\n color: var(--mj-brand-primary-hover);\n}\n\n/* Detail Pane Tabs */\n.detail-pane-tabs {\n display: flex;\n gap: 8px;\n margin: 8px 0 0 0;\n border-bottom: 1px solid var(--mj-border-default);\n padding: 0 16px;\n}\n\n.detail-tab {\n padding: 10px 16px;\n background: none;\n border: none;\n border-bottom: 3px solid transparent;\n color: var(--mj-text-muted);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.detail-tab:hover {\n color: var(--mj-text-secondary);\n background: color-mix(in srgb, var(--mj-text-primary) 2%, var(--mj-bg-surface));\n}\n\n.detail-tab.active {\n color: var(--mj-brand-primary);\n border-bottom-color: var(--mj-brand-primary);\n}\n\n.detail-tab i {\n font-size: 14px;\n}\n\n/* Detail Pane Content */\n.detail-pane-content {\n flex: 1;\n overflow-y: auto;\n min-height: 0;\n margin-bottom: 35px;\n}\n\n.detail-pane-content.with-tabs {\n /* When tabs are shown, content starts right after tabs */\n margin-top: 0;\n}\n\n/* Step Payload Diff */\n.step-payload-diff {\n height: 100%;\n overflow-y: auto;\n padding: 16px;\n}\n\n.step-payload-diff mj-deep-diff {\n display: block;\n height: 100%;\n}\n\n/* JSON Viewer adjustments when no tabs */\n.detail-pane-content:not(.with-tabs) .json-viewer {\n margin-top: 16px;\n}\n/* A detached workflow still executing after its run completed. Blue rather than green or amber: it\n is neither finished nor wrong, it is the same \"workflow\" provenance the timeline uses. */\n.workflow-running-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 12px;\n border-radius: var(--mj-radius-full, 999px);\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n white-space: nowrap;\n}\n"] }]
|
|
1914
2035
|
}], null, { TimelineComponent: [{
|
|
1915
2036
|
type: ViewChild,
|
|
1916
2037
|
args: [AIAgentRunTimelineComponent]
|
|
@@ -1918,5 +2039,5 @@ export { MJAIAgentRunFormComponentExtended };
|
|
|
1918
2039
|
type: ViewChild,
|
|
1919
2040
|
args: [AIAgentRunAnalyticsComponent]
|
|
1920
2041
|
}] }); })();
|
|
1921
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJAIAgentRunFormComponentExtended, { className: "MJAIAgentRunFormComponentExtended", filePath: "src/lib/custom/ai-agent-run/ai-agent-run.component.ts", lineNumber:
|
|
2042
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJAIAgentRunFormComponentExtended, { className: "MJAIAgentRunFormComponentExtended", filePath: "src/lib/custom/ai-agent-run/ai-agent-run.component.ts", lineNumber: 49 }); })();
|
|
1922
2043
|
//# sourceMappingURL=ai-agent-run.component.js.map
|