From 5ec9fd0bc363ed5b4afcec546d9ef158defeb7d3 Mon Sep 17 00:00:00 2001 From: Andrii Arsenin Date: Tue, 14 Apr 2026 19:29:48 +0300 Subject: [PATCH] refactor: add session and environment relationships to scenario run - add sessionId optional column to ScenarioRunEntity - add ManyToOne relationship to EnvironmentEntity (with eager loading) - add ManyToOne relationship to SessionEntity (optional) - update ScenarioRun client types to include session and environment data - add environment name and session link to RunDetailPage - update UI to display save session, environment, and session info --- client/src/api/types.ts | 3 +++ client/src/pages/run/RunDetailPage.tsx | 10 +++++++++- client/src/pages/scenario/ScenarioDetailPage.tsx | 4 ++-- client/src/pages/scenario/ScenariosPage.tsx | 4 ++-- server/src/mcp/mcp.service.ts | 2 +- server/src/scenario/scenario-run.entity.ts | 13 +++++++++++++ 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/client/src/api/types.ts b/client/src/api/types.ts index c2a1700..09f5d2c 100644 --- a/client/src/api/types.ts +++ b/client/src/api/types.ts @@ -98,8 +98,11 @@ export interface ScenarioRun { id: string; scenarioId: string; environmentId: string; + sessionId?: string | null; saveSession: boolean; scenario?: Pick; + environment?: Pick; + session?: { id: string; sessionName: string }; status: ScenarioRunStatus; stepRuns?: ScenarioRunStep[]; createdAt: string; diff --git a/client/src/pages/run/RunDetailPage.tsx b/client/src/pages/run/RunDetailPage.tsx index 0da2860..2e8abf3 100644 --- a/client/src/pages/run/RunDetailPage.tsx +++ b/client/src/pages/run/RunDetailPage.tsx @@ -1,5 +1,5 @@ import { useEffect, useRef, useState } from 'react'; -import { useNavigate, useParams } from 'react-router-dom'; +import { useNavigate, useParams, Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { runs } from '../../api'; import type { @@ -324,6 +324,14 @@ export function RunDetailPage() { }, { term: t('runs.field_created'), detail: }, { term: t('runs.field_updated'), detail: }, + ...(run.environment ? [{ + term: 'Environment', + detail: {run.environment.name}, + }] : []), + ...(run.session ? [{ + term: 'Session', + detail: {run.session.sessionName}, + }] : []), ]} /> diff --git a/client/src/pages/scenario/ScenarioDetailPage.tsx b/client/src/pages/scenario/ScenarioDetailPage.tsx index b767d1e..4ae5e30 100644 --- a/client/src/pages/scenario/ScenarioDetailPage.tsx +++ b/client/src/pages/scenario/ScenarioDetailPage.tsx @@ -559,9 +559,9 @@ export function ScenarioDetailPage() { type="checkbox" checked={saveSessionFlag} onChange={(e) => setSaveSessionFlag(e.target.checked)} - disabled={running} + disabled /> - Save session for explore mode + Save session )} diff --git a/client/src/pages/scenario/ScenariosPage.tsx b/client/src/pages/scenario/ScenariosPage.tsx index e29f202..0ba756f 100644 --- a/client/src/pages/scenario/ScenariosPage.tsx +++ b/client/src/pages/scenario/ScenariosPage.tsx @@ -222,9 +222,9 @@ export function ScenariosPage() { type="checkbox" checked={saveSessionFlag} onChange={(e) => setSaveSessionFlag(e.target.checked)} - disabled={running} + disabled /> - Save session for explore mode + Save session )} diff --git a/server/src/mcp/mcp.service.ts b/server/src/mcp/mcp.service.ts index 5590f5b..9d50814 100644 --- a/server/src/mcp/mcp.service.ts +++ b/server/src/mcp/mcp.service.ts @@ -703,7 +703,7 @@ export class McpService { inputSchema: { id: z.uuid().describe("Scenario ID to run"), environmentId: z.uuid().describe("Environment ID to run the scenario in"), - saveSession: z.boolean().optional().describe("Save session for explore mode after run completes"), + saveSession: z.boolean().optional().describe("Save session after run completes"), }, }, async ({ id, environmentId, saveSession }) => { diff --git a/server/src/scenario/scenario-run.entity.ts b/server/src/scenario/scenario-run.entity.ts index aee0259..6c4895b 100644 --- a/server/src/scenario/scenario-run.entity.ts +++ b/server/src/scenario/scenario-run.entity.ts @@ -10,6 +10,8 @@ import { } from "typeorm"; import { ScenarioRunStepEntity } from "./scenario-run-step.entity"; import { ScenarioEntity } from "./scenario.entity"; +import { EnvironmentEntity } from "../environment/environment.entity"; +import { SessionEntity } from "../session/session.entity"; export type RunStatus = "pending" | "in_progress" | "pass" | "fail"; @@ -28,6 +30,17 @@ export class ScenarioRunEntity { @JoinColumn({ name: "scenarioId" }) scenario: ScenarioEntity; + @ManyToOne(() => EnvironmentEntity, { onDelete: "SET NULL", nullable: true }) + @JoinColumn({ name: "environmentId" }) + environment: EnvironmentEntity; + + @Column("text", { nullable: true, default: null }) + sessionId: string | null; + + @ManyToOne(() => SessionEntity, { onDelete: "SET NULL", nullable: true }) + @JoinColumn({ name: "sessionId" }) + session: SessionEntity | null; + @Column({ type: "text", default: "pending" }) status: RunStatus;