From 2135c52516306b0812c1bdb88efaba9c667bce48 Mon Sep 17 00:00:00 2001 From: William Newman <3382274+newmanw@users.noreply.github.com> Date: Fri, 30 Aug 2024 10:13:41 -0600 Subject: [PATCH] Fix event service subscription for fetch completion --- web-app/src/app/event/event.service.ts | 189 +++++++++---------- web-app/src/app/home/home.module.ts | 2 + web-app/src/app/http/token.interceptor.ts | 11 +- web-app/src/app/ingress/ingress.component.ts | 30 +-- 4 files changed, 107 insertions(+), 125 deletions(-) diff --git a/web-app/src/app/event/event.service.ts b/web-app/src/app/event/event.service.ts index 044c3c6ae..f9fe26005 100644 --- a/web-app/src/app/event/event.service.ts +++ b/web-app/src/app/event/event.service.ts @@ -1,6 +1,5 @@ import { Injectable } from "@angular/core"; -import { Observable, ObservableInput, catchError, finalize, forkJoin, of, tap, zip } from "rxjs"; -import * as moment from 'moment' +import { Observable, Subject, catchError, combineLatest, finalize, forkJoin, map, of, take, tap } from "rxjs"; import { FilterService } from "../filter/filter.service"; import { PollingService } from "./polling.service"; import { ObservationService } from "../observation/observation.service"; @@ -10,6 +9,7 @@ import { FeedService } from "core-lib-src/feed"; import { LocationService } from "../user/location/location.service"; import { LocalStorageService } from "../http/local-storage.service"; import * as _ from 'lodash' +import * as moment from 'moment' @Injectable({ providedIn: 'root' @@ -70,13 +70,13 @@ export class EventService { } if (filter.event || filter.timeInterval) { // requery server - this.fetch(); + this.fetch() } else if (filter.teams) { // filter in memory - this.onTeamsChanged(); + this.onTeamsChanged() } if (filter.actionFilter) { - this.onActionFilterChanged(); + this.onActionFilterChanged() } } @@ -470,10 +470,20 @@ export class EventService { parameters.interval = time; } - return forkJoin({ - locations: this.fetchLocations(event, parameters), - observations: this.fetchObservations(event, parameters) - }) + return combineLatest([ + this.locationService + .getUserLocationsForEvent(event, parameters) + .pipe(map((locations: any) => { + this.parseLocations(event, locations) + })), + this.observationService + .getObservationsForEvent(event, parameters) + .pipe(map((observations: any) => { + this.parseObservations(event, observations) + })) + ]).pipe( + take(1) + ) } fetchLayers(event) { @@ -514,113 +524,102 @@ export class EventService { }); } - fetchObservations(event, parameters): Observable { - const observable = this.observationService.getObservationsForEvent(event, parameters) - observable.subscribe((observations: any) => { - var added = []; - var updated = []; - var removed = []; - - var observationsById = {}; - var filteredObservationsById = this.eventsById[event.id].filteredObservationsById; - observations.forEach((observation: any) => { - // Check if this observation passes the current filter - if (this.filterService.observationInFilter(observation)) { - // Check if we already have this observation, if so update, otherwise add - var localObservation = filteredObservationsById[observation.id]; - if (localObservation) { - if (localObservation.lastModified !== observation.lastModified) { - updated.push(observation); - } else if (observation.attachments) { - var some = _.some(observation.attachments, function (attachment) { - var localAttachment = _.find(localObservation.attachments, function (a) { return a.id === attachment.id; }); - return !localAttachment || localAttachment.lastModified !== attachment.lastModified; - }); - - if (some) updated.push(observation); - } - } else { - added.push(observation); - } + parseObservations(event: any, observations: any): any { + var added = []; + var updated = []; + var removed = []; - // remove from list of observations if it came back from server - // remaining elements in this list will be removed - delete filteredObservationsById[observation.id]; - - observationsById[observation.id] = observation; + var observationsById = {}; + var filteredObservationsById = this.eventsById[event.id].filteredObservationsById; + observations.forEach((observation: any) => { + // Check if this observation passes the current filter + if (this.filterService.observationInFilter(observation)) { + // Check if we already have this observation, if so update, otherwise add + var localObservation = filteredObservationsById[observation.id]; + if (localObservation) { + if (localObservation.lastModified !== observation.lastModified) { + updated.push(observation); + } else if (observation.attachments) { + var some = _.some(observation.attachments, function (attachment) { + var localAttachment = _.find(localObservation.attachments, function (a) { return a.id === attachment.id; }); + return !localAttachment || localAttachment.lastModified !== attachment.lastModified; + }); + + if (some) updated.push(observation); + } + } else { + added.push(observation); } - }); - - // remaining elements were not pulled from the server, hence we should remove them - removed = Object.values(filteredObservationsById); - this.eventsById[event.id].observationsById = _.keyBy(observations, 'id'); - this.eventsById[event.id].filteredObservationsById = observationsById; + // remove from list of observations if it came back from server + // remaining elements in this list will be removed + delete filteredObservationsById[observation.id]; - this.observationsChanged({ added: added, updated: updated, removed: removed }); + observationsById[observation.id] = observation; + } }); - return observable - } + // remaining elements were not pulled from the server, hence we should remove them + removed = Object.values(filteredObservationsById); - fetchLocations(event, parameters): Observable { - const observable = this.locationService.getUserLocationsForEvent(event, parameters) + this.eventsById[event.id].observationsById = _.keyBy(observations, 'id'); + this.eventsById[event.id].filteredObservationsById = observationsById; - observable.subscribe((userLocations: any) => { - const added = []; - const updated = []; + this.observationsChanged({ added: added, updated: updated, removed: removed }); + } - const usersById = {}; - const filteredUsersById = this.eventsById[event.id].filteredUsersById; - userLocations.forEach((userLocation: any) => { - // Track each location feature by users id, - // so update the locations id to match the usersId - const location = userLocation.locations[0]; - location.id = userLocation.id; + parseLocations(event, userLocations: any) { + const added = []; + const updated = []; - userLocation.location = location; - delete userLocation.locations; + const usersById = {}; + const filteredUsersById = this.eventsById[event.id].filteredUsersById; + userLocations.forEach((userLocation: any) => { + // Track each location feature by users id, + // so update the locations id to match the usersId + const location = userLocation.locations[0]; + location.id = userLocation.id; - if (userLocation.user.iconUrl) { - var params = new HttpParams(); - params = params.append('access_token', this.localStorageService.getToken()) - params = params.append('_dc', userLocation.user.lastUpdated) + userLocation.location = location; + delete userLocation.locations; - location.style = { - iconUrl: `${userLocation.user.iconUrl}?${params.toString()}` - } + if (userLocation.user.iconUrl) { + var params = new HttpParams(); + params = params.append('access_token', this.localStorageService.getToken()) + params = params.append('_dc', userLocation.user.lastUpdated) + + location.style = { + iconUrl: `${userLocation.user.iconUrl}?${params.toString()}` } + } - if (this.filterService.isUserInTeamFilter(userLocation.id)) { - // Check if we already have this user, if so update, otherwise add - const localUser = filteredUsersById[userLocation.id]; - if (localUser) { + if (this.filterService.isUserInTeamFilter(userLocation.id)) { + // Check if we already have this user, if so update, otherwise add + const localUser = filteredUsersById[userLocation.id]; + if (localUser) { - if (userLocation.location.properties.timestamp !== localUser.location.properties.timestamp) { - updated.push(userLocation); - } - } else { - added.push(userLocation); + if (userLocation.location.properties.timestamp !== localUser.location.properties.timestamp) { + updated.push(userLocation); } - - // remove from list of observations if it came back from server - // remaining elements in this list will be removed - delete filteredUsersById[userLocation.id]; - - usersById[userLocation.id] = userLocation; + } else { + added.push(userLocation); } - }); - - // remaining elements were not pulled from the server, hence we should remove them - const removed = _.values(filteredUsersById); - this.eventsById[event.id].usersById = _.keyBy(userLocations, 'id'); - this.eventsById[event.id].filteredUsersById = usersById; + // remove from list of observations if it came back from server + // remaining elements in this list will be removed + delete filteredUsersById[userLocation.id]; - this.usersChanged({ added: added, updated: updated, removed: removed }); + usersById[userLocation.id] = userLocation; + } }); - return observable + // remaining elements were not pulled from the server, hence we should remove them + const removed = _.values(filteredUsersById); + + this.eventsById[event.id].usersById = _.keyBy(userLocations, 'id'); + this.eventsById[event.id].filteredUsersById = usersById; + + this.usersChanged({ added: added, updated: updated, removed: removed }); } poll(interval) { diff --git a/web-app/src/app/home/home.module.ts b/web-app/src/app/home/home.module.ts index 610b40fa7..696a71406 100644 --- a/web-app/src/app/home/home.module.ts +++ b/web-app/src/app/home/home.module.ts @@ -138,6 +138,7 @@ import { HomeComponent } from '..//home/home.component'; import { RouterModule, Routes } from '@angular/router'; import { UserResolver } from '../ingress/user.resolver'; import { UserAvatarModule } from '../user/user-avatar/user-avatar.module'; +import { IngressModule } from '../ingress/ingress.module'; const routes: Routes = [{ path: '', @@ -228,6 +229,7 @@ const routes: Routes = [{ ContactDialogComponent ], imports: [ + IngressModule, UserAvatarModule, FeedItemSummaryModule, StaticIconModule, diff --git a/web-app/src/app/http/token.interceptor.ts b/web-app/src/app/http/token.interceptor.ts index ff332d28a..bf0b7792f 100644 --- a/web-app/src/app/http/token.interceptor.ts +++ b/web-app/src/app/http/token.interceptor.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpContextToken, HttpStatusCode, HttpErrorResponse, HttpClient } from '@angular/common/http'; +import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpContextToken, HttpStatusCode, HttpErrorResponse } from '@angular/common/http'; import { catchError, Observable, Subject, switchMap, throwError } from 'rxjs'; import { LocalStorageService } from './local-storage.service'; import { AuthenticationDialogComponent } from '../ingress/authentication/authentication-dialog.component'; @@ -34,7 +34,6 @@ export class TokenInterceptorService implements HttpInterceptor { this.isRefreshingToken = true this.dialog.open(AuthenticationDialogComponent, { width: '600px', - height: '400px', disableClose: true, autoFocus: false }).afterClosed().subscribe(() => { @@ -44,9 +43,7 @@ export class TokenInterceptorService implements HttpInterceptor { } return this.tokenSubject.pipe( - switchMap(() => { - return next.handle(this.tokenRequest(req)) - }) + switchMap(() => next.handle(this.tokenRequest(req))) ) } } @@ -60,7 +57,7 @@ export class TokenInterceptorService implements HttpInterceptor { } tokenRequest(req: HttpRequest): HttpRequest { - const token = this.localStorageService.getToken(); - return req.clone({ headers: req.headers.set('Authorization', `Bearer ${token}`) }); + const token = this.localStorageService.getToken() + return req.clone({ headers: req.headers.set('Authorization', `Bearer ${token}`) }) } } diff --git a/web-app/src/app/ingress/ingress.component.ts b/web-app/src/app/ingress/ingress.component.ts index 154b19e78..43609d9b9 100644 --- a/web-app/src/app/ingress/ingress.component.ts +++ b/web-app/src/app/ingress/ingress.component.ts @@ -1,15 +1,14 @@ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core' +import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core' import { Api, AuthenticationStrategy } from '../api/api.entity' -import { ActivatedRoute } from '@angular/router' import { UserService } from '../user/user.service' import { AuthorizationEvent } from './authorization/authorization.component' import { LocalStorageService } from '../http/local-storage.service' import { DiscalimeCloseEvent, DiscalimerCloseReason } from './disclaimer/disclaimer.component' import { animate, style, transition, trigger } from '@angular/animations' import { SignupEvent } from './authentication/local/signup.component' -import * as _ from 'underscore' import { User } from 'core-lib-src/user' import { InitializedEvent } from './intialize/initialize.component' +import * as _ from 'underscore' enum IngressState { Initialize, @@ -85,7 +84,7 @@ class Initialize extends Ingress { ]) ] }) -export class IngressComponent implements OnInit { +export class IngressComponent implements OnChanges { @Input() api: Api @Input() landing: boolean @Output() complete = new EventEmitter() @@ -98,29 +97,14 @@ export class IngressComponent implements OnInit { localAuthenticationStrategy: any constructor( - private route: ActivatedRoute, private userService: UserService, private localStorageService: LocalStorageService ) { } - ngOnInit(): void { - this.route.data.subscribe(({ api }) => { - this.api = api - - if (this.api.initial) { - this.ingress = new Initialize() - } - - this.localAuthenticationStrategy = this.api?.authenticationStrategies['local']; - if (this.localAuthenticationStrategy) { - this.localAuthenticationStrategy.name = 'local'; - } - - this.thirdPartyStrategies = _.map(_.omit(this.api?.authenticationStrategies, this.localStrategyFilter), function (strategy: AuthenticationStrategy, name: string) { - strategy.name = name; - return strategy; - }); - }) + ngOnChanges(changes: SimpleChanges): void { + if (changes.api.currentValue === true) { + this.ingress = new Initialize() + } } localStrategyFilter(_strategy: AuthenticationStrategy, name: string) {