Skip to content

Commit

Permalink
Merged in feature/admin-pagination (pull request #13)
Browse files Browse the repository at this point in the history
Added generalised Material pagination table for admin backend views

Approved-by: Marcus Riemer
  • Loading branch information
yannickpschroeder authored and MarcusRiemer committed Apr 2, 2020
2 parents fa3ba04 + 7072bfb commit 387a981
Show file tree
Hide file tree
Showing 96 changed files with 2,763 additions and 913 deletions.
4 changes: 3 additions & 1 deletion client/src/app/admin/admin.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { adminRouting } from "./admin.routes";

import { AdminComponent } from "./admin.component";
import { AdminOverviewComponent } from "./admin-overview.component";
import { EditGrammarComponent } from "./edit-grammar.component";
import { LinkGrammarComponent } from "./link-grammar.component";
import { JsonEditor } from "./json-editor.component";
import { JsonSchemaValidationService } from "./json-schema-validation.service";
Expand All @@ -36,8 +35,10 @@ import { ErrorListComponent } from "./block-language/error-list.component";
import { OverviewBlockLanguageComponent } from "./block-language/overview-block-language.component";

import { CreateGrammarComponent } from "./grammar/create-grammar.component";
import { EditGrammarComponent } from "./grammar/edit-grammar.component";
import { OverviewGrammarComponent } from "./grammar/overview-grammar.component";
import { GalleryGrammarComponent } from "./grammar/gallery-grammar.component";
import { MetaCodeResourceSelectComponent } from "./grammar/meta-code-resource-select.component";

import { OverviewProjectComponent } from "./project/overview-project.component";

Expand Down Expand Up @@ -91,6 +92,7 @@ const materialModules = [
AdminNewsEditComponent,
ChangeRoles,
GalleryGrammarComponent,
MetaCodeResourceSelectComponent,
],
providers: [JsonSchemaValidationService],
exports: [],
Expand Down
2 changes: 1 addition & 1 deletion client/src/app/admin/admin.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { Routes, RouterModule } from "@angular/router";

import { AdminComponent, adminItems } from "./admin.component";
import { AdminOverviewComponent } from "./admin-overview.component";
import { EditGrammarComponent } from "./edit-grammar.component";
import { EditBlockLanguageComponent } from "./block-language/edit-block-language.component";
import { EditGrammarComponent } from "./grammar/edit-grammar.component";
import { OverviewGrammarComponent } from "./grammar/overview-grammar.component";
import { OverviewBlockLanguageComponent } from "./block-language/overview-block-language.component";
import { NavSiteComponent } from "../shared/nav-page.component";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import { generateBlockLanguage } from "../../shared/block/generator/generator";

import {
ServerApiService,
BlockLanguageDataService,
GrammarDataService,
ListBlockLanguageDataService,
IndividualGrammarDataService,
ListGrammarDataService,
} from "../../shared/serverdata";

/**
Expand Down Expand Up @@ -39,19 +40,15 @@ export class CreateBlockLanguageComponent {
useSlug = false;

constructor(
private _serverData: BlockLanguageDataService,
private _grammarData: GrammarDataService,
private _serverData: ListBlockLanguageDataService,
private _grammarData: IndividualGrammarDataService,
private _grammarList: ListGrammarDataService,
private _serverApi: ServerApiService,
private _http: HttpClient,
private _router: Router
) {}

/**
* Grammars that may be used for creation
*/
public get availableGrammars() {
return this._grammarData.list;
}
readonly availableGrammars = this._grammarList.list;

/**
* Attempts to create the specified block language
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {
import { ActivatedRoute, Router } from "@angular/router";

import {
GrammarDataService,
BlockLanguageDataService,
ListGrammarDataService,
MutateBlockLanguageService,
} from "../../shared/serverdata";
import { ToolbarService } from "../../shared/toolbar.service";

Expand All @@ -25,8 +25,8 @@ export class EditBlockLanguageComponent implements AfterViewInit {
constructor(
private _activatedRoute: ActivatedRoute,
private _router: Router,
private _grammarData: GrammarDataService,
private _blockLanguageData: BlockLanguageDataService,
private _grammarData: ListGrammarDataService,
private _mutateBlockLanguageData: MutateBlockLanguageService,
private _current: EditBlockLanguageService,
private _toolbarService: ToolbarService
) {}
Expand Down Expand Up @@ -117,7 +117,7 @@ export class EditBlockLanguageComponent implements AfterViewInit {
* User has decided to delete.
*/
async onDelete() {
await this._blockLanguageData.deleteSingle(this.editedSubject.id);
await this._mutateBlockLanguageData.deleteSingle(this.editedSubject.id);
this._router.navigate([".."], { relativeTo: this._activatedRoute });
}

Expand Down
22 changes: 14 additions & 8 deletions client/src/app/admin/block-language/edit-block-language.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import { BehaviorSubject } from "rxjs";
import { switchMap, map, first, filter, flatMap } from "rxjs/operators";

import {
GrammarDataService,
BlockLanguageDataService,
IndividualGrammarDataService,
IndividualBlockLanguageDataService,
MutateBlockLanguageService,
} from "../../shared/serverdata";
import { BlockLanguageDescription } from "../../shared/block/block-language.description";
import {
Expand All @@ -34,8 +35,9 @@ export class EditBlockLanguageService {
public prettyPrintedBlockLanguage = "";

constructor(
private _serverData: BlockLanguageDataService,
private _grammarData: GrammarDataService,
private _individualBlockLanguageData: IndividualBlockLanguageDataService,
private _mutateBlockLanguageData: MutateBlockLanguageService,
private _individualGrammarData: IndividualGrammarDataService,
private _activatedRoute: ActivatedRoute,
private _snackBar: MatSnackBar,
private _title: Title
Expand All @@ -44,7 +46,9 @@ export class EditBlockLanguageService {
this._activatedRoute.paramMap
.pipe(
map((params: ParamMap) => params.get("blockLanguageId")),
switchMap((id: string) => this._serverData.getSingle(id).pipe(first()))
switchMap((id: string) =>
this._individualBlockLanguageData.getSingle(id).pipe(first())
)
)
.subscribe((blockLanguage) => {
this._editedSubject.next(blockLanguage);
Expand All @@ -67,7 +71,9 @@ export class EditBlockLanguageService {
* The grammar that is the basis for this block language.
*/
readonly baseGrammar = this._editedSubject.pipe(
flatMap((blockLang) => this._grammarData.getSingle(blockLang.grammarId))
flatMap((blockLang) =>
this._individualGrammarData.getSingle(blockLang.grammarId)
)
);

/**
Expand Down Expand Up @@ -121,7 +127,7 @@ export class EditBlockLanguageService {
// And do something meaningful if they are
if (this.generatorErrors.length === 0) {
// Fetch the actual grammar that should be used
this._grammarData
this._individualGrammarData
.getSingle(this.editedSubject.grammarId, true)
.pipe(first())
.subscribe((g) => {
Expand Down Expand Up @@ -170,7 +176,7 @@ export class EditBlockLanguageService {
* Saves the current state of the block language
*/
save() {
this._serverData.updateBlockLanguage(this.editedSubject);
this._mutateBlockLanguageData.updateSingle(this.editedSubject);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { MatAutocompleteSelectedEvent } from "@angular/material/autocomplete";

import { first, map, tap } from "rxjs/operators";

import { GrammarDataService } from "../../shared/serverdata";
import { IndividualGrammarDataService } from "../../shared/serverdata";
import { ScopeTraitAdd } from "../../shared/block/generator/traits.description";
import {
FullNodeAttributeDescription,
Expand Down Expand Up @@ -48,7 +48,7 @@ interface TargetBlock {
export class EditSingleTraitScopeComponent implements OnInit, OnChanges {
constructor(
private _editedBlockLanguageService: EditBlockLanguageService,
private _grammarData: GrammarDataService
private _individualGrammarData: IndividualGrammarDataService
) {}

/**
Expand Down Expand Up @@ -81,7 +81,7 @@ export class EditSingleTraitScopeComponent implements OnInit, OnChanges {
* Used to get hold of the grammar that is used by this block language.
*/
ngOnInit() {
this._grammarData
this._individualGrammarData
.getSingle(this._editedBlockLanguageService.editedSubject.grammarId)
.pipe(first())
.subscribe((g) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import { FormsModule } from "@angular/forms";
import { RouterTestingModule } from "@angular/router/testing";
import { TestBed } from "@angular/core/testing";
import { NoopAnimationsModule } from "@angular/platform-browser/animations";
import {
HttpClientTestingModule,
HttpTestingController,
} from "@angular/common/http/testing";
import { MatSnackBarModule } from "@angular/material/snack-bar";
import { MatTableModule } from "@angular/material/table";
import { MatPaginatorModule } from "@angular/material/paginator";
import { MatSortModule } from "@angular/material/sort";
import { PortalModule } from "@angular/cdk/portal";

import { first } from "rxjs/operators";

import { ServerApiService, ToolbarService } from "../../shared";
import {
ListBlockLanguageDataService,
MutateBlockLanguageService,
} from "../../shared/serverdata";
import { DefaultValuePipe } from "../../shared/default-value.pipe";
import {
provideBlockLanguageList,
buildBlockLanguage,
} from "../../editor/spec-util";

import { OverviewBlockLanguageComponent } from "./overview-block-language.component";
import { PaginatorTableComponent } from "../../shared/table/paginator-table.component";

describe("OverviewBlockLanguageComponent", () => {
async function createComponent() {
await TestBed.configureTestingModule({
imports: [
FormsModule,
NoopAnimationsModule,
MatSnackBarModule,
MatTableModule,
MatPaginatorModule,
MatSortModule,
PortalModule,
HttpClientTestingModule,
RouterTestingModule.withRoutes([]),
],
providers: [
ToolbarService,
ServerApiService,
ListBlockLanguageDataService,
MutateBlockLanguageService,
],
declarations: [
OverviewBlockLanguageComponent,
DefaultValuePipe,
PaginatorTableComponent,
],
}).compileComponents();

let fixture = TestBed.createComponent(OverviewBlockLanguageComponent);
let component = fixture.componentInstance;
fixture.detectChanges();

const httpTesting = TestBed.inject(HttpTestingController);
const serverApi = TestBed.inject(ServerApiService);

return {
fixture,
component,
element: fixture.nativeElement as HTMLElement,
httpTesting,
serverApi,
};
}

it(`can be instantiated`, async () => {
const t = await createComponent();

expect(t.component).toBeDefined();
});

it(`Displays a loading indicator (or not)`, async () => {
const t = await createComponent();

const initialLoading = await t.component.blockLanguages.listCache.inProgress
.pipe(first())
.toPromise();
expect(initialLoading).toBe(true);

provideBlockLanguageList([]);

const afterResponse = await t.component.blockLanguages.listCache.inProgress
.pipe(first())
.toPromise();
expect(afterResponse).toBe(false);
});

it(`Displays an empty list`, async () => {
const t = await createComponent();

provideBlockLanguageList([]);

t.fixture.detectChanges();
await t.fixture.whenRenderingDone();
});

it(`Displays a list with a single element`, async () => {
const t = await createComponent();

const i1 = buildBlockLanguage({ name: "B1" });
provideBlockLanguageList([i1]);

t.fixture.detectChanges();
await t.fixture.whenRenderingDone();

const tableElement = t.element.querySelector("table");
const i1Row = tableElement.querySelector("tbody > tr");

expect(i1Row.textContent).toMatch(i1.name);
expect(i1Row.textContent).toMatch(i1.id);
});

it(`reloads data on refresh`, async () => {
const t = await createComponent();

const i1 = buildBlockLanguage({ name: "B1" });
provideBlockLanguageList([i1]);

const initialData = await t.component.blockLanguages.list
.pipe(first())
.toPromise();
expect(initialData).toEqual([i1]);

t.component.onRefresh();
provideBlockLanguageList([]);

const refreshedData = await t.component.blockLanguages.list
.pipe(first())
.toPromise();
expect(refreshedData).toEqual([]);
});

it(`Triggers deletion`, async () => {
const t = await createComponent();

const i1 = buildBlockLanguage({ name: "B1" });
provideBlockLanguageList([i1]);

t.fixture.detectChanges();
await t.fixture.whenRenderingDone();

const tableElement = t.element.querySelector("table");
const i1Row = tableElement.querySelector("tbody > tr");
const i1Delete = i1Row.querySelector(
"button[data-spec=delete]"
) as HTMLButtonElement;

i1Delete.click();

t.httpTesting
.expectOne({
method: "DELETE",
url: t.serverApi.individualBlockLanguageUrl(i1.id),
})
.flush("");

provideBlockLanguageList([]);

const refreshedData = await t.component.blockLanguages.list
.pipe(first())
.toPromise();
expect(refreshedData).toEqual([]);
});
});
Loading

0 comments on commit 387a981

Please sign in to comment.