feat: add saveSession flag to create scenario runs

- Add optional `saveSession` boolean parameter to CreateScenarioRunDto
- Add `saveSession` column to ScenarioRunEntity
- When saveSession=true and run completes, preserve the browser context as a named explore session instead of closing it
- Session name follows pattern: run-{runId}
- Automatically extracts token and localStorage for session persistence
- Injected SessionService and SessionContextService into ScenarioSchedulerService
- Updated MCP run_scenario tool to accept saveSession parameter
- Updated UI run dialog with checkbox to enable session preservation
- Client API updated to pass saveSession flag
This commit is contained in:
2026-04-14 18:54:45 +03:00
parent 0e47623a6b
commit 196bf4c2e8
9 changed files with 88 additions and 14 deletions
+2 -2
View File
@@ -192,10 +192,10 @@ export const scenarios = {
remove(id: string): Promise<void> {
return request(`/scenarios/${id}`, { method: 'DELETE' });
},
run(id: string, environmentId: string): Promise<ScenarioRun> {
run(id: string, environmentId: string, saveSession?: boolean): Promise<ScenarioRun> {
return request(`/scenarios/${id}/run`, {
method: 'POST',
body: JSON.stringify({ environmentId }),
body: JSON.stringify({ environmentId, saveSession }),
});
},
getRun(scenarioId: string, runId: string): Promise<ScenarioRunDetail> {
+1
View File
@@ -98,6 +98,7 @@ export interface ScenarioRun {
id: string;
scenarioId: string;
environmentId: string;
saveSession: boolean;
scenario?: Pick<Scenario, 'id' | 'name'>;
status: ScenarioRunStatus;
stepRuns?: ScenarioRunStep[];
@@ -44,6 +44,7 @@ export function ScenarioDetailPage() {
const [reorderingSteps, setReorderingSteps] = useState(false);
const [runModalOpen, setRunModalOpen] = useState(false);
const [running, setRunning] = useState(false);
const [saveSessionFlag, setSaveSessionFlag] = useState(false);
const [envs, setEnvs] = useState<Environment[]>([]);
const [selectedEnvId, setSelectedEnvId] = useState('');
const [pendingDelete, setPendingDelete] = useState<
@@ -89,10 +90,11 @@ export function ScenarioDetailPage() {
}
setRunning(true);
try {
const run = await scenarios.run(scenario.id, selectedEnvId);
const run = await scenarios.run(scenario.id, selectedEnvId, saveSessionFlag);
toast.success('Scenario run started');
navigate(`/scenarios/${id}/runs/${run.id}`);
setRunModalOpen(false);
setSaveSessionFlag(false);
} catch (err) {
toast.error((err as Error).message);
} finally {
@@ -545,12 +547,23 @@ export function ScenarioDetailPage() {
{envs.length === 0 ? (
<p>{t('scenarios.run_modal_no_env')}</p>
) : (
<Select
label={t('scenarios.run_modal_env_label')}
value={selectedEnvId}
onChange={(e) => setSelectedEnvId(e.target.value)}
options={envs.map((env) => ({ value: env.id, label: env.name }))}
/>
<>
<Select
label={t('scenarios.run_modal_env_label')}
value={selectedEnvId}
onChange={(e) => setSelectedEnvId(e.target.value)}
options={envs.map((env) => ({ value: env.id, label: env.name }))}
/>
<label style={{ display: 'flex', alignItems: 'center', marginTop: '1rem', gap: '0.5rem' }}>
<input
type="checkbox"
checked={saveSessionFlag}
onChange={(e) => setSaveSessionFlag(e.target.checked)}
disabled={running}
/>
<span>Save session for explore mode</span>
</label>
</>
)}
</Modal>
</div>