feat(export-import): add yaml export/import with id upsert for credentials, snippets, and scenarios
- all entities export a kind field (credential/snippet/scenario) for safe type checking on import - import upserts by id: overwrites if id exists, creates with explicit id otherwise - scenario export now includes id and step ids; import deletes old steps before recreating - add GET /:id/export and POST /import endpoints to credential and snippet controllers - add UuidBadge ui component: shortens uuid to first+last 4 hex chars, tooltip, clipboard copy with animated ClipboardCheck icon pop - apply UuidBadge across all entity id display sites (detail pages, card footers, table columns) - add export/import buttons to CredentialsPage, SnippetsPage, CredentialDetailPage, SnippetDetailPage
This commit is contained in:
@@ -5,7 +5,7 @@ import {
|
||||
Get,
|
||||
HttpCode,
|
||||
Param,
|
||||
ParseIntPipe,
|
||||
ParseUUIDPipe,
|
||||
Patch,
|
||||
Post,
|
||||
Query,
|
||||
@@ -61,7 +61,7 @@ export class ScenarioController {
|
||||
@ApiOperation({ summary: "Get a scenario with its steps" })
|
||||
@ApiResponse({ status: 200 })
|
||||
@ApiResponse({ status: 404, description: "Scenario not found" })
|
||||
findOne(@Param("id", ParseIntPipe) id: number) {
|
||||
findOne(@Param("id", ParseUUIDPipe) id: string) {
|
||||
return this.scenarioService.findOne(id);
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ export class ScenarioController {
|
||||
@ApiResponse({ status: 200 })
|
||||
@ApiResponse({ status: 404, description: "Scenario not found" })
|
||||
update(
|
||||
@Param("id", ParseIntPipe) id: number,
|
||||
@Param("id", ParseUUIDPipe) id: string,
|
||||
@Body() dto: UpdateScenarioDto,
|
||||
) {
|
||||
return this.scenarioService.update(id, dto);
|
||||
@@ -81,7 +81,7 @@ export class ScenarioController {
|
||||
@ApiOperation({ summary: "Delete a scenario and all its steps" })
|
||||
@ApiResponse({ status: 204 })
|
||||
@ApiResponse({ status: 404, description: "Scenario not found" })
|
||||
remove(@Param("id", ParseIntPipe) id: number) {
|
||||
remove(@Param("id", ParseUUIDPipe) id: string) {
|
||||
return this.scenarioService.remove(id);
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ export class ScenarioController {
|
||||
@ApiOperation({ summary: "Export a scenario as a portable JSON payload" })
|
||||
@ApiResponse({ status: 200 })
|
||||
@ApiResponse({ status: 404, description: "Scenario not found" })
|
||||
exportScenario(@Param("id", ParseIntPipe) id: number) {
|
||||
exportScenario(@Param("id", ParseUUIDPipe) id: string) {
|
||||
return this.scenarioService.exportScenario(id);
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ export class ScenarioController {
|
||||
@ApiResponse({ status: 201, description: "Step created" })
|
||||
@ApiResponse({ status: 404, description: "Scenario not found" })
|
||||
createStep(
|
||||
@Param("id", ParseIntPipe) id: number,
|
||||
@Param("id", ParseUUIDPipe) id: string,
|
||||
@Body() dto: CreateScenarioStepDto,
|
||||
) {
|
||||
return this.scenarioService.createStep(id, dto);
|
||||
@@ -111,8 +111,8 @@ export class ScenarioController {
|
||||
@ApiResponse({ status: 200 })
|
||||
@ApiResponse({ status: 404, description: "Scenario or step not found" })
|
||||
findStep(
|
||||
@Param("id", ParseIntPipe) id: number,
|
||||
@Param("stepId", ParseIntPipe) stepId: number,
|
||||
@Param("id", ParseUUIDPipe) id: string,
|
||||
@Param("stepId", ParseUUIDPipe) stepId: string,
|
||||
) {
|
||||
return this.scenarioService.findStep(id, stepId);
|
||||
}
|
||||
@@ -122,8 +122,8 @@ export class ScenarioController {
|
||||
@ApiResponse({ status: 200 })
|
||||
@ApiResponse({ status: 404, description: "Scenario or step not found" })
|
||||
updateStep(
|
||||
@Param("id", ParseIntPipe) id: number,
|
||||
@Param("stepId", ParseIntPipe) stepId: number,
|
||||
@Param("id", ParseUUIDPipe) id: string,
|
||||
@Param("stepId", ParseUUIDPipe) stepId: string,
|
||||
@Body() dto: UpdateScenarioStepDto,
|
||||
) {
|
||||
return this.scenarioService.updateStep(id, stepId, dto);
|
||||
@@ -135,8 +135,8 @@ export class ScenarioController {
|
||||
@ApiResponse({ status: 204 })
|
||||
@ApiResponse({ status: 404, description: "Scenario or step not found" })
|
||||
removeStep(
|
||||
@Param("id", ParseIntPipe) id: number,
|
||||
@Param("stepId", ParseIntPipe) stepId: number,
|
||||
@Param("id", ParseUUIDPipe) id: string,
|
||||
@Param("stepId", ParseUUIDPipe) stepId: string,
|
||||
) {
|
||||
return this.scenarioService.removeStep(id, stepId);
|
||||
}
|
||||
@@ -147,7 +147,7 @@ export class ScenarioController {
|
||||
@ApiOperation({ summary: "List credentials assigned to a scenario" })
|
||||
@ApiResponse({ status: 200 })
|
||||
@ApiResponse({ status: 404, description: "Scenario not found" })
|
||||
findScenarioCredentials(@Param("id", ParseIntPipe) id: number) {
|
||||
findScenarioCredentials(@Param("id", ParseUUIDPipe) id: string) {
|
||||
return this.scenarioService.findScenarioCredentials(id);
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ export class ScenarioController {
|
||||
@ApiResponse({ status: 404, description: "Scenario or credential not found" })
|
||||
@ApiResponse({ status: 409, description: "Alias already used in this scenario" })
|
||||
addScenarioCredential(
|
||||
@Param("id", ParseIntPipe) id: number,
|
||||
@Param("id", ParseUUIDPipe) id: string,
|
||||
@Body() dto: AddScenarioCredentialDto,
|
||||
) {
|
||||
return this.scenarioService.addScenarioCredential(id, dto);
|
||||
@@ -169,8 +169,8 @@ export class ScenarioController {
|
||||
@ApiResponse({ status: 204 })
|
||||
@ApiResponse({ status: 404, description: "Scenario or credential assignment not found" })
|
||||
removeScenarioCredential(
|
||||
@Param("id", ParseIntPipe) id: number,
|
||||
@Param("scCredId", ParseIntPipe) scCredId: number,
|
||||
@Param("id", ParseUUIDPipe) id: string,
|
||||
@Param("scCredId", ParseUUIDPipe) scCredId: string,
|
||||
) {
|
||||
return this.scenarioService.removeScenarioCredential(id, scCredId);
|
||||
}
|
||||
@@ -184,7 +184,7 @@ export class ScenarioController {
|
||||
@ApiResponse({ status: 200 })
|
||||
@ApiResponse({ status: 404, description: "Scenario not found" })
|
||||
findRuns(
|
||||
@Param("id", ParseIntPipe) id: number,
|
||||
@Param("id", ParseUUIDPipe) id: string,
|
||||
@Query() query: RunsQueryDto,
|
||||
) {
|
||||
return this.scenarioService.findRuns(id, query);
|
||||
@@ -194,7 +194,7 @@ export class ScenarioController {
|
||||
@ApiOperation({ summary: "Create a new run for a scenario" })
|
||||
@ApiResponse({ status: 201, description: "Run created with step runs" })
|
||||
@ApiResponse({ status: 404, description: "Scenario not found" })
|
||||
createRun(@Param("id", ParseIntPipe) id: number) {
|
||||
createRun(@Param("id", ParseUUIDPipe) id: string) {
|
||||
return this.scenarioService.createRun(id);
|
||||
}
|
||||
|
||||
@@ -203,8 +203,8 @@ export class ScenarioController {
|
||||
@ApiResponse({ status: 200 })
|
||||
@ApiResponse({ status: 404, description: "Scenario or run not found" })
|
||||
findRun(
|
||||
@Param("id", ParseIntPipe) id: number,
|
||||
@Param("runId", ParseIntPipe) runId: number,
|
||||
@Param("id", ParseUUIDPipe) id: string,
|
||||
@Param("runId", ParseUUIDPipe) runId: string,
|
||||
) {
|
||||
return this.scenarioService.findRun(id, runId);
|
||||
}
|
||||
@@ -218,8 +218,8 @@ export class ScenarioController {
|
||||
@ApiResponse({ status: 200 })
|
||||
@ApiResponse({ status: 404, description: "Scenario or run not found" })
|
||||
waitForRun(
|
||||
@Param("id", ParseIntPipe) id: number,
|
||||
@Param("runId", ParseIntPipe) runId: number,
|
||||
@Param("id", ParseUUIDPipe) id: string,
|
||||
@Param("runId", ParseUUIDPipe) runId: string,
|
||||
) {
|
||||
return this.scenarioService.waitForRun(id, runId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user