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
This commit is contained in:
@@ -98,8 +98,11 @@ export interface ScenarioRun {
|
|||||||
id: string;
|
id: string;
|
||||||
scenarioId: string;
|
scenarioId: string;
|
||||||
environmentId: string;
|
environmentId: string;
|
||||||
|
sessionId?: string | null;
|
||||||
saveSession: boolean;
|
saveSession: boolean;
|
||||||
scenario?: Pick<Scenario, 'id' | 'name'>;
|
scenario?: Pick<Scenario, 'id' | 'name'>;
|
||||||
|
environment?: Pick<Environment, 'id' | 'name'>;
|
||||||
|
session?: { id: string; sessionName: string };
|
||||||
status: ScenarioRunStatus;
|
status: ScenarioRunStatus;
|
||||||
stepRuns?: ScenarioRunStep[];
|
stepRuns?: ScenarioRunStep[];
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useRef, useState } from 'react';
|
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 { useTranslation } from 'react-i18next';
|
||||||
import { runs } from '../../api';
|
import { runs } from '../../api';
|
||||||
import type {
|
import type {
|
||||||
@@ -324,6 +324,14 @@ export function RunDetailPage() {
|
|||||||
},
|
},
|
||||||
{ term: t('runs.field_created'), detail: <Timestamp value={run.createdAt} /> },
|
{ term: t('runs.field_created'), detail: <Timestamp value={run.createdAt} /> },
|
||||||
{ term: t('runs.field_updated'), detail: <Timestamp value={run.updatedAt} /> },
|
{ term: t('runs.field_updated'), detail: <Timestamp value={run.updatedAt} /> },
|
||||||
|
...(run.environment ? [{
|
||||||
|
term: 'Environment',
|
||||||
|
detail: <span style={{ color: 'var(--color-link)', cursor: 'pointer' }}>{run.environment.name}</span>,
|
||||||
|
}] : []),
|
||||||
|
...(run.session ? [{
|
||||||
|
term: 'Session',
|
||||||
|
detail: <Link to={`/sessions/${run.session.id}`} style={{ color: 'var(--color-link)' }}>{run.session.sessionName}</Link>,
|
||||||
|
}] : []),
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -559,9 +559,9 @@ export function ScenarioDetailPage() {
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={saveSessionFlag}
|
checked={saveSessionFlag}
|
||||||
onChange={(e) => setSaveSessionFlag(e.target.checked)}
|
onChange={(e) => setSaveSessionFlag(e.target.checked)}
|
||||||
disabled={running}
|
disabled
|
||||||
/>
|
/>
|
||||||
<span>Save session for explore mode</span>
|
<span>Save session</span>
|
||||||
</label>
|
</label>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -222,9 +222,9 @@ export function ScenariosPage() {
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={saveSessionFlag}
|
checked={saveSessionFlag}
|
||||||
onChange={(e) => setSaveSessionFlag(e.target.checked)}
|
onChange={(e) => setSaveSessionFlag(e.target.checked)}
|
||||||
disabled={running}
|
disabled
|
||||||
/>
|
/>
|
||||||
<span>Save session for explore mode</span>
|
<span>Save session</span>
|
||||||
</label>
|
</label>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -703,7 +703,7 @@ export class McpService {
|
|||||||
inputSchema: {
|
inputSchema: {
|
||||||
id: z.uuid().describe("Scenario ID to run"),
|
id: z.uuid().describe("Scenario ID to run"),
|
||||||
environmentId: z.uuid().describe("Environment ID to run the scenario in"),
|
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 }) => {
|
async ({ id, environmentId, saveSession }) => {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import {
|
|||||||
} from "typeorm";
|
} from "typeorm";
|
||||||
import { ScenarioRunStepEntity } from "./scenario-run-step.entity";
|
import { ScenarioRunStepEntity } from "./scenario-run-step.entity";
|
||||||
import { ScenarioEntity } from "./scenario.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";
|
export type RunStatus = "pending" | "in_progress" | "pass" | "fail";
|
||||||
|
|
||||||
@@ -28,6 +30,17 @@ export class ScenarioRunEntity {
|
|||||||
@JoinColumn({ name: "scenarioId" })
|
@JoinColumn({ name: "scenarioId" })
|
||||||
scenario: ScenarioEntity;
|
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" })
|
@Column({ type: "text", default: "pending" })
|
||||||
status: RunStatus;
|
status: RunStatus;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user