Incident jde otevrit a posunout do dalsiho stavu
Seznam incidentu ukazoval jen titulek a casy, server pritom posilal impact i diagnostiku. Novy detail /dashboard/incidenty/🆔 co to znamena, ticket, zdroj, pro spravce platformy cela diagnostika s kopirovanim. Stav jde posunout (zkoumame, pricina znama, sledujeme, vyreseno), vyreseny vratit do sledovani. Nove pravo incident.manage, platformni incident meni jen spravce platformy, zmena jde do auditu. Endpointy GET /incidents/:id a PATCH /incidents/:id/status, OpenAPI a dokumentace. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
bc6508e1f3
commit
42b3da8303
@@ -124,6 +124,12 @@ export function listIncidents(tenantIds: string[]): Incident[] {
|
||||
});
|
||||
}
|
||||
|
||||
/** Incident podle ID. Cizi firmy se chova jako neexistujici, stejne jako u ticketu. */
|
||||
export function findIncident(id: string, tenantIds: string[]): Incident | undefined {
|
||||
const incident = incidents.find((item) => item.id === id);
|
||||
return incident && visibleTo(incident, tenantIds) ? incident : undefined;
|
||||
}
|
||||
|
||||
/** Uz je stejny problem otevreny? Aby deset stejnych chyb nedelalo deset incidentu. */
|
||||
export function findOpenIncident(source: string, tenantIds: string[]): Incident | undefined {
|
||||
return incidents.find(
|
||||
|
||||
@@ -68,6 +68,12 @@ export const permissionCatalog: PermissionDefinition[] = [
|
||||
},
|
||||
{ key: 'action.manage', label: 'Spravovat definice akcí', group: 'Nastavení firmy' },
|
||||
{ key: 'automation.edit', label: 'Upravovat automatizace', group: 'Nastavení firmy' },
|
||||
{
|
||||
key: 'incident.manage',
|
||||
label: 'Měnit stav incidentu',
|
||||
group: 'Nastavení firmy',
|
||||
hint: 'Posouvat incident firmy do dalšího stavu až po vyřešení. Platformní incidenty mění jen správce platformy.',
|
||||
},
|
||||
{ key: 'connector.manage', label: 'Spravovat konektory', group: 'Nastavení firmy' },
|
||||
{ key: 'widget.manage', label: 'Spravovat vlastní widgety', group: 'Nastavení firmy' },
|
||||
{ key: 'group.manage', label: 'Spravovat skupiny řešitelů', group: 'Nastavení firmy' },
|
||||
|
||||
@@ -2274,6 +2274,48 @@ export function buildOpenApiDocument() {
|
||||
},
|
||||
},
|
||||
},
|
||||
'/api/dashboard/incidents/{id}': {
|
||||
get: {
|
||||
tags: ['Dashboard'],
|
||||
summary: 'Detail incidentu',
|
||||
description:
|
||||
'Incident firmy nebo platformni. `detail` (diagnostika) dostane jen spravce platformy, ' +
|
||||
'ostatni maji null. Cizi incident je 404.',
|
||||
security: [{ bearerAuth: [] }],
|
||||
parameters: [idParam, tenantParam],
|
||||
responses: {
|
||||
'200': jsonResponse('Incident', { $ref: '#/components/schemas/Incident' }),
|
||||
'404': { description: 'Incident neexistuje nebo patri jine firme' },
|
||||
},
|
||||
},
|
||||
},
|
||||
'/api/dashboard/incidents/{id}/status': {
|
||||
patch: {
|
||||
tags: ['Dashboard'],
|
||||
summary: 'Posunout incident do dalsiho stavu',
|
||||
description:
|
||||
'Pravo incident.manage za firmu incidentu; platformni incident (bez firmy) meni jen ' +
|
||||
'spravce platformy. Stav resolved nastavi resolvedAt.',
|
||||
security: [{ bearerAuth: [] }],
|
||||
parameters: [idParam, tenantParam],
|
||||
requestBody: jsonBody({
|
||||
type: 'object',
|
||||
required: ['status'],
|
||||
properties: {
|
||||
status: {
|
||||
type: 'string',
|
||||
enum: ['investigating', 'identified', 'monitoring', 'resolved'],
|
||||
},
|
||||
},
|
||||
}),
|
||||
responses: {
|
||||
'200': jsonResponse('Incident', { $ref: '#/components/schemas/Incident' }),
|
||||
'400': { description: 'Neznamy stav' },
|
||||
'403': { description: 'Chybi pravo incident.manage' },
|
||||
'404': { description: 'Incident neexistuje nebo patri jine firme' },
|
||||
},
|
||||
},
|
||||
},
|
||||
'/api/dashboard/stream': {
|
||||
get: {
|
||||
tags: ['Dashboard'],
|
||||
|
||||
+63
-1
@@ -39,7 +39,13 @@ import {
|
||||
} from '../data/dashboardLayouts.js';
|
||||
import { collectScopes } from '../data/flowScope.js';
|
||||
import { widgetCatalog } from '../data/widgets.js';
|
||||
import { createIncident, listIncidents } from '../data/incidentStore.js';
|
||||
import {
|
||||
createIncident,
|
||||
findIncident,
|
||||
listIncidents,
|
||||
updateIncidentStatus,
|
||||
type Incident,
|
||||
} from '../data/incidentStore.js';
|
||||
import { getSummary } from '../data/mock.js';
|
||||
import { isMember, listGroups, listPeople } from '../data/people.js';
|
||||
import { hasPermission } from '../data/permissions.js';
|
||||
@@ -145,6 +151,62 @@ dashboardRouter.get('/incidents', (req, res) => {
|
||||
});
|
||||
});
|
||||
|
||||
/** Stejne pravidlo jako u seznamu: diagnostiku vidi jen spravce platformy. */
|
||||
function publicIncident(req: Request, incident: Incident): Incident {
|
||||
return { ...incident, detail: req.user!.platformAdmin ? incident.detail : null };
|
||||
}
|
||||
|
||||
dashboardRouter.get('/incidents/:id', (req, res) => {
|
||||
const scope = scopeOrDeny(req, res);
|
||||
if (!scope) return;
|
||||
|
||||
const incident = findIncident(req.params.id, scope.tenantIds);
|
||||
if (!incident) return res.status(404).json({ error: 'not_found', message: 'Incident neexistuje.' });
|
||||
return res.json(publicIncident(req, incident));
|
||||
});
|
||||
|
||||
const incidentStatusSchema = z.object({
|
||||
status: z.enum(['investigating', 'identified', 'monitoring', 'resolved']),
|
||||
});
|
||||
|
||||
/**
|
||||
* Posun incidentu do dalsiho stavu.
|
||||
*
|
||||
* Incident firmy meni, kdo ma v te firme `incident.manage`. Platformni incident
|
||||
* (bez firmy) je nas a meni ho jen spravce platformy - klient by jinak mohl
|
||||
* "vyresit" vypadek, ktery se tyka vsech.
|
||||
*/
|
||||
dashboardRouter.patch('/incidents/:id/status', (req, res) => {
|
||||
const scope = scopeOrDeny(req, res);
|
||||
if (!scope) return;
|
||||
|
||||
const incident = findIncident(req.params.id, scope.tenantIds);
|
||||
if (!incident) return res.status(404).json({ error: 'not_found', message: 'Incident neexistuje.' });
|
||||
|
||||
const allowed =
|
||||
req.user!.platformAdmin ||
|
||||
(incident.tenantId !== null && hasPermission(req.user!, 'incident.manage', incident.tenantId));
|
||||
if (!allowed) {
|
||||
return res.status(403).json({ error: 'forbidden', message: 'Stav incidentu nemůžete měnit.' });
|
||||
}
|
||||
|
||||
const parsed = incidentStatusSchema.safeParse(req.body);
|
||||
if (!parsed.success) return validationError(res, parsed.error);
|
||||
|
||||
const updated = updateIncidentStatus(incident.id, parsed.data.status);
|
||||
if (!updated) return res.status(404).json({ error: 'not_found', message: 'Incident neexistuje.' });
|
||||
|
||||
recordAudit({
|
||||
userId: req.user!.id,
|
||||
userEmail: req.user!.email,
|
||||
tenantId: incident.tenantId,
|
||||
action: 'incident.status',
|
||||
target: incident.id,
|
||||
detail: { status: parsed.data.status },
|
||||
});
|
||||
return res.json(publicIncident(req, updated));
|
||||
});
|
||||
|
||||
/**
|
||||
* Hlaseni padu portalu.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user