Skip to content

Commit

Permalink
Added the frontend state wiring for the task audit log [#413]
Browse files Browse the repository at this point in the history
  • Loading branch information
mcpierce authored and BRUCELLA2 committed Jul 22, 2020
1 parent d3851df commit 14fea56
Show file tree
Hide file tree
Showing 19 changed files with 969 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { Action } from '@ngrx/store';
import { TaskAuditLogEntry } from 'app/backend-status/models/task-audit-log-entry';

export enum TaskAuditLogActionTypes {
GetEntries = '[TASK AUDIT LOG] Get task audit log entries',
ReceivedEntries = '[TASK AUDIT LOG] Task audit log entries received',
GetEntriesFailed = '[TASK AUDIT LOG] Failed to get task audit log entries'
}

export class GetTaskAuditLogEntries implements Action {
readonly type = TaskAuditLogActionTypes.GetEntries;

constructor(
public payload: {
cutoff: number;
}
) {}
}

export class ReceivedTaskAuditLogEntries implements Action {
readonly type = TaskAuditLogActionTypes.ReceivedEntries;

constructor(public payload: { entries: TaskAuditLogEntry[] }) {}
}

export class GetTaskAuditLogEntriesFailed implements Action {
readonly type = TaskAuditLogActionTypes.GetEntriesFailed;

constructor() {}
}

export type TaskAuditLogActions =
| GetTaskAuditLogEntries
| ReceivedTaskAuditLogEntries
| GetTaskAuditLogEntriesFailed;
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { TaskAuditLogAdaptor } from './task-audit-log.adaptor';
import {
TASK_AUDIT_LOG_ENTRY_1,
TASK_AUDIT_LOG_ENTRY_2,
TASK_AUDIT_LOG_ENTRY_3,
TASK_AUDIT_LOG_ENTRY_4,
TASK_AUDIT_LOG_ENTRY_5
} from 'app/backend-status/models/task-audit-log-entry.fixtures';
import { TestBed } from '@angular/core/testing';
import { Store, StoreModule } from '@ngrx/store';
import { AppState } from 'app/backend-status';
import {
GetTaskAuditLogEntries,
GetTaskAuditLogEntriesFailed,
ReceivedTaskAuditLogEntries
} from 'app/backend-status/actions/task-audit-log.actions';
import { LoggerModule } from '@angular-ru/logger';
import {
reducer,
TASK_AUDIT_LOG_FEATURE_KEY
} from 'app/backend-status/reducers/task-audit-log.reducer';
import { EffectsModule } from '@ngrx/effects';
import { TaskAuditLogEffects } from 'app/backend-status/effects/task-audit-log.effects';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { MessageService } from 'primeng/api';
import { TranslateModule } from '@ngx-translate/core';

describe('TaskAuditLogAdaptor', () => {
const LAST_ENTRY_DATE = new Date().getTime();
const LOG_ENTRIES = [
TASK_AUDIT_LOG_ENTRY_1,
TASK_AUDIT_LOG_ENTRY_2,
TASK_AUDIT_LOG_ENTRY_3,
TASK_AUDIT_LOG_ENTRY_4,
TASK_AUDIT_LOG_ENTRY_5
];

let taskAuditLogAdaptor: TaskAuditLogAdaptor;
let store: Store<AppState>;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
LoggerModule.forRoot(),
TranslateModule.forRoot(),
StoreModule.forRoot({}),
StoreModule.forFeature(TASK_AUDIT_LOG_FEATURE_KEY, reducer),
EffectsModule.forRoot([]),
EffectsModule.forFeature([TaskAuditLogEffects])
],
providers: [TaskAuditLogAdaptor, MessageService]
});

taskAuditLogAdaptor = TestBed.get(TaskAuditLogAdaptor);
store = TestBed.get(Store);
spyOn(store, 'dispatch').and.callThrough();
});

it('should create an instance', () => {
expect(taskAuditLogAdaptor).toBeTruthy();
});

describe('getting the list of task audit log entries', () => {
let lastEntryDate: number;

beforeEach(() => {
lastEntryDate = taskAuditLogAdaptor.lastEntryDate;
taskAuditLogAdaptor.getEntries();
});

it('fires an action', () => {
expect(store.dispatch).toHaveBeenCalledWith(
new GetTaskAuditLogEntries({ cutoff: lastEntryDate })
);
});

it('provides updates on fetching', () => {
taskAuditLogAdaptor.fetchingEntries$.subscribe(response =>
expect(response).toBeTruthy()
);
});

describe('success', () => {
beforeEach(() => {
store.dispatch(
new ReceivedTaskAuditLogEntries({ entries: LOG_ENTRIES })
);
});

it('provides updates on fetching', () => {
taskAuditLogAdaptor.fetchingEntries$.subscribe(response =>
expect(response).toBeFalsy()
);
});

it('provides updates on the log entries', () => {
taskAuditLogAdaptor.entries$.subscribe(response =>
expect(response).toEqual(LOG_ENTRIES)
);
});
});

describe('failure', () => {
beforeEach(() => {
store.dispatch(new GetTaskAuditLogEntriesFailed());
});

it('provides updates on fetching', () => {
taskAuditLogAdaptor.fetchingEntries$.subscribe(response =>
expect(response).toBeFalsy()
);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import {Injectable} from '@angular/core';
import {LoggerService} from '@angular-ru/logger';
import {Store} from '@ngrx/store';
import {AppState} from 'app/backend-status';
import {BehaviorSubject, Observable} from 'rxjs';
import {TaskAuditLogEntry} from 'app/backend-status/models/task-audit-log-entry';
import {GetTaskAuditLogEntries} from 'app/backend-status/actions/task-audit-log.actions';
import {TASK_AUDIT_LOG_FEATURE_KEY, TaskAuditLogState} from 'app/backend-status/reducers/task-audit-log.reducer';
import {filter} from 'rxjs/operators';
import * as _ from 'lodash';

@Injectable({
providedIn: 'root'
})
export class TaskAuditLogAdaptor {
private _lastEntryDate$ = new BehaviorSubject<number>(0);
private _fetchingEntries$ = new BehaviorSubject<boolean>(false);
private _entries$ = new BehaviorSubject<TaskAuditLogEntry[]>([]);

constructor(private logger: LoggerService, private store: Store<AppState>) {
this.store
.select(TASK_AUDIT_LOG_FEATURE_KEY)
.pipe(filter(state => !!state))
.subscribe((state: TaskAuditLogState) => {
this.logger.debug('task audit log state changed:', state);
if (!_.isEqual(this._lastEntryDate$.getValue(), state.lastEntryDate)) {
this._lastEntryDate$.next(state.lastEntryDate);
}
if (this._fetchingEntries$.getValue() !== state.fetchingEntries) {
this._fetchingEntries$.next(state.fetchingEntries);
}
if (!_.isEqual(this._entries$.getValue(), state.entries)) {
this._entries$.next(state.entries);
}
});
}

getEntries(): void {
this.logger.debug(
'getting task audit log entries:',
this._lastEntryDate$.getValue()
);
this.store.dispatch(
new GetTaskAuditLogEntries({cutoff: this._lastEntryDate$.getValue()})
);
}

get lastEntryDate(): number {
return this._lastEntryDate$.getValue();
}

get fetchingEntries$(): Observable<boolean> {
return this._fetchingEntries$.asObservable();
}

get entries$(): Observable<TaskAuditLogEntry[]> {
return this._entries$.asObservable();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { API_ROOT_URL } from 'app/app.functions';

export const GET_TASK_LOG_ENTRIES_URL = `${API_ROOT_URL}/tasks/entries/\${timestamp}`;
28 changes: 28 additions & 0 deletions comixed-frontend/src/app/backend-status/backend-status.fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

export {
BUILD_DETAILS
} from 'app/backend-status/models/build-details.fixtures';
export {
TASK_AUDIT_LOG_ENTRY_1,
TASK_AUDIT_LOG_ENTRY_2,
TASK_AUDIT_LOG_ENTRY_3,
TASK_AUDIT_LOG_ENTRY_4,
TASK_AUDIT_LOG_ENTRY_5
} from 'app/backend-status/models/task-audit-log-entry.fixtures';
12 changes: 10 additions & 2 deletions comixed-frontend/src/app/backend-status/backend-status.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ import { BackendStatusRoutingModule } from 'app/backend-status/backend-status-ro
import { BuildDetailsAdaptor } from 'app/backend-status/adaptors/build-details.adaptor';
import { StoreModule } from '@ngrx/store';
import * as fromBuildDetails from './reducers/build-details.reducer';
import * as fromTaskAuditLog from './reducers/task-audit-log.reducer';
import { EffectsModule } from '@ngrx/effects';
import { BuildDetailsEffects } from 'app/backend-status/effects/build-details.effects';
import { TranslateModule } from '@ngx-translate/core';
import { TaskAuditLogEffects } from 'app/backend-status/effects/task-audit-log.effects';
import { TaskAuditLogPageComponent } from './pages/task-audit-log-page/task-audit-log-page.component';
import { TaskAuditLogAdaptor } from 'app/backend-status/adaptors/task-audit-log.adaptor';

@NgModule({
declarations: [BuildDetailsPageComponent],
Expand All @@ -38,9 +42,13 @@ import { TranslateModule } from '@ngx-translate/core';
fromBuildDetails.BUILD_DETAILS_FEATURE_KEY,
fromBuildDetails.reducer
),
EffectsModule.forFeature([BuildDetailsEffects])
StoreModule.forFeature(
fromTaskAuditLog.TASK_AUDIT_LOG_FEATURE_KEY,
fromTaskAuditLog.reducer
),
EffectsModule.forFeature([BuildDetailsEffects, TaskAuditLogEffects])
],
exports: [CommonModule],
providers: [BuildDetailsService, BuildDetailsAdaptor]
providers: [BuildDetailsService, BuildDetailsAdaptor, TaskAuditLogAdaptor]
})
export class BackendStatusModule {}

0 comments on commit 14fea56

Please sign in to comment.