Works kind of, wip

This commit is contained in:
Daniel Ponte 2025-02-01 08:52:03 -05:00
parent 1c0734f19d
commit 8a223b8897
9 changed files with 135 additions and 136 deletions

View file

@ -27,8 +27,7 @@
} }
} }
], ],
"navigationUrls": "navigationUrls": [
[
"/**", "/**",
"!/**/*.*", "!/**/*.*",
"!/**/****", "!/**/****",

View file

@ -1,10 +1,4 @@
import { import { Component, inject, ViewChild } from '@angular/core';
Component,
inject,
Pipe,
PipeTransform,
ViewChild,
} from '@angular/core';
import { CommonModule, AsyncPipe } from '@angular/common'; import { CommonModule, AsyncPipe } from '@angular/common';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
@ -17,13 +11,20 @@ import { PrefsService } from '../prefs/prefs.service';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { SelectionModel } from '@angular/cdk/collections'; import { SelectionModel } from '@angular/cdk/collections';
import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatCheckboxModule } from '@angular/material/checkbox';
import { BehaviorSubject, Observable, Subscription } from 'rxjs'; import { BehaviorSubject, Subscription } from 'rxjs';
import { map, switchMap } from 'rxjs/operators'; import { switchMap } from 'rxjs/operators';
import { CallsListParams, CallsService } from './calls.service'; import {
CallsListParams,
CallsService,
DatePipe,
DownloadURLPipe,
FixedPointPipe,
TalkgroupPipe,
TimePipe,
} from './calls.service';
import { CallRecord } from '../calls'; import { CallRecord } from '../calls';
import { TalkgroupService } from '../talkgroups/talkgroups.service'; import { TalkgroupService } from '../talkgroups/talkgroups.service';
import { Talkgroup } from '../talkgroup';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { import {
FormControl, FormControl,
@ -49,94 +50,6 @@ import {
import { IncidentRecord } from '../incidents'; import { IncidentRecord } from '../incidents';
import { SelectIncidentDialogComponent } from '../incidents/select-incident-dialog/select-incident-dialog.component'; import { SelectIncidentDialogComponent } from '../incidents/select-incident-dialog/select-incident-dialog.component';
@Pipe({
name: 'grabDate',
standalone: true,
pure: true,
})
export class DatePipe implements PipeTransform {
transform(ts: string, args?: any): string {
const timestamp = new Date(ts);
return timestamp.getMonth() + 1 + '/' + timestamp.getDate();
}
}
@Pipe({
name: 'time',
standalone: true,
pure: true,
})
export class TimePipe implements PipeTransform {
transform(ts: string, args?: any): string {
const timestamp = new Date(ts);
return timestamp.toLocaleTimeString(navigator.language, {
hour: '2-digit',
minute: '2-digit',
hourCycle: 'h23',
});
}
}
@Pipe({
name: 'talkgroup',
standalone: true,
pure: true,
})
export class TalkgroupPipe implements PipeTransform {
constructor(private tgService: TalkgroupService) {}
transform(call: CallRecord, field: string): Observable<string> {
return this.tgService.getTalkgroup(call.system_id, call.tgid).pipe(
map((tg: Talkgroup) => {
switch (field) {
case 'alpha': {
return tg.alpha_tag ?? call.tgid;
break;
}
case 'group': {
return tg.tg_group ?? '\u2014';
break;
}
case 'system': {
return tg.system?.name ?? tg.system_id.toString();
}
default: {
return tg.name ?? '\u2014';
break;
}
}
}),
);
}
}
@Pipe({
name: 'fixedPoint',
standalone: true,
pure: true,
})
export class FixedPointPipe implements PipeTransform {
constructor() {}
transform(quant: number, divisor: number, places: number): string {
const seconds = quant / divisor;
return seconds.toFixed(places);
}
}
@Pipe({
name: 'audioDownloadURL',
standalone: true,
pure: true,
})
export class DownloadURLPipe implements PipeTransform {
constructor(private callsSvc: CallsService) {}
transform(call: CallRecord, args?: any): string {
return this.callsSvc.callAudioDownloadURL(call.id);
}
}
const reqPageSize = 200; const reqPageSize = 200;
@Component({ @Component({
selector: 'app-calls', selector: 'app-calls',
@ -144,8 +57,8 @@ const reqPageSize = 200;
MatIconModule, MatIconModule,
FixedPointPipe, FixedPointPipe,
TalkgroupPipe, TalkgroupPipe,
DatePipe,
TimePipe, TimePipe,
DatePipe,
MatPaginatorModule, MatPaginatorModule,
MatTableModule, MatTableModule,
AsyncPipe, AsyncPipe,

View file

@ -1,8 +1,98 @@
import { Injectable } from '@angular/core'; import { Injectable, Pipe, PipeTransform } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs'; import { map, Observable } from 'rxjs';
import { CallRecord } from '../calls'; import { CallRecord } from '../calls';
import { environment } from '.././../environments/environment'; import { environment } from '.././../environments/environment';
import { TalkgroupService } from '../talkgroups/talkgroups.service';
import { Talkgroup } from '../talkgroup';
@Pipe({
name: 'grabDate',
standalone: true,
pure: true,
})
export class DatePipe implements PipeTransform {
transform(ts: string, args?: any): string {
const timestamp = new Date(ts);
return timestamp.getMonth() + 1 + '/' + timestamp.getDate();
}
}
@Pipe({
name: 'time',
standalone: true,
pure: true,
})
export class TimePipe implements PipeTransform {
transform(ts: string, args?: any): string {
const timestamp = new Date(ts);
return timestamp.toLocaleTimeString(navigator.language, {
hour: '2-digit',
minute: '2-digit',
hourCycle: 'h23',
});
}
}
@Pipe({
name: 'talkgroup',
standalone: true,
pure: true,
})
export class TalkgroupPipe implements PipeTransform {
constructor(private tgService: TalkgroupService) {}
transform(call: CallRecord, field: string): Observable<string> {
return this.tgService.getTalkgroup(call.system_id, call.tgid).pipe(
map((tg: Talkgroup) => {
switch (field) {
case 'alpha': {
return tg.alpha_tag ?? call.tgid;
break;
}
case 'group': {
return tg.tg_group ?? '\u2014';
break;
}
case 'system': {
return tg.system?.name ?? tg.system_id.toString();
}
default: {
return tg.name ?? '\u2014';
break;
}
}
}),
);
}
}
@Pipe({
name: 'fixedPoint',
standalone: true,
pure: true,
})
export class FixedPointPipe implements PipeTransform {
constructor() {}
transform(quant: number, divisor: number, places: number): string {
const seconds = quant / divisor;
return seconds.toFixed(places);
}
}
@Pipe({
name: 'audioDownloadURL',
standalone: true,
pure: true,
})
export class DownloadURLPipe implements PipeTransform {
constructor(private callsSvc: CallsService) {}
transform(call: CallRecord, args?: any): string {
return this.callsSvc.callAudioDownloadURL(call.id);
}
}
export interface CallsListParams { export interface CallsListParams {
start: Date | null; start: Date | null;

View file

@ -35,7 +35,7 @@ import {
TimePipe, TimePipe,
DatePipe, DatePipe,
DownloadURLPipe, DownloadURLPipe,
} from '../../calls/calls.component'; } from '../../calls/calls.service';
import { CallPlayerComponent } from '../../calls/player/call-player/call-player.component'; import { CallPlayerComponent } from '../../calls/player/call-player/call-player.component';
import { FmtDatePipe } from '../incidents.component'; import { FmtDatePipe } from '../incidents.component';
import { MatMenuModule } from '@angular/material/menu'; import { MatMenuModule } from '@angular/material/menu';
@ -183,7 +183,8 @@ export class IncidentComponent {
ngOnInit() { ngOnInit() {
let incOb: Observable<IncidentRecord>; let incOb: Observable<IncidentRecord>;
if (this.route.component === this.constructor) { // loaded by route if (this.route.component === this.constructor) {
// loaded by route
this.incID = this.route.snapshot.paramMap.get('id')!; this.incID = this.route.snapshot.paramMap.get('id')!;
incOb = this.incSvc.getIncident(this.incID); incOb = this.incSvc.getIncident(this.incID);
} else { } else {

View file

@ -1,10 +1,6 @@
@let sh = share | async; @let sh = share | async;
@if (sh == null) { @if (sh == null) {
} @else if (sh.shareType == "incident") {
} @else if (sh.shareType == 'incident') {
<app-incident [incident]="sh"></app-incident> <app-incident [incident]="sh"></app-incident>
} @else if (sh.shareType == 'call') { } @else if (sh.shareType == "call") {
} @else {}
} @else {
}

View file

@ -8,9 +8,8 @@ describe('ShareComponent', () => {
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [ShareComponent] imports: [ShareComponent],
}) }).compileComponents();
.compileComponents();
fixture = TestBed.createComponent(ShareComponent); fixture = TestBed.createComponent(ShareComponent);
component = fixture.componentInstance; component = fixture.componentInstance;

View file

@ -5,15 +5,11 @@ import { Observable, Subscription, switchMap } from 'rxjs';
import { IncidentComponent } from '../incidents/incident/incident.component'; import { IncidentComponent } from '../incidents/incident/incident.component';
import { AsyncPipe } from '@angular/common'; import { AsyncPipe } from '@angular/common';
@Component({ @Component({
selector: 'app-share', selector: 'app-share',
imports: [ imports: [AsyncPipe, IncidentComponent],
AsyncPipe,
IncidentComponent,
],
templateUrl: './share.component.html', templateUrl: './share.component.html',
styleUrl: './share.component.scss' styleUrl: './share.component.scss',
}) })
export class ShareComponent { export class ShareComponent {
shareID!: string; shareID!: string;

View file

@ -9,26 +9,28 @@ export interface Share {
share: ShareType; share: ShareType;
} }
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root',
}) })
export class ShareService { export class ShareService {
constructor(private http: HttpClient) {}
constructor(
private http: HttpClient,
) { }
getShare(id: string): Observable<Share | null> { getShare(id: string): Observable<Share | null> {
return this.http.get<ShareType>(`/share/${id}`, {observe: 'response'}).pipe( return this.http
.get<ShareType>(`/share/${id}`, { observe: 'response' })
.pipe(
map((res) => { map((res) => {
let typ = res.headers.get('X-Share-Type'); let typ = res.headers.get('X-Share-Type');
switch (typ) { switch (typ) {
case 'call': case 'call':
return <Share>{shareType: typ, share: (res.body as ArrayBuffer)}; return <Share>{ shareType: typ, share: res.body as ArrayBuffer };
case 'incident': case 'incident':
return <Share>{shareType: typ, share: (res.body as IncidentRecord)}; return <Share>{
shareType: typ,
share: res.body as IncidentRecord,
};
} }
return null; return null;
}) }),
); );
} }
} }

View file

@ -33,7 +33,10 @@ export class TalkgroupService {
private subscriptions = new Subscription(); private subscriptions = new Subscription();
constructor(private http: HttpClient) { constructor(private http: HttpClient) {
this.tgs$ = this.fetchAll.pipe(switchMap(() => this.getTalkgroups())); this.tgs$ = this.fetchAll.pipe(switchMap(() => this.getTalkgroups()));
this.tags$ = this.fetchAll.pipe(switchMap(() => this.getAllTags()), shareReplay()); this.tags$ = this.fetchAll.pipe(
switchMap(() => this.getAllTags()),
shareReplay(),
);
this.fillTgMap(); this.fillTgMap();
} }