Initial incident record
This commit is contained in:
parent
086bb90064
commit
b16b3810cc
8 changed files with 147 additions and 13 deletions
|
@ -65,6 +65,14 @@ export const routes: Routes = [
|
||||||
),
|
),
|
||||||
data: { title: 'Incidents' },
|
data: { title: 'Incidents' },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'incidents/:id',
|
||||||
|
loadComponent: () =>
|
||||||
|
import('./incidents/incident/incident.component').then(
|
||||||
|
(m) => m.IncidentComponent,
|
||||||
|
),
|
||||||
|
data: { title: 'View Incident' },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'alerts',
|
path: 'alerts',
|
||||||
loadComponent: () =>
|
loadComponent: () =>
|
||||||
|
|
|
@ -1 +1,15 @@
|
||||||
<p>incident works!</p>
|
@let inc = inc$ | async;
|
||||||
|
<mat-card class="incident" appearance="outlined">
|
||||||
|
<h1>{{ inc?.name }}</h1>
|
||||||
|
<div class="inc-heading">
|
||||||
|
<div class="field field-start field-label">Start</div>
|
||||||
|
<div class="field field-data field-start">
|
||||||
|
{{ inc?.startTime | fmtDate }}
|
||||||
|
</div>
|
||||||
|
<div class="field field-end field-label">End</div>
|
||||||
|
<div class="field field-data field-end">{{ inc?.endTime | fmtDate }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="inc-description">
|
||||||
|
{{ inc?.description }}
|
||||||
|
</div>
|
||||||
|
</mat-card>
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
.incident {
|
||||||
|
margin: 50px 50px 50px 50px;
|
||||||
|
padding: 50px 50px 50px 50px;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
width: 50%;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inc-heading,
|
||||||
|
.inc-description {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
flex: 1 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inc-heading,
|
||||||
|
.inc-description {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field {
|
||||||
|
flex: 1 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-label {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
.field-label::after {
|
||||||
|
content: ":";
|
||||||
|
}
|
|
@ -1,9 +1,73 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component, computed, inject, ViewChild } from '@angular/core';
|
||||||
|
import { toSignal } from '@angular/core/rxjs-interop';
|
||||||
|
import { debounceTime } from 'rxjs/operators';
|
||||||
|
import {
|
||||||
|
Talkgroup,
|
||||||
|
TalkgroupUpdate,
|
||||||
|
IconMap,
|
||||||
|
iconMapping,
|
||||||
|
} from '../../talkgroup';
|
||||||
|
import { COMMA, ENTER } from '@angular/cdk/keycodes';
|
||||||
|
import { TalkgroupService } from '../../talkgroups/talkgroups.service';
|
||||||
|
import {
|
||||||
|
MatAutocomplete,
|
||||||
|
MatAutocompleteModule,
|
||||||
|
MatAutocompleteSelectedEvent,
|
||||||
|
MatAutocompleteActivatedEvent,
|
||||||
|
} from '@angular/material/autocomplete';
|
||||||
|
import { CommonModule, DatePipe } from '@angular/common';
|
||||||
|
import { BehaviorSubject, catchError, of, Subscription } from 'rxjs';
|
||||||
|
import { shareReplay } from 'rxjs/operators';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import {
|
||||||
|
ReactiveFormsModule,
|
||||||
|
FormGroup,
|
||||||
|
FormControl,
|
||||||
|
FormsModule,
|
||||||
|
} from '@angular/forms';
|
||||||
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { IncidentsService } from '../incidents.service';
|
||||||
|
import { IncidentRecord } from '../../incidents';
|
||||||
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
import { FmtDatePipe } from '../incidents.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-incident',
|
selector: 'app-incident',
|
||||||
imports: [],
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
FormsModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatCheckboxModule,
|
||||||
|
MatIconModule,
|
||||||
|
MatCardModule,
|
||||||
|
FmtDatePipe,
|
||||||
|
],
|
||||||
templateUrl: './incident.component.html',
|
templateUrl: './incident.component.html',
|
||||||
styleUrl: './incident.component.scss',
|
styleUrl: './incident.component.scss',
|
||||||
})
|
})
|
||||||
export class IncidentComponent {}
|
export class IncidentComponent {
|
||||||
|
inc$!: Observable<IncidentRecord>;
|
||||||
|
subscriptions: Subscription = new Subscription();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private incSvc: IncidentsService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
saveIncName(ev: Event) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const incID = this.route.snapshot.paramMap.get('id')!;
|
||||||
|
this.inc$ = this.incSvc.getIncident(incID);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.subscriptions.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -34,12 +34,17 @@ import { ToolbarContextService } from '../navigation/toolbar-context.service';
|
||||||
standalone: true,
|
standalone: true,
|
||||||
pure: true,
|
pure: true,
|
||||||
})
|
})
|
||||||
export class DatePipe implements PipeTransform {
|
export class FmtDatePipe implements PipeTransform {
|
||||||
transform(ts: string, args?: any): string {
|
transform(ts: string | Date | null | undefined, args?: any): string {
|
||||||
if (!ts) {
|
if (!ts) {
|
||||||
return '\u2014';
|
return '\u2014';
|
||||||
}
|
}
|
||||||
const timestamp = new Date(ts);
|
let timestamp: Date;
|
||||||
|
if (ts instanceof Date) {
|
||||||
|
timestamp = ts;
|
||||||
|
} else {
|
||||||
|
timestamp = new Date(ts);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
timestamp.getMonth() +
|
timestamp.getMonth() +
|
||||||
1 +
|
1 +
|
||||||
|
@ -61,7 +66,7 @@ const reqPageSize = 200;
|
||||||
selector: 'app-incidents',
|
selector: 'app-incidents',
|
||||||
imports: [
|
imports: [
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
DatePipe,
|
FmtDatePipe,
|
||||||
MatPaginatorModule,
|
MatPaginatorModule,
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
AsyncPipe,
|
AsyncPipe,
|
||||||
|
|
|
@ -47,4 +47,8 @@ export class IncidentsService {
|
||||||
updateIncident(id: string, inp: IncidentRecord): Observable<IncidentRecord> {
|
updateIncident(id: string, inp: IncidentRecord): Observable<IncidentRecord> {
|
||||||
return this.http.patch<IncidentRecord>('/api/incident/' + id, inp);
|
return this.http.patch<IncidentRecord>('/api/incident/' + id, inp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getIncident(id: string): Observable<IncidentRecord> {
|
||||||
|
return this.http.get<IncidentRecord>('/api/incident/' + id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
MatAutocompleteActivatedEvent,
|
MatAutocompleteActivatedEvent,
|
||||||
} from '@angular/material/autocomplete';
|
} from '@angular/material/autocomplete';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { BehaviorSubject, catchError, of, Subscription } from 'rxjs';
|
import { catchError, of, Subscription } from 'rxjs';
|
||||||
import { shareReplay } from 'rxjs/operators';
|
import { shareReplay } from 'rxjs/operators';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
|
|
|
@ -26,6 +26,7 @@ export interface TalkgroupsPaginated {
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class TalkgroupService {
|
export class TalkgroupService {
|
||||||
|
private readonly _getTalkgroup = new Map<string, ReplaySubject<Talkgroup>>();
|
||||||
private tgs$: Observable<Talkgroup[]>;
|
private tgs$: Observable<Talkgroup[]>;
|
||||||
private tags$!: Observable<string[]>;
|
private tags$!: Observable<string[]>;
|
||||||
private fetchAll = new BehaviorSubject<'fetch'>('fetch');
|
private fetchAll = new BehaviorSubject<'fetch'>('fetch');
|
||||||
|
@ -45,13 +46,19 @@ export class TalkgroupService {
|
||||||
}
|
}
|
||||||
|
|
||||||
getTalkgroups(): Observable<Talkgroup[]> {
|
getTalkgroups(): Observable<Talkgroup[]> {
|
||||||
return this.http.get<Talkgroup[]>('/api/talkgroup/');
|
return this.http.get<Talkgroup[]>('/api/talkgroup/').pipe(shareReplay());
|
||||||
}
|
}
|
||||||
|
|
||||||
getTalkgroup(sys: number, tg: number): Observable<Talkgroup> {
|
getTalkgroup(sys: number, tg: number): Observable<Talkgroup> {
|
||||||
return this.tgs$.pipe(
|
const key = this.tgKey(sys, tg);
|
||||||
switchMap((tgs) => tgs.filter(t => t.system_id === sys && t.tgid === tg))
|
if (!this._getTalkgroup.get(key)) {
|
||||||
);
|
return this.tgs$.pipe(
|
||||||
|
switchMap((talkg) =>
|
||||||
|
talkg.filter((tgv) => tgv.tgid == tg && tgv.system_id == sys),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return this._getTalkgroup.get(key)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
putTalkgroup(tu: TalkgroupUpdate): Observable<Talkgroup> {
|
putTalkgroup(tu: TalkgroupUpdate): Observable<Talkgroup> {
|
||||||
|
|
Loading…
Reference in a new issue