Files
catalog_admin/ts_web/views/upladmin-incidents-view/upladmin-incidents-view.ts

293 lines
8.2 KiB
TypeScript

import {
DeesElement,
customElement,
html,
state,
css,
cssManager,
} from '@design.estate/dees-element';
import type { DeesAppuiBase } from '@design.estate/dees-catalog';
// View lifecycle interfaces (defined locally as they're not exported from dees-catalog)
interface IViewActivationContext {
appui: DeesAppuiBase;
viewId: string;
params?: Record<string, string>;
}
interface IViewLifecycle {
onActivate?: (context: IViewActivationContext) => void | Promise<void>;
onDeactivate?: () => void | Promise<void>;
}
import { adminState } from '../../services/admin-state.js';
import type { IIncidentDetails, TIncidentSeverity, TIncidentStatus } from '../../interfaces/index.js';
import '../../elements/upladmin-incident-list/upladmin-incident-list.js';
import '../../elements/upladmin-incident-form/upladmin-incident-form.js';
import '../../elements/upladmin-incident-update/upladmin-incident-update.js';
type TViewMode = 'list' | 'form' | 'update';
type TTimeFilter = 'current' | 'past' | 'all';
@customElement('upladmin-incidents-view')
export class UpladminIncidentsView extends DeesElement implements IViewLifecycle {
@state()
accessor currentMode: TViewMode = 'list';
@state()
accessor selectedIncidentId: string | null = null;
@state()
accessor timeFilter: TTimeFilter = 'current';
@state()
accessor severityFilter: TIncidentSeverity | 'all' = 'all';
@state()
accessor loading: boolean = false;
private appuiRef: DeesAppuiBase | null = null;
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
height: 100%;
}
`,
];
async onActivate(context: IViewActivationContext): Promise<void> {
this.appuiRef = context.appui;
// Check route params and view ID
if (context.params?.id) {
if (context.viewId === 'incident-update') {
this.currentMode = 'update';
this.selectedIncidentId = context.params.id;
} else {
this.currentMode = 'form';
this.selectedIncidentId = context.params.id === 'create' ? null : context.params.id;
}
} else {
this.currentMode = 'list';
this.selectedIncidentId = null;
}
// Set secondary menu
this.updateSecondaryMenu();
// No content tabs - incident-list has internal tabs
context.appui.setContentTabs([]);
}
private updateSecondaryMenu(): void {
if (!this.appuiRef) return;
const activeCount = adminState.getActiveIncidents().length;
const pastCount = adminState.incidents.filter((i) => i.status === 'resolved' || i.status === 'postmortem').length;
this.appuiRef.setSecondaryMenu({
heading: 'Incidents',
groups: [
{
name: 'Filter',
iconName: 'lucide:filter',
items: [
{
key: 'current',
iconName: 'lucide:alertCircle',
action: () => this.setTimeFilter('current'),
badge: activeCount,
badgeVariant: activeCount > 0 ? 'error' : 'default',
},
{
key: 'past',
iconName: 'lucide:history',
action: () => this.setTimeFilter('past'),
badge: pastCount,
},
{
key: 'all',
iconName: 'lucide:list',
action: () => this.setTimeFilter('all'),
badge: adminState.incidents.length,
},
],
},
{
name: 'Severity',
iconName: 'lucide:alertTriangle',
collapsed: true,
items: [
{
key: 'critical',
iconName: 'lucide:xCircle',
action: () => this.setSeverityFilter('critical'),
},
{
key: 'major',
iconName: 'lucide:alertOctagon',
action: () => this.setSeverityFilter('major'),
},
{
key: 'minor',
iconName: 'lucide:alertTriangle',
action: () => this.setSeverityFilter('minor'),
},
{
key: 'maintenance',
iconName: 'lucide:wrench',
action: () => this.setSeverityFilter('maintenance'),
},
],
},
{
name: 'Actions',
iconName: 'lucide:zap',
items: [
{
key: 'create',
iconName: 'lucide:plus',
action: () => this.showForm(null),
},
],
},
],
});
// Select current filter
this.appuiRef.setSecondaryMenuSelection(this.timeFilter);
}
private setTimeFilter(filter: TTimeFilter): void {
this.timeFilter = filter;
this.severityFilter = 'all';
this.appuiRef?.setSecondaryMenuSelection(filter);
}
private setSeverityFilter(severity: TIncidentSeverity): void {
this.severityFilter = severity;
this.appuiRef?.setSecondaryMenuSelection(severity);
}
private showForm(incidentId: string | null): void {
this.currentMode = 'form';
this.selectedIncidentId = incidentId;
}
private showUpdate(incidentId: string): void {
this.currentMode = 'update';
this.selectedIncidentId = incidentId;
}
private showList(): void {
this.currentMode = 'list';
this.selectedIncidentId = null;
}
private get filteredIncidents(): IIncidentDetails[] {
let incidents = adminState.incidents;
// Apply time filter
if (this.timeFilter === 'current') {
incidents = incidents.filter(
(i) => i.status !== 'resolved' && i.status !== 'postmortem'
);
} else if (this.timeFilter === 'past') {
incidents = incidents.filter(
(i) => i.status === 'resolved' || i.status === 'postmortem'
);
}
// Apply severity filter
if (this.severityFilter !== 'all') {
incidents = incidents.filter((i) => i.severity === this.severityFilter);
}
return incidents;
}
private handleIncidentSave = (e: CustomEvent): void => {
console.log('Incident saved:', e.detail);
this.showList();
};
private handleUpdateSave = (e: CustomEvent): void => {
console.log('Update saved:', e.detail);
this.showList();
};
private handleCancel = (): void => {
this.showList();
};
private handleIncidentEdit = (e: CustomEvent): void => {
const incident = e.detail?.incident as IIncidentDetails;
if (incident) {
this.showForm(incident.id);
}
};
private handleIncidentAddUpdate = (e: CustomEvent): void => {
const incident = e.detail?.incident as IIncidentDetails;
if (incident) {
this.showUpdate(incident.id);
}
};
render() {
if (this.currentMode === 'update') {
const incident = this.selectedIncidentId
? adminState.incidents.find((i) => i.id === this.selectedIncidentId)
: null;
return html`
<upladmin-incident-update
.incident=${incident}
.loading=${this.loading}
@updateSave=${this.handleUpdateSave}
@cancel=${this.handleCancel}
></upladmin-incident-update>
`;
}
if (this.currentMode === 'form') {
const incident = this.selectedIncidentId
? adminState.incidents.find((i) => i.id === this.selectedIncidentId)
: null;
return html`
<upladmin-incident-form
.incident=${incident
? {
id: incident.id,
title: incident.title,
severity: incident.severity,
status: incident.status,
affectedServices: incident.affectedServices,
impact: incident.impact,
rootCause: incident.rootCause,
resolution: incident.resolution,
}
: null}
.availableServices=${adminState.monitors}
.loading=${this.loading}
@incidentSave=${this.handleIncidentSave}
@cancel=${this.handleCancel}
></upladmin-incident-form>
`;
}
return html`
<upladmin-incident-list
.incidents=${this.filteredIncidents}
.loading=${this.loading}
@incidentAdd=${() => this.showForm(null)}
@incidentEdit=${this.handleIncidentEdit}
@incidentAddUpdate=${this.handleIncidentAddUpdate}
></upladmin-incident-list>
`;
}
}