Просмотр исходного кода

feat(admin-ui): Create pagination & data table components

Michael Bromley 7 лет назад
Родитель
Сommit
d1658b0451

+ 1 - 0
admin-ui/package.json

@@ -36,6 +36,7 @@
     "core-js": "^2.5.4",
     "graphql": "^0.13.2",
     "graphql-tag": "^2.9.2",
+    "ngx-pagination": "^3.1.1",
     "rxjs": "^6.0.0",
     "rxjs-compat": "^6.2.1",
     "zone.js": "^0.8.26"

+ 9 - 0
admin-ui/src/app/shared/components/data-table/data-table-column.component.ts

@@ -0,0 +1,9 @@
+import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
+
+@Component({
+    selector: 'vdr-dt-column',
+    template: `<ng-template><ng-content></ng-content></ng-template>`,
+})
+export class DataTableColumnComponent {
+    @ViewChild(TemplateRef) template: TemplateRef<any>;
+}

+ 33 - 0
admin-ui/src/app/shared/components/data-table/data-table.component.html

@@ -0,0 +1,33 @@
+<table class="table">
+    <thead>
+    <tr>
+        <th *ngFor="let header of columns?.toArray()" class="left">
+            <ng-container *ngTemplateOutlet="header.template"></ng-container>
+        </th>
+    </tr>
+    </thead>
+    <tbody>
+    <tr *ngFor="let item of items | paginate:{ itemsPerPage: itemsPerPage, currentPage: currentPage, totalItems: totalItems }">
+        <ng-container *ngTemplateOutlet="rowTemplate; context: { item: item }"></ng-container>
+    </tr>
+    </tbody>
+</table>
+<div class="table-footer">
+
+    <div class="form-group">
+        <div class="select">
+            <select [value]="itemsPerPage" (change)="itemsPerPageChange.emit($event.target.value)">
+                <option [value]="10">10 per page</option>
+                <option [value]="25">25 per page</option>
+                <option [value]="50">50 per page</option>
+                <option [value]="100">100 per page</option>
+            </select>
+        </div>
+    </div>
+
+    <vdr-pagination-controls [currentPage]="currentPage"
+                             [itemsPerPage]="itemsPerPage"
+                             [totalItems]="totalItems"
+                             (pageChange)="pageChange.emit($event)"></vdr-pagination-controls>
+
+</div>

+ 7 - 0
admin-ui/src/app/shared/components/data-table/data-table.component.scss

@@ -0,0 +1,7 @@
+@import "variables";
+
+.table-footer {
+    display: flex;
+    align-items: baseline;
+    justify-content: space-between;
+}

+ 28 - 0
admin-ui/src/app/shared/components/data-table/data-table.component.spec.ts

@@ -0,0 +1,28 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { NgxPaginationModule } from 'ngx-pagination';
+import { PaginationControlsComponent } from '../pagination-controls/pagination-controls.component';
+import { DataTableColumnComponent } from './data-table-column.component';
+import { DataTableComponent } from './data-table.component';
+
+describe('DataTableComponent', () => {
+    let component: DataTableComponent;
+    let fixture: ComponentFixture<DataTableComponent>;
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+            imports: [NgxPaginationModule],
+            declarations: [ DataTableComponent, DataTableColumnComponent, PaginationControlsComponent ],
+        })
+            .compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(DataTableComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+});

+ 54 - 0
admin-ui/src/app/shared/components/data-table/data-table.component.ts

@@ -0,0 +1,54 @@
+import {
+    AfterViewInit,
+    ChangeDetectionStrategy,
+    Component,
+    ContentChild,
+    ContentChildren,
+    EventEmitter,
+    Input,
+    OnInit,
+    Output,
+    QueryList,
+    TemplateRef,
+} from '@angular/core';
+import { PaginationInstance, PaginationService } from 'ngx-pagination';
+import { DataTableColumnComponent } from './data-table-column.component';
+
+@Component({
+    selector: 'vdr-data-table',
+    templateUrl: 'data-table.component.html',
+    styleUrls: ['data-table.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+    providers: [PaginationService],
+})
+export class DataTableComponent implements OnInit, AfterViewInit {
+
+    @Input() items: any[];
+    @Input() itemsPerPage: number;
+    @Input() currentPage: number;
+    @Input() totalItems: number;
+    @Output() pageChange = new EventEmitter<number>();
+    @Output() itemsPerPageChange = new EventEmitter<number>();
+    @ContentChildren(DataTableColumnComponent) columns: QueryList<DataTableColumnComponent>;
+    @ContentChild(TemplateRef) rowTemplate: TemplateRef<any>;
+    paginationConfig: PaginationInstance;
+
+    ngOnInit() {
+        this.paginationConfig = {
+            itemsPerPage: this.itemsPerPage,
+            currentPage: this.currentPage,
+            totalItems: this.totalItems,
+        };
+    }
+
+    ngOnChanges() {
+        if (this.paginationConfig) {
+            this.paginationConfig.itemsPerPage = this.itemsPerPage;
+            this.paginationConfig.currentPage = this.currentPage;
+            this.paginationConfig.totalItems = this.totalItems;
+        }
+    }
+
+    ngAfterViewInit(): void {
+    }
+}

+ 35 - 0
admin-ui/src/app/shared/components/pagination-controls/pagination-controls.component.html

@@ -0,0 +1,35 @@
+<pagination-template #p="paginationApi"
+                     (pageChange)="pageChange.emit($event)">
+    <ul>
+        <li class="pagination-previous">
+
+            <a *ngIf="!p.isFirstPage()"
+               (click)="p.previous()"
+               (keyup.enter)="p.previous()"
+               tabindex="0"> « </a>
+            <div *ngIf="p.isFirstPage()"> « </div>
+        </li>
+
+        <li *ngFor="let page of p.pages">
+            <a (click)="p.setCurrent(page.value)"
+               (keyup.enter)="p.setCurrent(page.value)"
+               *ngIf="p.getCurrent() !== page.value"
+               tabindex="0">
+                {{ page.label }}
+            </a>
+
+            <div class="current" *ngIf="p.getCurrent() === page.value">
+                {{ page.label }}
+            </div>
+        </li>
+
+        <li class="pagination-next">
+            <a *ngIf="!p.isLastPage()"
+               (click)="p.next()"
+               (keyup.enter)="p.next()"
+               tabindex="0"> » </a>
+            <div *ngIf="p.isLastPage()"> » </div>
+        </li>
+
+    </ul>
+</pagination-template>

+ 29 - 0
admin-ui/src/app/shared/components/pagination-controls/pagination-controls.component.scss

@@ -0,0 +1,29 @@
+@import "variables";
+
+pagination-template {
+    display: block;
+    ul {
+        list-style-type: none;
+        display: flex;
+        justify-content: center;
+    }
+    li {
+        transition: border-bottom-color 0.2s;
+    }
+    li > a {
+        cursor: pointer;
+        &:hover, &:focus {
+            border-bottom-color: $color-grey-3;
+            text-decoration: none;
+        }
+    }
+    li > a, li > div {
+        padding: 3px 12px;
+        display: block;
+        border-bottom: 3px solid transparent;
+        user-select: none;
+    }
+    li > div.current {
+        border-bottom-color: $color-brand;
+    }
+}

+ 14 - 0
admin-ui/src/app/shared/components/pagination-controls/pagination-controls.component.ts

@@ -0,0 +1,14 @@
+import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
+
+@Component({
+    selector: 'vdr-pagination-controls',
+    templateUrl: './pagination-controls.component.html',
+    styleUrls: ['./pagination-controls.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class PaginationControlsComponent {
+    @Input() currentPage: number;
+    @Input() itemsPerPage: number;
+    @Input() totalItems: number;
+    @Output() pageChange = new EventEmitter<number>();
+}

+ 12 - 4
admin-ui/src/app/shared/shared.module.ts

@@ -1,11 +1,12 @@
 import { CommonModule } from '@angular/common';
-import { HttpClientModule } from '@angular/common/http';
 import { NgModule } from '@angular/core';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { RouterModule } from '@angular/router';
 import { ClarityModule } from '@clr/angular';
-import { ApolloModule } from 'apollo-angular';
-import { HttpLinkModule } from 'apollo-angular-link-http';
+import { NgxPaginationModule } from 'ngx-pagination';
+import { DataTableColumnComponent } from './components/data-table/data-table-column.component';
+import { DataTableComponent } from './components/data-table/data-table.component';
+import { PaginationControlsComponent } from './components/pagination-controls/pagination-controls.component';
 
 const IMPORTS = [
     ClarityModule,
@@ -13,11 +14,18 @@ const IMPORTS = [
     FormsModule,
     ReactiveFormsModule,
     RouterModule,
+    NgxPaginationModule,
+];
+
+const DECLARATIONS = [
+    DataTableComponent, DataTableColumnComponent, PaginationControlsComponent,
 ];
 
 @NgModule({
     imports: IMPORTS,
-    exports: IMPORTS,
+    exports: [...IMPORTS, ...DECLARATIONS],
+    declarations: DECLARATIONS,
+    entryComponents: [],
 })
 export class SharedModule {
 

+ 4 - 0
admin-ui/yarn.lock

@@ -5055,6 +5055,10 @@ next-tick@1:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
 
+ngx-pagination@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/ngx-pagination/-/ngx-pagination-3.1.1.tgz#fcde5cb5fd4a1bd6aa785ff062a55f3deefcd3ac"
+
 nice-try@^1.0.4:
   version "1.0.4"
   resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4"