feat(snippets): add snippets entity, crud, and auto-browser-per-run

- add Snippet entity with name, description, code; full CRUD backend
- add snippets pages (list, create, edit, detail) and nav entry
- add runSnippet helper in code-executor using new Function with args array
- add result param to execute() so validateCode can access exec output
- remove sessionName from steps; each run now spawns its own fresh browser
- fix waitForURL race by polling localStorage for token instead
This commit is contained in:
2026-04-10 00:22:51 +03:00
parent 1efbbb38a3
commit 1164289173
26 changed files with 876 additions and 89 deletions
+27 -2
View File
@@ -10,6 +10,7 @@ import type {
ScenarioRunDetail,
ScenarioRunStep,
ScenarioStep,
Snippet,
} from './types';
// In dev, Vite proxies /environments /sessions /scenarios /keys to localhost:3000.
@@ -58,6 +59,32 @@ export const credentials = {
},
};
// ── Snippets ──────────────────────────────────────────────────────────────────
export const snippets = {
list(page = 1, limit = 50): Promise<PaginatedResponse<Snippet>> {
return request(`/snippets?page=${page}&limit=${limit}`);
},
get(id: number): Promise<Snippet> {
return request(`/snippets/${id}`);
},
create(payload: Pick<Snippet, 'name' | 'code'> & { description?: string }): Promise<Snippet> {
return request('/snippets', {
method: 'POST',
body: JSON.stringify(payload),
});
},
update(id: number, patch: Partial<Pick<Snippet, 'name' | 'description' | 'code'>>): Promise<Snippet> {
return request(`/snippets/${id}`, {
method: 'PATCH',
body: JSON.stringify(patch),
});
},
remove(id: number): Promise<void> {
return request(`/snippets/${id}`, { method: 'DELETE' });
},
};
// ── Environments ──────────────────────────────────────────────────────────────
export const environments = {
@@ -184,7 +211,6 @@ export interface CreateStepPayload {
title?: string;
order: number;
type: 'login' | 'exec' | 'sign';
sessionName: string;
execCode?: string;
validateCode?: string;
}
@@ -193,7 +219,6 @@ export interface UpdateStepPayload {
title?: string;
order?: number;
type?: 'login' | 'exec' | 'sign';
sessionName?: string;
execCode?: string;
validateCode?: string;
}