Skip to content

Commit

Permalink
NRPT-241: Multi-select add records to collection (#505)
Browse files Browse the repository at this point in the history
* NRPT-241: Multi-select add records to collection

* NRPT-241: Code review updates
- Fix cancel button logic when adding records to collection
- Prevent state from being set on records list page when not editing a collection

* NRPT-241: Code review comments
- collectionAddEdit now tracks if it is stale, and acts accordingly on page load

* NRPT-241: Code review updates
- Use 'status' field on collectionAddEdit state to determine validity of state

* NRPT-241: code review updates
- Unify collection state variable names between components for easier reading
- Minor UI tweaks
  • Loading branch information
NickPhura authored Jul 21, 2020
1 parent cae2c28 commit 92113e9
Show file tree
Hide file tree
Showing 17 changed files with 374 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ <h2 class="border-0 mb-0">Collection Information</h2>
<lib-table-template
*ngIf="tableData.totalListItems > 0"
[data]="tableData"
(messageOut)="alert()"
></lib-table-template>
</section>
</main>
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
import { takeUntil } from 'rxjs/operators';
import { CollectionBCMI } from '../../../../../common/src/app/models/bcmi/collection-bcmi';
import { Subject } from 'rxjs';
import { ActivatedRoute, Router } from '@angular/router';
import { MinesCollectionRecordTableRowComponent } from './mines-collection-detail-record-row/mines-collection-detail-record-row.component';
Expand Down Expand Up @@ -75,13 +74,14 @@ export class MinesCollectionDetailComponent implements OnInit, OnDestroy {
return;
}

this.collection = res.collection[0] && res.collection[0].data && new CollectionBCMI(res.collection[0].data);
this.collection = res.collection[0] && res.collection[0].data;

this.isPublished = this.isRecordPublished();

this.populateTextFields();

this.tableData.items = this.collection.records.map(record => ({ rowData: record }));
this.sortRecords();
this.tableData.items = this.collection.collectionRecords.map(record => ({ rowData: record }));

this.tableData.totalListItems = this.tableData.items.length;

Expand All @@ -93,6 +93,25 @@ export class MinesCollectionDetailComponent implements OnInit, OnDestroy {
});
}

/**
* Sort the collection.collectionRecords array.
*
* Why? Mongo $lookup does not preserve order, so the looked-up records projected into the
* this.collection.collectionRecords field must be sorted based on the original this.collection.records array which
* is in proper order.
*
* @memberof MinesAddEditComponent
*/
sortRecords() {
if (!this.collection || !this.collection.collectionRecords || !this.collection.collectionRecords.length) {
return;
}

this.collection.collectionRecords.sort((a, b) => {
return this.collection.records.indexOf(a._id) - this.collection.records.indexOf(b._id);
});
}

/**
* Derive static text strings.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ export class MinesCollectionResolver implements Resolve<Observable<SearchResults

resolve(route: ActivatedRouteSnapshot): Observable<SearchResults[]> {
const collectionId = route.paramMap.get('collectionId');
return this.factoryService.getRecord(collectionId, 'CollectionBCMI');
return this.factoryService.getRecord(collectionId, 'CollectionBCMI', true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,19 @@ <h2 class="border-0 mb-0">Edit Collection</h2>
<!-- TODO Manage records -->
<!-- </section> -->

<section>
<div class="text-right mb-3">
<button
class="btn btn-primary"
(click)="onAddRecordsToCollection()"
title="Select records to add to the collection"
>
<i class="material-icons mr-1 align-middle">add</i>
<span class="align-middle">Select Records To Add</span>
</button>
</div>
</section>

<section class="my-3 py-3">
<div *ngIf="!myForm.get('collectionRecords').value || !myForm.get('collectionRecords').value.length">
No records have been added to this collection.
Expand All @@ -131,7 +144,7 @@ <h2 class="border-0 mb-0">Edit Collection</h2>
<tr>
<th class="col-1"></th>
<th class="col-3">
Collection Name
Record Name
</th>
<th class="col-2">
Agency
Expand All @@ -156,11 +169,11 @@ <h2 class="border-0 mb-0">Edit Collection</h2>
<i class="material-icons" cdkDragHandle>reorder</i>
</button>
</td>
<td data-label="Collection Name" class="col-3">
<td data-label="Record Name" class="col-3">
{{ formGroup.get('record').value.recordName || '-' }}
</td>
<td data-label="Agency" class="col-2">
{{ formGroup.get('record').value.issuingAgency || '-' }}
{{ formGroup.get('record').value.issuingAgency || formGroup.get('record').value.agency || '-' }}
</td>
<td data-label="Source System" class="col-1">
{{ formGroup.get('record').value.sourceSystemRef || '-' }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { RouterTestingModule } from '@angular/router/testing';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { DialogService } from 'ng2-bootstrap-modal';
import { NgxPaginationModule } from 'ngx-pagination';
import { GlobalModule, LoadingScreenService, Utils } from 'nrpti-angular-components';
import { GlobalModule, LoadingScreenService, Utils, StoreService } from 'nrpti-angular-components';
import { CommonModule } from '../../../../../common/src/app/common.module';
import { ActivatedRouteStub, TestBedHelper } from '../../../../../common/src/app/spec/spec-utils';
import { RecordUtils } from '../../records/utils/record-utils';
Expand Down Expand Up @@ -51,6 +51,7 @@ describe('MinesCollectionsAddEditComponent', () => {
Utils,
RecordUtils,
DialogService,
StoreService,
{ provide: LoadingScreenService, useValue: mockLoadingScreenService },
{ provide: Router, useValue: mockRouter },
{ provide: ActivatedRoute, useValue: mockActivatedRoute },
Expand All @@ -59,9 +60,9 @@ describe('MinesCollectionsAddEditComponent', () => {
}).compileComponents();
}));

it('should create', () => {
it('should create', async(() => {
const { component } = testBedHelper.createComponent();

expect(component).toBeTruthy();
});
}));
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { FormArray, FormControl, FormGroup } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import moment from 'moment';
import { DialogService } from 'ng2-bootstrap-modal';
import { LoadingScreenService, Utils } from 'nrpti-angular-components';
import { LoadingScreenService, Utils, StoreService } from 'nrpti-angular-components';
import { of } from 'rxjs';
import { catchError, takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs/Subject';
import { Picklists } from '../../../../../common/src/app/utils/record-constants';
import { Picklists, StateIDs, StateStatus } from '../../../../../common/src/app/utils/record-constants';
import { ConfirmComponent } from '../../confirm/confirm.component';
import { RecordUtils } from '../../records/utils/record-utils';
import { FactoryService } from '../../services/factory.service';
Expand Down Expand Up @@ -38,6 +38,9 @@ export class MinesCollectionsAddEditComponent implements OnInit, OnDestroy {
public collectionTypes = Picklists.collectionTypePicklist;
public collectionAgencies = Picklists.collectionAgencyPicklist;

// collection add edit state
public collectionState = null;

constructor(
public route: ActivatedRoute,
public router: Router,
Expand All @@ -46,12 +49,15 @@ export class MinesCollectionsAddEditComponent implements OnInit, OnDestroy {
private loadingScreenService: LoadingScreenService,
private utils: Utils,
private dialogService: DialogService,
private storeService: StoreService,
private _changeDetectionRef: ChangeDetectorRef
) {}

ngOnInit() {
this.loadingScreenService.setLoadingState(true, 'main');

this.setOrRemoveCollectionAddEditState();

this.route.data.pipe(takeUntil(this.ngUnsubscribe)).subscribe((res: any) => {
this.isEditing = res.breadcrumb !== 'Add Collection';
if (this.isEditing) {
Expand All @@ -75,6 +81,22 @@ export class MinesCollectionsAddEditComponent implements OnInit, OnDestroy {
});
}

/**
* Sets the initial collectionAddEdit state, or removes it from the store if it is invalid.
*
* @memberof MinesCollectionsAddEditComponent
*/
setOrRemoveCollectionAddEditState() {
const tempCollectionAddEditState = this.storeService.getItem(StateIDs.collectionAddEdit);
if (tempCollectionAddEditState) {
if (tempCollectionAddEditState.status === StateStatus.invalid) {
this.storeService.removeItem(StateIDs.collectionAddEdit);
} else {
this.collectionState = tempCollectionAddEditState;
}
}
}

/**
* Sort the collection.collectionRecords array.
*
Expand Down Expand Up @@ -115,42 +137,76 @@ export class MinesCollectionsAddEditComponent implements OnInit, OnDestroy {
/**
* Build the add-edit form.
*
* If editing, pre-populate any existing values.
* If editing, pre-populate any existing values. If StoreService contains an item named 'collectionAddEdit', use any
* values set in that piece of state to pre-populate the form fields, and then clear that item from the store.
*
* @private
* @memberof MinesCollectionsAddEditComponent
*/
private buildForm() {
this.myForm = new FormGroup({
collectionName: new FormControl((this.collection && this.collection.name) || ''),
collectionName: new FormControl(
(this.collectionState && this.collectionState.collectionName) || (this.collection && this.collection.name) || ''
),
collectionDate: new FormControl(
(this.collection &&
this.collection.date &&
this.utils.convertJSDateToNGBDate(new Date(this.collection.date))) ||
(this.collectionState &&
this.collectionState.collectionDate &&
this.utils.convertJSDateToNGBDate(new Date(this.collectionState.collectionDate.date))) ||
(this.collection &&
this.collection.date &&
this.utils.convertJSDateToNGBDate(new Date(this.collection.date))) ||
'' ||
null
),
collectionType: new FormControl((this.collection && this.collection.type) || ''),
collectionAgency: new FormControl((this.collection && this.collection.agency) || ''),
collectionPublish: new FormControl((this.collection && this.collection.read.includes('public')) || false),
collectionRecords: new FormArray(this.getRecordsFormGroups())
collectionType: new FormControl(
(this.collectionState && this.collectionState.collectionType) || (this.collection && this.collection.type) || ''
),
collectionAgency: new FormControl(
(this.collectionState && this.collectionState.collectionAgency) ||
(this.collection && this.collection.agency) ||
''
),
collectionPublish: new FormControl(
(this.collectionState && this.collectionState.collectionPublish) ||
(this.collection && this.collection.read.includes('public')) ||
false
),
collectionRecords: new FormArray(
(this.collectionState && this.getRecordsFormGroups(this.collectionState.collectionRecords)) ||
(this.collection && this.getRecordsFormGroups(this.collection.collectionRecords)) ||
[]
)
});

if (this.collectionState) {
// State was saved from before, so mark everything dirty so as not to miss any previous user edits
this.myForm.get('collectionName').markAsDirty();
this.myForm.get('collectionDate').markAsDirty();
this.myForm.get('collectionType').markAsDirty();
this.myForm.get('collectionAgency').markAsDirty();
this.myForm.get('collectionPublish').markAsDirty();
this.myForm.get('collectionRecords').markAsDirty();

// Remove used state
this.storeService.removeItem(StateIDs.collectionAddEdit);
}
}

/**
* Builds an array of records FormGroups, each with its own set of FormControls.
*
* @param {*} recordsArray array of records to parse into an array of FormGroups
* @returns {FormGroup[]} array of records FormGroup elements
* @memberof MinesAddEditComponent
*/
getRecordsFormGroups(): FormGroup[] {
if (!this.collection || !this.collection.collectionRecords || !this.collection.collectionRecords.length) {
getRecordsFormGroups(recordsArray): FormGroup[] {
if (!recordsArray || !recordsArray.length) {
return [];
}

const records: FormGroup[] = [];

this.collection.collectionRecords.forEach((record: any) => {
recordsArray.forEach((record: any) => {
records.push(
new FormGroup({
record: new FormControl(record || null)
Expand Down Expand Up @@ -216,6 +272,38 @@ export class MinesCollectionsAddEditComponent implements OnInit, OnDestroy {
this.myForm.get('collectionRecords').markAsDirty();
}

/**
* Add records to the collections array of associated records.
*
* @memberof MinesCollectionsAddEditComponent
*/
onAddRecordsToCollection() {
// Save the current state of the form using the store service.
// This should always overwrite any existing collectionAddEdit state, and not append to it.
this.storeService.setItem({
collectionAddEdit: {
// routing ids
mineId: this.route.snapshot.paramMap.get('mineId'),
collectionId: (this.collection && this.collection._id) || null,

// form values
collectionName: this.myForm.get('collectionName').value,
collectionDate: this.myForm.get('collectionDate').value,
collectionType: this.myForm.get('collectionType').value,
collectionAgency: this.myForm.get('collectionAgency').value,
collectionPublish: this.myForm.get('collectionPublish').value,
collectionRecords: this.myForm.get('collectionRecords').value.map(recordFormGroup => recordFormGroup.record),
originalCollectionRecords: this.myForm
.get('collectionRecords')
.value.map(recordFormGroup => recordFormGroup.record),
status: StateStatus.created
}
});

// Navigate to the record list page for this mine
this.router.navigate(['mines', this.route.snapshot.paramMap.get('mineId'), 'records']);
}

/**
* Remove a record from the collections array of associated records.
*
Expand Down Expand Up @@ -351,6 +439,13 @@ export class MinesCollectionsAddEditComponent implements OnInit, OnDestroy {
}

ngOnDestroy(): void {
// When the component is destroying, if collectionAddEdit state exists, but the user hadn't clicked the
// 'addRecordsToCollection' button, then remove the collection state from the store.
const collectionAddEditState = this.storeService.getItem(StateIDs.collectionAddEdit);
if (collectionAddEditState && collectionAddEditState.status !== StateStatus.created) {
this.storeService.removeItem(StateIDs.collectionAddEdit);
}

this.loadingScreenService.setLoadingState(false, 'main');

this.ngUnsubscribe.next();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ describe('MinesCollectionsListResolver', () => {
'updateTableObjectWithUrlParams'
]);

beforeEach(() => {
beforeEach(async(() => {
TestBed.configureTestingModule({
providers: [
{ provide: FactoryService, useValue: spyFactoryService },
{ provide: TableTemplateUtils, useValue: spyTableTemplateUtils }
]
}).compileComponents();
});
}));

it('should create', async(() => {
const factoryService = TestBed.get(FactoryService);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,11 @@ <h1 id="name" class="m-0">{{ (mine && mine.name) || '-' }}</h1>
</section>

<section>
<div class="border-bottom">
<div class="text-right mb-3">
<button class="btn btn-primary" (click)="addCollection()" title="Create new collection">
<i class="material-icons mr-1 align-middle">add</i>
<span class="align-middle">Create New Collection</span>
</button>
</div>
<div class="text-right mb-3">
<button class="btn btn-primary" (click)="addCollection()" title="Create new collection">
<i class="material-icons mr-1 align-middle">add</i>
<span class="align-middle">Create New Collection</span>
</button>
</div>
</section>

Expand All @@ -73,4 +71,4 @@ <h1 id="name" class="m-0">{{ (mine && mine.name) || '-' }}</h1>
></lib-table-template>
</section>

</main>
</main>
Loading

0 comments on commit 92113e9

Please sign in to comment.