Skip to content

Commit

Permalink
Propose KEP layout
Browse files Browse the repository at this point in the history
Signed-off-by: Sascha Grunert <sgrunert@suse.com>
  • Loading branch information
saschagrunert committed Jan 27, 2020
1 parent 7694654 commit a78ab1d
Show file tree
Hide file tree
Showing 48 changed files with 3,694 additions and 36,160 deletions.
37 changes: 11 additions & 26 deletions src/app/filter/filter.component.ts
Expand Up @@ -4,7 +4,7 @@ import { skip } from 'rxjs/operators';
import { Options, OptionType } from '@app/shared/model/options.model';
import { Filter } from '@app/shared/model/filter.model';
import { Settings } from '@app/shared/model/settings.model';
import { Note } from '@app/shared/model/notes.model';
import { Kep } from '@app/shared/model/notes.model';
import { getAllNotesSelector } from '@app/notes/notes.reducer';
import { State } from '@app/app.reducer';
import { UpdateFilter } from './filter.actions';
Expand All @@ -20,7 +20,7 @@ export class FilterComponent implements OnInit {
options: Options = new Options();
filter: Filter = new Filter();
settings: Settings = new Settings();
notes: Note[] = [];
keps: Kep[] = [];

/**
* FilterComponent's constructor
Expand All @@ -31,9 +31,9 @@ export class FilterComponent implements OnInit {
* Runs after component initialization
*/
ngOnInit() {
this.store.pipe(select(getAllNotesSelector)).subscribe(notes => {
if (notes) {
this.notes = notes;
this.store.pipe(select(getAllNotesSelector)).subscribe(keps => {
if (keps) {
this.keps = keps;
this.updateOptions();
}
});
Expand All @@ -54,34 +54,19 @@ export class FilterComponent implements OnInit {
}

/**
* Update the options from the provided notes
* Update the options from the provided keps
*/
updateOptions(): void {
// Reset the options
this.options = new Options();

// Populate the new options
for (const note of Object.values(this.notes)) {
if (OptionType.areas in note) {
this.options.add(OptionType.areas, note.areas);
for (const kep of Object.values(this.keps)) {
if (OptionType.owningSigs in kep) {
this.options.add(OptionType.owningSigs, [kep.owningSig]);
}
if (OptionType.kinds in note) {
this.options.add(OptionType.kinds, note.kinds);
}
if (OptionType.sigs in note) {
this.options.add(OptionType.sigs, note.sigs);
}
if (OptionType.documentation in note) {
this.options.add(
OptionType.documentation,
note.documentation.map(x => x.type.toString()),
);
}
if (
!this.options.get(OptionType.releaseVersions).has(note.release_version) &&
(this.settings.displayPreReleases || !this.filter.isPreRelease(note.release_version))
) {
this.options.get(OptionType.releaseVersions).add(note.release_version);
if (OptionType.participatingSigs in kep) {
this.options.add(OptionType.participatingSigs, kep.participatingSigs);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/app/main/main.component.html
@@ -1,7 +1,7 @@
<nav class="navbar fixed-top navbar-dark bg-dark navbar-expand-lg shadow">
<a class="navbar-brand" href="/">
<img src="assets/img/logo.svg" alt="kubernetes" class="d-inline-block align-top" />
release notes
Enhancement Proposals
</a>
<button
class="navbar-toggler"
Expand Down
8 changes: 4 additions & 4 deletions src/app/notes/notes.actions.ts
@@ -1,5 +1,5 @@
import { Action } from '@ngrx/store';
import { Note } from '@app/shared/model/notes.model';
import { Kep } from '@app/shared/model/notes.model';
import { Filter } from '@app/shared/model/filter.model';

export enum ActionTypes {
Expand All @@ -19,12 +19,12 @@ export class Failed implements Action {

export class DoFilter implements Action {
readonly type = ActionTypes.DoFilter;
constructor(public notes: Note[], public filter: Filter) {}
constructor(public notes: Kep[], public filter: Filter) {}
}

export class DoFilterSuccess implements Action {
readonly type = ActionTypes.DoFilterSuccess;
constructor(public notes: Note[]) {}
constructor(public notes: Kep[]) {}
}

export class GetNotes implements Action {
Expand All @@ -34,7 +34,7 @@ export class GetNotes implements Action {

export class GetNotesSuccess implements Action {
readonly type = ActionTypes.GetNotesSuccess;
constructor(public payload: Note[]) {}
constructor(public payload: Kep[]) {}
}

export type NotesAction = Failed | DoFilter | DoFilterSuccess | GetNotes | GetNotesSuccess;
61 changes: 18 additions & 43 deletions src/app/notes/notes.component.html
Expand Up @@ -4,64 +4,39 @@
<ng-container *ngFor="let note of filteredNotes | paginate: { itemsPerPage: 10, currentPage: p }">
<div class="card">
<div class="card-header">
<a target="_blank" href="{{ note.pr_url }}">#{{ note.pr_number }}</a> by
<a target="_blank" href="{{ note.author_url }}">{{ note.author }}</a>
<a target="_blank" href="#">#{{ note.title }}</a> by
<a target="_blank" href="#">{{ note.authors }} </a>
<span>(owned by {{ note.owningSig }})</span>
<br />
<span>{{ note.creationDate }} (Updated: {{ note.lastUpdated }})</span>

<a
ngbTooltip="Additional Documentation"
ngbTooltip="Show"
placement="right"
tooltipClass="documentationTooltip"
*ngIf="note.documentation"
class="text-secondary"
id="documentationButton-{{ note.pr_number }}"
id="documentationButton-{{ note.id }}"
data-toggle="collapse"
href="#documentationContent-{{ note.pr_number }}"
href="#documentationContent-{{ note.id }}"
>
<fa-icon class="icon" [icon]="faBook" size="lg"></fa-icon>
</a>
<span
(click)="toggleFilter(OptionType.releaseVersions, note.release_version)"
class="k8s-badge float-sm-right badge badge-dark"
>{{ note.release_version }}</span
>

<span class="k8s-badge float-sm-right badge badge-dark"
>Reviewed by: {{ note.reviewers }}</span
>
<span
*ngFor="let sig of note.sigs"
(click)="toggleFilter(OptionType.sigs, sig)"
*ngFor="let sig of note.participatingSigs"
class="k8s-badge float-sm-right badge badge-success"
>{{ sig }}</span
>
<span
*ngFor="let kind of note.kinds"
(click)="toggleFilter(OptionType.kinds, kind)"
class="k8s-badge float-sm-right badge badge-primary"
>{{ kind }}</span
>
<span
*ngFor="let area of note.areas"
(click)="toggleFilter(OptionType.areas, area)"
class="k8s-badge float-sm-right badge badge-secondary"
>{{ area }}</span
>
<span class="k8s-badge float-sm-right badge badge-success">Editor: {{ note.editor }}</span>
<span class="k8s-badge float-sm-right badge badge-primary">{{ note.status }}</span>
</div>
<div class="card-body">
<div [innerHTML]="note.markdown | markdown"></div>
<div
*ngIf="note.documentation"
class="collapse {{ collapseClass() }}"
id="documentationContent-{{ note.pr_number }}"
>
<h6>Additional Documentation</h6>
<ul>
<li *ngFor="let doc of note.documentation">
<a href="{{ doc.url }}" target="_blank">
<span *ngIf="doc.description; else elseBlock">
{{ saneKEPDescription(doc) }}
</span>
<ng-template #elseBlock>{{ doc.url }}</ng-template>
<span class="badge doc-badge {{ badgeClass(doc.type) }}">{{ doc.type }}</span>
</a>
</li>
</ul>
<div [innerHTML]="toc(note.markdown) | markdown"></div>
<div class="collapse {{ collapseClass() }}" id="documentationContent-{{ note.id }}">
<div [innerHTML]="stripToc(note.markdown) | markdown"></div>
</div>
</div>
</div>
Expand Down
60 changes: 24 additions & 36 deletions src/app/notes/notes.component.ts
@@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import { Store, select } from '@ngrx/store';
import { Note, Documentation } from '@app/shared/model/notes.model';
import { Kep } from '@app/shared/model/notes.model';
import { DoFilter, GetNotes } from './notes.actions';
import { State } from '@app/app.reducer';
import { getErrorSelector, getAllNotesSelector, getFilteredNotesSelector } from './notes.reducer';
Expand All @@ -18,13 +18,14 @@ import { getFilterSelector } from '@app/filter/filter.reducer';
})
export class NotesComponent {
filter: Filter = new Filter();
allNotes: Note[] = [];
filteredNotes: Note[] = [];
allNotes: Kep[] = [];
filteredNotes: Kep[] = [];
p = 1;
faBook = faBook;
errorMessage = '';

readonly kep = 'KEP';
readonly tocStart = '<!-- toc -->';
readonly tocEnd = '<!-- /toc -->';

constructor(private store: Store<State>) {
this.store.dispatch(new GetNotes());
Expand Down Expand Up @@ -74,50 +75,37 @@ export class NotesComponent {
}

/**
* Retrieve the badge css class for a given documentation string
* Retrieve the collapse css class based on the current filter
*
* @returns The resulting class as string
*/
public badgeClass(t: string): string {
if (t === this.kep) {
return 'badge-primary';
} else if (t === 'official') {
return 'badge-success';
}
return 'badge-secondary';
public collapseClass(): string {
/* if (!this.filter.optionIsEmpty(OptionType.owningSigs)) {
return 'show';
} */
return '';
}

/**
* Sanitize the documentation description
*
* @param doc The documentation to be processed
* Returns the table of contents from a markdown string
*
* @returns The resulting description as string
* @returns The resulting string
*/
public saneKEPDescription(doc: Documentation): string {
const stripped = doc.description
.replace(/[\[\]]/g, '') // remove brackets
.replace(this.kep, '') // remove 'KEP'
.trim();

if (stripped === '') {
// write out KEP
return 'Kubernetes Enhancement Proposal';
}

// all other sort of descriptions
return stripped;
public toc(md: string): string {
const toc = md.substring(
md.lastIndexOf(this.tocStart) + this.tocStart.length,
md.lastIndexOf(this.tocEnd),
);
const result = toc.replace(/\[(.*)\]\(.*\)/g, '$1');
return result;
}

/**
* Retrieve the collapse css class based on the current filter
* Strips the table of contents from a markdown string
*
* @returns The resulting class as string
* @returns The resulting string
*/
public collapseClass(): string {
if (!this.filter.optionIsEmpty(OptionType.documentation)) {
return 'show';
}
return '';
public stripToc(md: string): string {
return md.substring(md.lastIndexOf(this.tocEnd));
}
}
52 changes: 14 additions & 38 deletions src/app/notes/notes.effects.ts
Expand Up @@ -4,7 +4,7 @@ import { of } from 'rxjs';
import { catchError, exhaustMap, map } from 'rxjs/operators';
import { ActionTypes, DoFilterSuccess, DoFilter, Failed, GetNotesSuccess } from './notes.actions';
import { NotesService } from './notes.service';
import { Note } from '@app/shared/model/notes.model';
import { Kep } from '@app/shared/model/notes.model';
import { OptionType } from '@app/shared/model/options.model';
import { LoggerService } from '@shared/services/logger.service';

Expand All @@ -15,7 +15,7 @@ export class NotesEffects {
ofType(ActionTypes.GetNotes),
exhaustMap(() =>
this.notesService.getNotes().pipe(
map((notes: Note[]) => {
map((notes: Kep[]) => {
this.logger.debug('[Notes Effects:GetNotes] SUCCESS');
return new GetNotesSuccess(notes);
}),
Expand All @@ -40,70 +40,46 @@ export class NotesEffects {
};
}),
exhaustMap(data => {
const filteredNotes: Set<Note> = new Set();
const filteredKeps: Set<Kep> = new Set();
const filter = data.filter;

for (const note of data.notes) {
// Filter the release versions
if (
!filter.has(OptionType.releaseVersions, note.release_version) &&
(!filter.optionIsEmpty(OptionType.releaseVersions) ||
filter.isPreRelease(note.release_version))
) {
// Wrong release version set, it will not be added
continue;
}

for (const kep of data.notes) {
// If the filter is empty (this ignores the releaseVersions field),
// show the note
if (filter.isEmpty()) {
filteredNotes.add(note);
filteredKeps.add(kep);
continue;
}

// Filter all regular option types
if (filter.hasAny(OptionType.areas, note.areas)) {
filteredNotes.add(note);
continue;
}
if (filter.hasAny(OptionType.kinds, note.kinds)) {
filteredNotes.add(note);
continue;
}
if (filter.hasAny(OptionType.sigs, note.sigs)) {
filteredNotes.add(note);
if (filter.has(OptionType.owningSigs, kep.owningSig)) {
filteredKeps.add(kep);
continue;
}
if (
note.documentation &&
filter.hasAny(
OptionType.documentation,
note.documentation.map(x => x.type.toString()),
)
) {
filteredNotes.add(note);
if (filter.hasAny(OptionType.participatingSigs, kep.participatingSigs)) {
filteredKeps.add(kep);
continue;
}

// Now lazily filter every string based field via the text based filter
if (filter.text.length > 0) {
for (const key of Object.keys(note)) {
for (const key of Object.keys(kep)) {
if (
typeof note[key] === 'string' &&
note[key]
typeof kep[key] === 'string' &&
kep[key]
.toUpperCase()
.trim()
.includes(filter.text.toUpperCase().trim())
) {
filteredNotes.add(note);
filteredKeps.add(kep);
break;
}
}
}
}

this.logger.debug('[Notes Effects:DoFilter] SUCCESS (filtered)');
return of(new DoFilterSuccess([...filteredNotes]));
return of(new DoFilterSuccess([...filteredKeps]));
}),
);

Expand Down

0 comments on commit a78ab1d

Please sign in to comment.