Skip to content

Commit

Permalink
Add settings component and add pre-release option
Browse files Browse the repository at this point in the history
This adds the new settings component and makes the display
of pre-releases optional.

Signed-off-by: Sascha Grunert <sgrunert@suse.com>
  • Loading branch information
saschagrunert committed Aug 13, 2019
1 parent d73d82d commit 780c828
Show file tree
Hide file tree
Showing 22 changed files with 431 additions and 35 deletions.
22 changes: 20 additions & 2 deletions cypress/integration/app.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
describe('Release Notes App', () => {
// Test constants
const aboutButton = '#aboutButton';
const aboutLink = '#aboutLink';
const settingsLink = '#settingsLink';
const appModal = 'app-modal';
const documentationButton = '#documentationButton';
const documentationContent = '#documentationContent';
Expand All @@ -11,6 +12,7 @@ describe('Release Notes App', () => {
const option1140 = `${optionID}-1-14-0`;
const option1150 = `${optionID}-1-15-0`;
const option1160 = `${optionID}-1-16-0`;
const option1170 = `${optionID}-1-17-0-alpha-2`;
const optionKubectl = `${optionID}-kubectl`;
const optionKubelet = `${optionID}-kubelet`;
const optionKEP = `${optionID}-KEP`;
Expand All @@ -31,8 +33,10 @@ describe('Release Notes App', () => {
const v1150entry4 = '#66635';
const v1150entry5 = '#66928';
const v1160entry1 = '#74416';
const v1170entry1 = '#69263';
const v1160entry1DocumentationButton = `${documentationButton}-${v1160entry1.replace('#', '')}`;
const v1160entry1DocumentationContent = `${documentationContent}-${v1160entry1.replace('#', '')}`;
const preReleaseSetting = '#preReleaseSetting';

beforeEach(() => {
cy.visit('/');
Expand Down Expand Up @@ -163,7 +167,7 @@ describe('Release Notes App', () => {
it(`should be possible to open the 'About' page`, () => {
// Given
// When
cy.get(aboutButton).click();
cy.get(aboutLink).click();

// Then
cy.get(appModal).should('be.visible');
Expand Down Expand Up @@ -269,4 +273,18 @@ describe('Release Notes App', () => {
cy.get(optionTest).should('be.checked');
cy.get(searchBar).should('have.attr', 'ng-reflect-model', 'shutdown');
});

it(`should be possible to enable showing pre-releases`, () => {
// Given
cy.get(settingsLink).click();
cy.get(preReleaseSetting).should('be.visible');
cy.get(preReleaseSetting).should('not.be.checked');
cy.get(option1170).should('not.be.visible');

// When
cy.get(preReleaseSetting).check();

// Then
cy.get(option1170).should('be.visible');
});
});
20 changes: 17 additions & 3 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { FilterComponent } from './filter/filter.component';
import { MainComponent } from './main/main.component';
import { ModalComponent } from './modal/modal.component';
import { NotesComponent } from './notes/notes.component';
import { SettingsComponent } from './settings/settings.component';

import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
Expand All @@ -18,16 +19,25 @@ import { LoggerService } from '@shared/services/logger.service';
import { EffectsModule } from '@ngrx/effects';
import { NotesEffects } from './notes/notes.effects';
import { FilterEffects } from './filter/filter.effects';
import { SettingsEffects } from './settings/settings.effects';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { StoreModule } from '@ngrx/store';
import { environment } from '../environments/environment';
import { notesReducer } from './notes/notes.reducer';
import { settingsReducer } from './settings/settings.reducer';
import { filterReducer } from './filter/filter.reducer';
import { MarkdownModule, MarkedOptions } from 'ngx-markdown';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';

@NgModule({
declarations: [AppComponent, FilterComponent, MainComponent, ModalComponent, NotesComponent],
declarations: [
AppComponent,
FilterComponent,
MainComponent,
ModalComponent,
NotesComponent,
SettingsComponent,
],
imports: [
HttpClientModule,
BrowserModule,
Expand All @@ -49,8 +59,12 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
},
},
}),
StoreModule.forRoot({ filter: filterReducer, notes: notesReducer }),
EffectsModule.forRoot([FilterEffects, NotesEffects]),
StoreModule.forRoot({
filter: filterReducer,
notes: notesReducer,
settings: settingsReducer,
}),
EffectsModule.forRoot([FilterEffects, NotesEffects, SettingsEffects]),
StoreDevtoolsModule.instrument({ maxAge: 25, logOnly: environment.production }),
FontAwesomeModule,
],
Expand Down
3 changes: 3 additions & 0 deletions src/app/app.reducer.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { ActionReducerMap } from '@ngrx/store';
import { State as NotesState, notesReducer } from './notes/notes.reducer';
import { State as FilterState, filterReducer } from './filter/filter.reducer';
import { State as SettingsState, settingsReducer } from './settings/settings.reducer';

export interface State {
filter: FilterState;
notes: NotesState;
settings: SettingsState;
}

export const reducers: ActionReducerMap<State> = {
filter: filterReducer,
notes: notesReducer,
settings: settingsReducer,
};
16 changes: 14 additions & 2 deletions src/app/filter/filter.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { notesReducer } from '@app/notes/notes.reducer';
import { Note } from '@app/notes/notes.model';
import { notesMock } from '@app/notes/notes.model.mock';
import { filterReducer } from '@app/filter/filter.reducer';
import { settingsReducer } from '@app/settings/settings.reducer';

describe('FilterComponent', () => {
let component: FilterComponent;
Expand All @@ -20,6 +21,7 @@ describe('FilterComponent', () => {
StoreModule.forRoot({
filter: combineReducers(filterReducer),
notes: combineReducers(notesReducer),
settings: combineReducers(settingsReducer),
}),
],
}).compileComponents();
Expand All @@ -43,18 +45,28 @@ describe('FilterComponent', () => {
});

it('should succeed to update options', () => {
component.updateOptions(notesMock);
component.notes = notesMock;
component.updateOptions();
expect(component.options.areas.length).toEqual(1);
expect(component.options.kinds.length).toEqual(1);
expect(component.options.sigs.length).toEqual(1);
expect(component.options.releaseVersions.length).toEqual(1);
});

it('should succeed to update options on empty/invalid notes', () => {
component.updateOptions([{} as Note]);
component.notes = [{} as Note];
component.updateOptions();
expect(component.options.areas.length).toEqual(0);
expect(component.options.kinds.length).toEqual(0);
expect(component.options.sigs.length).toEqual(0);
expect(component.options.releaseVersions.length).toEqual(1);
});

it('should indicate if a release version is a pre-release', () => {
expect(component.isPreRelease(undefined)).toBeFalsy();
expect(component.isPreRelease('1.15.1')).toBeFalsy();
expect(component.isPreRelease('1.16.0-alpha.1')).toBeTruthy();
expect(component.isPreRelease('1.16.0-beta.1')).toBeTruthy();
expect(component.isPreRelease('1.16.0-rc.1')).toBeTruthy();
});
});
43 changes: 39 additions & 4 deletions src/app/filter/filter.component.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { Component } from '@angular/core';
import { Store, select } from '@ngrx/store';
import { skip } from 'rxjs/operators';
import { Filter, Options } from '@app/shared/model/options.model';
import { Settings } from '@app/shared/model/settings.model';
import { Note } from '@app/notes/notes.model';
import { getAllNotesSelector } from '@app/notes/notes.reducer';
import { State } from '@app/app.reducer';
import { UpdateFilter } from './filter.actions';
import { getFilterSelector } from '@app/filter/filter.reducer';
import { getSettingsSelector } from '@app/settings/settings.reducer';

@Component({
selector: 'app-filter',
Expand All @@ -14,14 +17,17 @@ import { getFilterSelector } from '@app/filter/filter.reducer';
export class FilterComponent {
options: Options = new Options();
filter: Filter = new Filter();
settings: Settings = new Settings();
notes: Note[] = [];

/**
* FilterComponent's constructor
*/
constructor(private store: Store<State>) {
this.store.pipe(select(getAllNotesSelector)).subscribe(notes => {
if (notes) {
this.updateOptions(notes);
this.notes = notes;
this.updateOptions();
}
});

Expand All @@ -30,13 +36,25 @@ export class FilterComponent {
this.filter = filter;
}
});

this.store
.pipe(select(getSettingsSelector))
.pipe(skip(1))
.subscribe(settings => {
this.settings = settings;
this.updateOptions();
});
}

/**
* Update the options from the provided notes
*/
updateOptions(notes: Note[]): void {
for (const note of Object.values(notes)) {
updateOptions(): void {
// Reset the options
this.options = new Options();

// Populate the new options
for (const note of Object.values(this.notes)) {
if ('areas' in note) {
this.options.areas = [...new Set(this.options.areas.concat(note.areas))];
}
Expand All @@ -53,12 +71,29 @@ export class FilterComponent {
),
];
}
if (this.options.releaseVersions.indexOf(note.release_version) < 0) {
if (
!this.options.releaseVersions.includes(note.release_version) &&
(this.settings.displayPreReleases || !this.isPreRelease(note.release_version))
) {
this.options.releaseVersions.push(note.release_version);
}
}
}

/**
* Test wheter a release version string is a pre release
*
* @param version The release version string
*
* @returns boolean true if it's a pre-release, otherwise false
*/
isPreRelease(version: string): boolean {
if (version) {
return version.includes('alpha') || version.includes('beta') || version.includes('rc');
}
return false;
}

/**
* Update the filter object based on the given parameters
*/
Expand Down
3 changes: 2 additions & 1 deletion src/app/main/main.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@
</ul>
<ul class="navbar-nav">
<li class="nav-item">
<button (click)="openModal()" id="aboutButton" class="btn btn-outline-info">About</button>
<a (click)="openModal()" href="#" id="aboutLink" class="nav-link">About</a>
</li>
<li class="nav-item" id="settingsButton"><app-settings></app-settings></li>
</ul>
</div>
</nav>
Expand Down
11 changes: 10 additions & 1 deletion src/app/main/main.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,28 @@ import { MainComponent } from './main.component';
import { NotesComponent } from '@app/notes/notes.component';
import { FilterComponent } from '@app/filter/filter.component';
import { ModalComponent } from '@app/modal/modal.component';
import { SettingsComponent } from '@app/settings/settings.component';
import { filterReducer } from '@app/filter/filter.reducer';
import { notesReducer } from '@app/notes/notes.reducer';
import { MarkdownModule, MarkedOptions } from 'ngx-markdown';
import { RouterTestingModule } from '@angular/router/testing';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { settingsReducer } from '@app/settings/settings.reducer';

describe('MainComponent', () => {
let component: MainComponent;
let fixture: ComponentFixture<MainComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [NotesComponent, FilterComponent, ModalComponent, MainComponent],
declarations: [
FilterComponent,
MainComponent,
ModalComponent,
NotesComponent,
SettingsComponent,
],
imports: [
FontAwesomeModule,
FormsModule,
Expand All @@ -44,6 +52,7 @@ describe('MainComponent', () => {
StoreModule.forRoot({
filter: combineReducers(filterReducer),
notes: combineReducers(notesReducer),
settings: combineReducers(settingsReducer),
}),
],
})
Expand Down
5 changes: 1 addition & 4 deletions src/app/notes/notes.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,7 @@ export class NotesService {

const observables = [];
for (const asset of assets) {
if (asset.hidden) {
continue;
}
observables.push(this.http.get(asset.path));
observables.push(this.http.get(asset));
}

return forkJoin(observables).pipe(map(this.toNoteList));
Expand Down
43 changes: 43 additions & 0 deletions src/app/settings/settings.actions.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { ActionTypes, UpdateSettings, UpdateSettingsSuccess, Failed } from './settings.actions';
import { Settings } from '@app/shared/model/settings.model';

describe('SettingsActions', () => {
// Given
const testSettings = new Settings();

it('should be able to create a Failed action', () => {
// Given
const error = 'error';

// When
const action = new Failed(error);

// Then
expect({ ...action }).toEqual({
type: ActionTypes.Failed,
error,
});
});

it('should be able to create a UpdateSettings action', () => {
// When
const action = new UpdateSettings(testSettings);

// Then
expect({ ...action }).toEqual({
type: ActionTypes.UpdateSettings,
settings: testSettings,
});
});

it('should be able to create a UpdateSettingsSuccess action', () => {
// When
const action = new UpdateSettingsSuccess(testSettings);

// Then
expect({ ...action }).toEqual({
type: ActionTypes.UpdateSettingsSuccess,
settings: testSettings,
});
});
});
26 changes: 26 additions & 0 deletions src/app/settings/settings.actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Action } from '@ngrx/store';
import { Settings } from '@app/shared/model/settings.model';

export enum ActionTypes {
Failed = '[Settings Component] Failed',

UpdateSettings = '[Settings Component] Update Settings',
UpdateSettingsSuccess = '[Settings Component] Update Settings Success',
}

export class Failed implements Action {
readonly type = ActionTypes.Failed;
constructor(public error: string) {}
}

export class UpdateSettings implements Action {
readonly type = ActionTypes.UpdateSettings;
constructor(public settings: Settings) {}
}

export class UpdateSettingsSuccess implements Action {
readonly type = ActionTypes.UpdateSettingsSuccess;
constructor(public settings: Settings) {}
}

export type SettingsAction = Failed | UpdateSettings | UpdateSettingsSuccess;
Loading

0 comments on commit 780c828

Please sign in to comment.