feat(sessions): add detail page, Notification component, and session API improvements

- add SessionDetailPage with breadcrumbs, DescriptionList, status badge, masked token
- add Notification component (info/success/error/warning/note variants) for contextual messages
- use Notification for 404 errors on session and environment detail pages
- add GET /sessions/:id endpoint; sanitize token (head…tail) and strip cookies/localStorage
- change DELETE /sessions/:id to return 204 No Content so client redirect works correctly
- add onRowClick prop to Table for clickable rows; stop propagation on actions column
- update status badges: open=success (green), closed=error (red) on both list and detail
This commit is contained in:
2026-04-09 19:00:16 +03:00
parent 097c747993
commit d342637eb6
14 changed files with 290 additions and 11 deletions
+1
View File
@@ -1,5 +1,6 @@
{
"name": "liquio-qa-bot",
"version": "1.2.0",
"description": "",
"main": "index.js",
"scripts": {
+23 -1
View File
@@ -2,6 +2,8 @@ import {
Controller,
Delete,
Get,
HttpCode,
NotFoundException,
Param,
ParseIntPipe,
Query,
@@ -12,6 +14,11 @@ import { SessionContextService } from "./session-context.service";
import { PaginationQueryDto } from "../common/dto/pagination.dto";
import { SessionOrderBy } from "./session.service";
function maskToken(token: string, head = 6, tail = 4): string {
if (token.length <= head + tail + 1) return token;
return `${token.slice(0, head)}\u2026${token.slice(-tail)}`;
}
@ApiTags("sessions")
@Controller("sessions")
export class SessionController {
@@ -27,9 +34,24 @@ export class SessionController {
return this.sessionService.findAll(query);
}
@Get(":id")
@ApiOperation({ summary: "Get a session by ID" })
@ApiResponse({ status: 200, description: "Session found" })
@ApiResponse({ status: 404, description: "Session not found" })
async findOne(@Param("id", ParseIntPipe) id: number) {
const session = await this.sessionService.findById(id);
if (!session) throw new NotFoundException(`Session ${id} not found`);
const { token, cookies, localStorage, ...rest } = session;
return {
...rest,
token: maskToken(token),
};
}
@Delete(":id")
@HttpCode(204)
@ApiOperation({ summary: "Delete a session by ID (closes it first if open)" })
@ApiResponse({ status: 200, description: "Session deleted" })
@ApiResponse({ status: 204, description: "Session deleted" })
@ApiResponse({ status: 404, description: "Session not found" })
async remove(@Param("id", ParseIntPipe) id: number): Promise<void> {
await this.sessionContextService.delete(id);