feat(runs): add log search with backend LIKE filter and pagination

- add Search pill component with lucide icon and focus highlight
- wire debounced search input to GET /run/:id?q= backend filter
- backend filters run logs with LIKE %q% via TypeORM
- add sectionHeadingRow layout for heading + search alignment
- add i18n keys: runs.step_title, logs_search_placeholder
This commit is contained in:
2026-04-10 15:09:05 +03:00
parent fd655c3253
commit 2046e64428
9 changed files with 119 additions and 9 deletions
+2 -1
View File
@@ -205,8 +205,9 @@ export class ScenarioController {
findRun(
@Param("id", ParseUUIDPipe) id: string,
@Param("runId", ParseUUIDPipe) runId: string,
@Query("q") q?: string,
) {
return this.scenarioService.findRun(id, runId);
return this.scenarioService.findRun(id, runId, q);
}
@Post(":id/run/:runId/wait")
+3 -2
View File
@@ -1,6 +1,6 @@
import { ConflictException, Injectable, NotFoundException } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { Like, Repository } from "typeorm";
import { ScenarioEntity } from "./scenario.entity";
import { ScenarioStepEntity } from "./scenario-step.entity";
import { ScenarioRunEntity } from "./scenario-run.entity";
@@ -247,6 +247,7 @@ export class ScenarioService {
async findRun(
scenarioId: string,
runId: string,
q?: string,
): Promise<ScenarioRunEntity & { logs: ScenarioRunLogEntity[] }> {
await this.findOne(scenarioId); // 404 guard
const run = await this.runRepo.findOne({
@@ -259,7 +260,7 @@ export class ScenarioService {
`Run ${runId} not found in scenario ${scenarioId}`,
);
const logs = await this.runLogRepo.find({
where: { runId },
where: q?.trim() ? { runId, message: Like(`%${q.trim()}%`) } : { runId },
order: { createdAt: "ASC" },
});
return Object.assign(run, { logs });