Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more maps #2038

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/app/components/home/home.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,25 @@ <h2>View Some {{ viewMoreLink.label | titlecase }}s</h2>
</ng-container>
</div>
</section>

<!-- Live an interactive map -->
hudson-newey marked this conversation as resolved.
Show resolved Hide resolved
<section
id="interactiveMap"
class="pb-5 pt-5 border-top border-top text-bg-light"
>
<div class="container">
<h2>View the Live Site Map</h2>

<ng-container *ngIf="allSites$ | withLoading | async as sites">
<baw-loading *ngIf="sites.loading" [size]="lg"></baw-loading>

<div style="width: 100%; height: 24em;">
<baw-site-map
*ngIf="!sites.loading && sites.value.size > 0"
[projects]="projects(sites.value).toArray()"
[regions]="regions(sites.value).toArray()"
></baw-site-map>
</div>
</ng-container>
</div>
</section>
32 changes: 28 additions & 4 deletions src/app/components/home/home.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ import { generateProject } from "@test/fakes/Project";
import { generateRegion } from "@test/fakes/Region";
import { interceptFilterApiRequest } from "@test/helpers/general";
import { MockComponent } from "ng-mocks";
import { BehaviorSubject } from "rxjs";
import { BehaviorSubject, of } from "rxjs";
import { MapComponent } from "@shared/map/map.component";
import { List } from "immutable";
import { HomeComponent } from "./home.component";

describe("HomeComponent", () => {
Expand All @@ -37,9 +39,14 @@ describe("HomeComponent", () => {
let cmsService: SpyObject<CmsService>;
let config: ConfigService;
let spec: Spectator<HomeComponent>;

const createComponent = createComponentFactory({
component: HomeComponent,
declarations: [CardsComponent, MockComponent(CardComponent)],
declarations: [
CardsComponent,
MockComponent(MapComponent),
MockComponent(CardComponent),
],
imports: [
MockBawApiModule,
MockConfigModule,
Expand Down Expand Up @@ -112,12 +119,20 @@ describe("HomeComponent", () => {
cmsService.get.and.callFake(() => new BehaviorSubject("cms content"));
}

beforeEach(() => {
function setup() {
spec = createComponent({ detectChanges: false });
projectApi = spec.inject(ProjectsService);
regionApi = spec.inject(ShallowRegionsService);
config = spec.inject(ConfigService);
});

const mockProjectList = List<Project | Region>([]);
spyOn(spec.component, "fetchAllSiteLocations").and.callFake(() => of(mockProjectList));
spec.component.models$ = of(mockProjectList);
spec.component.allSites$ = of(mockProjectList);

}

beforeEach(() => setup());

// TODO Re-enable once cms is setup
/* assertCms<HomeComponent>(async () => {
Expand Down Expand Up @@ -215,5 +230,14 @@ describe("HomeComponent", () => {
expect(button).toHaveStrongRoute(test.link);
});
});

describe("site map", () => {
it("should create", () => {
expect(spec.query("#interactiveMap")).toExist();
});

it("should handle taking both projects and regions", async () => {
});
Comment on lines +239 to +240
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty test?

});
});
});
44 changes: 44 additions & 0 deletions src/app/components/home/home.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class HomeComponent extends PageComponent implements OnInit {
};
public viewMoreLink: { label: string; link: StrongRoute };
public models$: Observable<List<Project | Region>>;
public allSites$: Observable<List<Project | Region>>;
public sourceRepo: string;

public constructor(
Expand Down Expand Up @@ -81,6 +82,9 @@ class HomeComponent extends PageComponent implements OnInit {
map((models) => List<Project | Region>(models)),
takeUntil(this.unsubscribe)
);

// to render the "live site map" at the bottom of the home page, the home component has to have knowledge of all the site locations
this.fetchAllSiteLocations();
}

public calculateSvgTextYPos(index: number) {
Expand Down Expand Up @@ -117,6 +121,46 @@ class HomeComponent extends PageComponent implements OnInit {

return `${xPos} ${yPos} ${width} ${height}`;
}

/**
* The home component must have knowledge on all site locations for the overview map
*/
public fetchAllSiteLocations(): Observable<List<Project | Region>> {
const settings = this.config.settings;

let pageNumber = 1;
// Get the first page of points. This will also provide information on the max page length to search through
let maxPageNumber = 1;

while (pageNumber <= maxPageNumber) {
const filter = { paging: { page: pageNumber } };

const sites: Observable<Region[] | Project[]> = settings.hideProjects
? this.regionApi.filter(filter)
: this.projectApi.filter(filter);
Comment on lines +138 to +140
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why don't we just query for all sites?


this.allSites$ = sites.pipe(
map((models) => List<Project | Region>(models)),
takeUntil(this.unsubscribe)
);

// find the max page number from the metadata
this.allSites$
.pipe(takeUntil(this.unsubscribe))
.subscribe((site) => maxPageNumber = site.toArray()?.shift()?.getMetadata()?.paging?.maxPage);
pageNumber++;
}

return this.allSites$;
}

public projects(sites: List<Project | Region>): List<Project> {
return sites?.filter((location) => location.kind === "Project") as List<Project>;
}

public regions(sites: List<Project | Region>): List<Region> {
return sites?.filter((location) => location.kind === "Region") as List<Region>;
}
Comment on lines +128 to +163
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some notes:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I think we can strip all this logic and my suggestions out and move it into the component

}

HomeComponent.linkToRoute({
Expand Down
7 changes: 4 additions & 3 deletions src/app/components/home/home.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ import { NgModule } from "@angular/core";
import { RouterModule } from "@angular/router";
import { getRouteConfigForPage } from "@helpers/page/pageRouting";
import { SharedModule } from "@shared/shared.module";
import { ProjectsModule } from "../projects/projects.module";
import { HomeComponent } from "./home.component";
import { homeRoute } from "./home.menus";

const components = [HomeComponent];
const routes = homeRoute.compileRoutes(getRouteConfigForPage);

@NgModule({
declarations: components,
imports: [SharedModule, RouterModule.forChild(routes)],
exports: [RouterModule, ...components],
declarations: components,
exports: [RouterModule, ...components],
imports: [SharedModule, RouterModule.forChild(routes), ProjectsModule]
})
export class HomeModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe("SiteMapComponent", () => {
function setup(project: Project, region?: Region) {
spec = createComponent({
detectChanges: false,
props: { project, region },
props: { projects: [project], regions: [region] },
});
api = spec.inject(SitesService);
}
Expand Down Expand Up @@ -90,10 +90,9 @@ describe("SiteMapComponent", () => {
function interceptApiRequest(
responses: Errorable<Site[]>[],
expectations?: ((filter: Filters<ISite>, project: Project) => void)[],
hasRegion?: boolean
): Promise<void>[] {
return interceptRepeatApiRequests<ISite, Site[]>(
hasRegion ? api.filterByRegion : api.filter,
api.filterByRegion,
responses,
expectations
);
Expand Down Expand Up @@ -216,8 +215,7 @@ describe("SiteMapComponent", () => {
const promise = Promise.all(
interceptApiRequest(
sites,
[assertFilter(1, defaultProject, defaultRegion)],
true
[assertFilter(1, defaultProject, defaultRegion)]
)
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,28 @@ import { switchMap, takeUntil } from "rxjs/operators";
export class SiteMapComponent extends withUnsubscribe() implements OnInit {
// TODO Implement system to change colour of selected sites
@Input() public selected: List<Site>;
@Input() public project: Project;
@Input() public region: Region;
@Input() public projects: Project[];
@Input() public regions: Region[];
public markers: List<MapMarkerOptions> = List([]);

public constructor(private sitesApi: SitesService) {
super();
}

public ngOnInit(): void {
this.regions?.forEach((region) => this.addSingleLocationMarkers(this.projects.pop(), region));
this.projects?.forEach((project) => this.addSingleLocationMarkers(project));
}

/**
* Fetches the markers for a project or region and adds the markers to the `markers` list for a single location
*/
private addSingleLocationMarkers(project?: Project, region?: Region): void {
const filters: Filters<ISite> = { paging: { page: 1 } };

this.getFilter(filters, this.project, this.region)
this.getFilter(filters, project, region)
.pipe(
switchMap((models) => this.getMarkers(models)),
switchMap((models) => this.getMarkers(models, project, region)),
takeUntil(this.unsubscribe)
)
.subscribe({
Expand All @@ -46,24 +54,26 @@ export class SiteMapComponent extends withUnsubscribe() implements OnInit {
filters: Filters<ISite>,
project: Project,
region?: Region
) {
return this.region
? this.sitesApi.filterByRegion(filters, project, region)
: this.sitesApi.filter(filters, project);
): Observable<Site[]> {
// since the region parameter is optional, if a region is not specified, it will default to undefined
// and will have the same result as `siteApi.filter()`
return this.sitesApi.filterByRegion(filters, project, region)
}

/**
* Retrieve map markers from api
*/
private getMarkers(sites: Site[]) {
private getMarkers(
sites: Site[],
project: Project,
region: Region
): Observable<Site[]> {
const numPages = sites?.[0]?.getMetadata()?.paging?.maxPage || 1;
const observables: Observable<Site[]>[] = [];

// Can skip first page because initial filter produces the results
for (let page = 2; page <= numPages; page++) {
observables.push(
this.getFilter({ paging: { page } }, this.project, this.region)
);
observables.push(this.getFilter({ paging: { page } }, project, region));
}

this.pushMarkers(sites);
Expand All @@ -73,7 +83,7 @@ export class SiteMapComponent extends withUnsubscribe() implements OnInit {
/**
* Push new sites to markers list
*/
private pushMarkers(sites: Site[]) {
private pushMarkers(sites: Site[]): void {
this.markers = this.markers.concat(
sanitizeMapMarkers(sites.map((site) => site.getMapMarker()))
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ describe("ProjectDetailsComponent", () => {
);
spectator.detectChanges();
await awaitChanges(promise);
expect(getMap().project).toEqual(defaultProject);
expect(getMap().projects).toEqual([defaultProject]);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const projectKey = "project";
<ul id="model-grid" class="list-group">
<!-- Google Maps -->
<div *ngIf="hasSites || hasRegions || loading" class="item map">
<baw-site-map [project]="project"></baw-site-map>
<baw-site-map [projects]="[project]"></baw-site-map>
</div>

<!-- Regions -->
Expand Down
29 changes: 29 additions & 0 deletions src/app/components/projects/pages/list/list.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { nStepObservable } from "@test/helpers/general";
import { assertErrorHandler } from "@test/helpers/html";
import { MockComponent } from "ng-mocks";
import { Subject } from "rxjs";
import { SiteMapComponent } from "@components/projects/components/site-map/site-map.component";
import { modelData } from "@test/helpers/faker";
import { ListComponent } from "./list.component";

const mockCardsComponent = MockComponent(CardsComponent);
Expand All @@ -41,6 +43,7 @@ describe("ProjectsListComponent", () => {
},
],
],
declarations: [MockComponent(SiteMapComponent)],
imports: [SharedModule, RouterTestingModule, MockBawApiModule],
});

Expand Down Expand Up @@ -195,4 +198,30 @@ describe("ProjectsListComponent", () => {
expect(spec.component.onFilter).toHaveBeenCalled();
});
});

describe("site map", () => {
it("should create", async () => {
const projects = generateProjects(modelData.datatype.number({ min: 1 }));
await handleApiRequest(projects);

expect(spec.query(SiteMapComponent)).toExist();
});

it("should display the same projects that are displayed in the filtered list", async () => {
const projects = generateProjects(modelData.datatype.number({ min: 1 }));
await handleApiRequest(projects);

const mapComponent = spec.query(SiteMapComponent);

const shownProjects = spec.component.models.toArray();
const mapProjects = mapComponent.projects;
const mapRegions = mapComponent.regions;

expect(mapProjects).toEqual(shownProjects);

// since there are no regions specified in the project component, there should not be any regions in the map component
// if this assertion fails, there is a problem with the `ngOnInit()` method
expect(mapRegions).toBeUndefined();
});
});
});
6 changes: 6 additions & 0 deletions src/app/components/projects/pages/list/list.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ export const projectsMenuItemActions = [
selector: "baw-projects-list",
template: `
<ng-container *ngIf="!error">
<ng-container *ngIf="!loading && models.size > 0;">
<div id="site-map" style="width: 100%; height: 24em;">
<baw-site-map [projects]="models.toArray()"></baw-site-map>
</div>
</ng-container>

<baw-debounce-input
label="Filter"
placeholder="Filter Projects"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ describe("RegionDetailsComponent", () => {
spectator.detectChanges();
await promise;
spectator.detectChanges();
expect(getMap().project).toEqual(defaultProject);
expect(getMap().projects).toEqual([defaultProject]);
});

it("should provide region to maps component", async () => {
Expand All @@ -168,7 +168,7 @@ describe("RegionDetailsComponent", () => {
spectator.detectChanges();
await promise;
spectator.detectChanges();
expect(getMap().region).toEqual(defaultRegion);
expect(getMap().regions).toEqual([defaultRegion]);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const regionKey = "region";
<ul id="model-grid" class="list-group">
<!-- Google Maps -->
<div *ngIf="hasSites()" class="item map">
<baw-site-map [project]="project" [region]="region"></baw-site-map>
<baw-site-map [projects]="[project]" [regions]="[region]"></baw-site-map>
</div>

<!-- Sites -->
Expand Down
Loading