From a71be390762189a6172942ebf2e67812b2c3384e Mon Sep 17 00:00:00 2001 From: Andrii Arsenin Date: Tue, 14 Apr 2026 21:11:35 +0300 Subject: [PATCH] fix: fix links in scenario service --- client/src/pages/run/RunDetailPage.tsx | 47 ++++++++++--------- .../src/pages/scenario/ScenarioDetailPage.tsx | 1 - client/src/pages/scenario/ScenariosPage.tsx | 1 - server/src/scenario/scenario-run.entity.ts | 8 ++-- .../scenario/scenario-scheduler.service.ts | 34 ++++++++------ server/src/scenario/scenario.service.ts | 4 +- 6 files changed, 50 insertions(+), 45 deletions(-) diff --git a/client/src/pages/run/RunDetailPage.tsx b/client/src/pages/run/RunDetailPage.tsx index 2e8abf3..02370ba 100644 --- a/client/src/pages/run/RunDetailPage.tsx +++ b/client/src/pages/run/RunDetailPage.tsx @@ -291,7 +291,7 @@ export function RunDetailPage() { items={[ { label: t('scenarios.title'), icon: , onClick: () => navigate('/scenarios') }, { - label: scenario?.name ?? `#${id}`, + label: scenario?.name ?? `${id}`, onClick: () => navigate(`/scenarios/${id}`), }, { @@ -299,7 +299,7 @@ export function RunDetailPage() { icon: , onClick: () => navigate(`/scenarios/${id}/runs`), }, - { label: `#${runId}` }, + { label: `${runId}` }, ]} /> @@ -312,27 +312,28 @@ export function RunDetailPage() { }, - { - term: t('runs.field_status'), - detail: ( - - {RUN_STATUS_LABEL[run.status]} - - ), - }, - { 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}, - }] : []), - ]} + items={(() => { + const items = [ + { term: t('runs.field_id'), detail: }, + { + term: t('runs.field_status'), + detail: ( + + {RUN_STATUS_LABEL[run.status]} + + ), + }, + { term: t('runs.field_created'), detail: }, + { term: t('runs.field_updated'), detail: }, + ]; + if (run.environment) { + items.push({ term: 'Environment', detail: {run.environment.name} }); + } + if (run.session) { + items.push({ term: 'Session', detail: {run.session.sessionName} }); + } + return items; + })()} /> diff --git a/client/src/pages/scenario/ScenarioDetailPage.tsx b/client/src/pages/scenario/ScenarioDetailPage.tsx index 4ae5e30..b606b3f 100644 --- a/client/src/pages/scenario/ScenarioDetailPage.tsx +++ b/client/src/pages/scenario/ScenarioDetailPage.tsx @@ -559,7 +559,6 @@ export function ScenarioDetailPage() { type="checkbox" checked={saveSessionFlag} onChange={(e) => setSaveSessionFlag(e.target.checked)} - disabled /> Save session diff --git a/client/src/pages/scenario/ScenariosPage.tsx b/client/src/pages/scenario/ScenariosPage.tsx index 0ba756f..57d3e7e 100644 --- a/client/src/pages/scenario/ScenariosPage.tsx +++ b/client/src/pages/scenario/ScenariosPage.tsx @@ -222,7 +222,6 @@ export function ScenariosPage() { type="checkbox" checked={saveSessionFlag} onChange={(e) => setSaveSessionFlag(e.target.checked)} - disabled /> Save session diff --git a/server/src/scenario/scenario-run.entity.ts b/server/src/scenario/scenario-run.entity.ts index 6c4895b..632f55c 100644 --- a/server/src/scenario/scenario-run.entity.ts +++ b/server/src/scenario/scenario-run.entity.ts @@ -8,10 +8,10 @@ import { PrimaryGeneratedColumn, UpdateDateColumn, } 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"; +import { ScenarioRunStepEntity } from "./scenario-run-step.entity"; +import { ScenarioEntity } from "./scenario.entity"; export type RunStatus = "pending" | "in_progress" | "pass" | "fail"; @@ -23,8 +23,8 @@ export class ScenarioRunEntity { @Column("text") scenarioId: string; - @Column("text", { default: "" }) - environmentId: string; + @Column("text", { nullable: true, default: null }) + environmentId: string | null; @ManyToOne(() => ScenarioEntity, { onDelete: "CASCADE" }) @JoinColumn({ name: "scenarioId" }) diff --git a/server/src/scenario/scenario-scheduler.service.ts b/server/src/scenario/scenario-scheduler.service.ts index c687c45..15002f6 100644 --- a/server/src/scenario/scenario-scheduler.service.ts +++ b/server/src/scenario/scenario-scheduler.service.ts @@ -7,6 +7,7 @@ import { chromium } from "playwright"; import { Repository } from "typeorm"; import type { ScriptLogger } from "../code-executor/code-executor.service"; import { CodeExecutorService } from "../code-executor/code-executor.service"; +import { ExecContextBuilder } from "../code-executor/exec-context.builder"; import { traceStorage } from "../common/trace-context"; import { TraceLogger } from "../common/trace-logger"; import { EnvironmentData, EnvironmentEntity } from "../environment/environment.entity"; @@ -170,7 +171,9 @@ export class ScenarioSchedulerService { } const handle = this.runBrowsers.get(runId); - if (!handle) return; + if (!handle) { + return; + } const sessionName = `run-${runId}`; try { @@ -184,7 +187,8 @@ export class ScenarioSchedulerService { cookies.find((c) => c.name === "token")?.value ?? ""; - await this.sessionService.upsert(sessionName, token, cookies, localStorage); + const session = await this.sessionService.upsert(sessionName, token, cookies, localStorage); + await this.runRepo.update(runId, { sessionId: session.id }); this.sessionContextService.register( sessionName, handle.browser, @@ -194,7 +198,7 @@ export class ScenarioSchedulerService { // Remove from runBrowsers so closeBrowserHandle won't close it this.runBrowsers.delete(runId); this.logger.log( - `Run #${runId}: browser preserved as session "${sessionName}"`, + `Run #${runId}: browser preserved as session "${sessionName}" (${session.id})`, ); } catch (err) { this.logger.warn( @@ -223,16 +227,17 @@ export class ScenarioSchedulerService { const creds = this.runCredentials.get(stepRun.runId); const snips = this.runSnippets.get(stepRun.runId); const env = this.runEnvironments.get(stepRun.runId); - const { result: execOutput } = await this.codeExecutor.execute({ - page, - browser: context, - code: step.execCode, - log: this.stepLogger(stepRun.id, stepRun.runId), - getStepOutput, - credentials: creds, - environment: env, - snippets: snips, - }); + const execCtx = new ExecContextBuilder() + .page(page) + .browser(context) + .code(step.execCode) + .log(this.stepLogger(stepRun.id, stepRun.runId)) + .getStepOutput(getStepOutput) + .credentials(creds) + .environment(env) + .snippets(snips) + .build(); + const { result: execOutput } = await this.codeExecutor.execute(execCtx); await this.passStepRun(stepRun, null, execOutput); } catch (err) { @@ -310,7 +315,8 @@ export class ScenarioSchedulerService { ], }); if (remaining === 0) { - await this.closeBrowserHandle(stepRun.runId); + // Don't close the browser here — maybePreserveSession will handle it + // (either preserving it if saveSession=true, or closing if false) await this.runRepo.update(stepRun.runId, { status: "pass" }); this.logger.log(`Run #${stepRun.runId} → pass (all steps passed)`); } diff --git a/server/src/scenario/scenario.service.ts b/server/src/scenario/scenario.service.ts index e7275eb..b84ca20 100644 --- a/server/src/scenario/scenario.service.ts +++ b/server/src/scenario/scenario.service.ts @@ -322,7 +322,7 @@ export class ScenarioService { await this.findOne(scenarioId); // 404 guard const run = await this.runRepo.findOne({ where: { id: runId, scenarioId }, - relations: ["stepRuns", "stepRuns.scenarioStep"], + relations: ["stepRuns", "stepRuns.scenarioStep", "environment", "session"], order: { stepRuns: { order: "ASC" } }, }); if (!run) @@ -387,7 +387,7 @@ export class ScenarioService { return this.runRepo.findOne({ where: { id: run.id }, - relations: ["stepRuns"], + relations: ["stepRuns", "environment", "session"], order: { stepRuns: { order: "ASC" } }, }) as Promise; }