Browse Source

feat(admin-ui): Create basic Administrators list

Michael Bromley 7 years ago
parent
commit
b240f8dd97

+ 13 - 0
admin-ui/src/app/administrator/administrator.module.ts

@@ -0,0 +1,13 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+
+import { SharedModule } from '../shared/shared.module';
+
+import { administratorRoutes } from './administrator.routes';
+import { AdministratorListComponent } from './components/administrator-list/administrator-list.component';
+
+@NgModule({
+    imports: [SharedModule, RouterModule.forChild(administratorRoutes)],
+    declarations: [AdministratorListComponent],
+})
+export class AdministratorModule {}

+ 15 - 0
admin-ui/src/app/administrator/administrator.routes.ts

@@ -0,0 +1,15 @@
+import { Route } from '@angular/router';
+
+import { _ } from '../core/providers/i18n/mark-for-extraction';
+
+import { AdministratorListComponent } from './components/administrator-list/administrator-list.component';
+
+export const administratorRoutes: Route[] = [
+    {
+        path: 'administrators',
+        component: AdministratorListComponent,
+        data: {
+            breadcrumb: _('breadcrumb.administrators'),
+        },
+    },
+];

+ 33 - 0
admin-ui/src/app/administrator/components/administrator-list/administrator-list.component.html

@@ -0,0 +1,33 @@
+<vdr-action-bar>
+    <vdr-ab-right>
+        <a class="btn btn-primary" [routerLink]="['./create']">
+            <clr-icon shape="plus"></clr-icon>
+            {{ 'catalog.create-new-administrator' | translate }}
+        </a>
+    </vdr-ab-right>
+</vdr-action-bar>
+
+<vdr-data-table [items]="administrators$ | async"
+                [itemsPerPage]="itemsPerPage$ | async"
+                [totalItems]="totalItems$ | async"
+                [currentPage]="currentPage$ | async"
+                (pageChange)="setPageNumber($event)"
+                (itemsPerPageChange)="setItemsPerPage($event)">
+    <vdr-dt-column>{{ 'administrator.ID' | translate }}</vdr-dt-column>
+    <vdr-dt-column>{{ 'administrator.first-name' | translate }}</vdr-dt-column>
+    <vdr-dt-column>{{ 'administrator.last-name' | translate }}</vdr-dt-column>
+    <vdr-dt-column>{{ 'administrator.email-address' | translate }}</vdr-dt-column>
+    <vdr-dt-column></vdr-dt-column>
+    <ng-template let-administrator="item">
+        <td class="left">{{ administrator.id }}</td>
+        <td class="left">{{ administrator.firstName }}</td>
+        <td class="left">{{ administrator.lastName }}</td>
+        <td class="left">{{ administrator.emailAddress }}</td>
+        <td class="right">
+            <vdr-table-row-action iconShape="edit"
+                                  [label]="'common.edit' | translate"
+                                  [linkTo]="['./', administrator.id]">
+            </vdr-table-row-action>
+        </td>
+    </ng-template>
+</vdr-data-table>

+ 0 - 0
admin-ui/src/app/administrator/components/administrator-list/administrator-list.component.scss


+ 67 - 0
admin-ui/src/app/administrator/components/administrator-list/administrator-list.component.ts

@@ -0,0 +1,67 @@
+import { Component, OnDestroy, OnInit } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { combineLatest, Observable, Subject } from 'rxjs';
+import { map, takeUntil } from 'rxjs/operators';
+
+import { DataService } from '../../../data/providers/data.service';
+
+@Component({
+    selector: 'vdr-administrator-list',
+    templateUrl: './administrator-list.component.html',
+    styleUrls: ['./administrator-list.component.scss'],
+})
+export class AdministratorListComponent implements OnInit, OnDestroy {
+    administrators$: Observable<any[]>;
+    totalItems$: Observable<number>;
+    itemsPerPage$: Observable<number>;
+    currentPage$: Observable<number>;
+    private destroy$ = new Subject<void>();
+
+    constructor(private dataService: DataService, private router: Router, private route: ActivatedRoute) {}
+
+    ngOnInit() {
+        const administratorsQuery = this.dataService.administrator.getAdministrators(10, 0);
+
+        const fetchPage = ([currentPage, itemsPerPage]: [number, number]) => {
+            const take = itemsPerPage;
+            const skip = (currentPage - 1) * itemsPerPage;
+            administratorsQuery.ref.refetch({ options: { skip, take } });
+        };
+
+        this.administrators$ = administratorsQuery.stream$.pipe(map(data => data.administrators.items));
+        this.totalItems$ = administratorsQuery.stream$.pipe(map(data => data.administrators.totalItems));
+        this.currentPage$ = this.route.queryParamMap.pipe(
+            map(qpm => qpm.get('page')),
+            map(page => (!page ? 1 : +page)),
+        );
+        this.itemsPerPage$ = this.route.queryParamMap.pipe(
+            map(qpm => qpm.get('perPage')),
+            map(perPage => (!perPage ? 10 : +perPage)),
+        );
+
+        combineLatest(this.currentPage$, this.itemsPerPage$)
+            .pipe(takeUntil(this.destroy$))
+            .subscribe(fetchPage);
+    }
+
+    ngOnDestroy() {
+        this.destroy$.next();
+        this.destroy$.complete();
+    }
+
+    setPageNumber(page: number) {
+        this.setQueryParam('page', page);
+    }
+
+    setItemsPerPage(perPage: number) {
+        this.setQueryParam('perPage', perPage);
+    }
+
+    private setQueryParam(key: string, value: any) {
+        this.router.navigate(['./'], {
+            queryParams: { [key]: value },
+            relativeTo: this.route,
+            queryParamsHandling: 'merge',
+        });
+    }
+}

+ 4 - 0
admin-ui/src/app/app.routes.ts

@@ -23,6 +23,10 @@ export const routes: Route[] = [
                 path: 'catalog',
                 loadChildren: './catalog/catalog.module#CatalogModule',
             },
+            {
+                path: 'admin',
+                loadChildren: './administrator/administrator.module#AdministratorModule',
+            },
         ],
     },
 ];

+ 13 - 0
admin-ui/src/app/core/components/main-nav/main-nav.component.html

@@ -35,5 +35,18 @@
                 </li>
             </ul>
         </section>
+        <section class="nav-group">
+            <input id="tabexample2" type="checkbox">
+            <label for="tabexample2">{{ 'nav.administrator' | translate }}</label>
+            <ul class="nav-list">
+                <li>
+                    <a class="nav-link"
+                       [routerLink]="['/admin', 'administrators']"
+                       routerLinkActive="active">
+                        <clr-icon shape="administrator" size="20"></clr-icon>{{ 'nav.administrators' | translate }}
+                    </a>
+                </li>
+            </ul>
+        </section>
     </section>
 </nav>

+ 32 - 0
admin-ui/src/app/data/definitions/administrator-definitions.ts

@@ -0,0 +1,32 @@
+import gql from 'graphql-tag';
+
+export const ADMINISTRATOR_FRAGMENT = gql`
+    fragment Administrator on Administrator {
+        id
+        firstName
+        lastName
+        emailAddress
+        user {
+            id
+            identifier
+            lastLogin
+            roles {
+                code
+                description
+                permissions
+            }
+        }
+    }
+`;
+
+export const GET_ADMINISTRATORS = gql`
+    query GetAdministrators($options: AdministratorListOptions) {
+        administrators(options: $options) {
+            items {
+                ...Administrator
+            }
+            totalItems
+        }
+    }
+    ${ADMINISTRATOR_FRAGMENT}
+`;

+ 23 - 0
admin-ui/src/app/data/providers/administrator-data.service.ts

@@ -0,0 +1,23 @@
+import { GetAdministrators, GetAdministratorsVariables } from 'shared/generated-types';
+
+import { getDefaultLanguage } from '../../common/utilities/get-default-language';
+import { GET_ADMINISTRATORS } from '../definitions/administrator-definitions';
+import { QueryResult } from '../query-result';
+
+import { BaseDataService } from './base-data.service';
+
+export class AdministratorDataService {
+    constructor(private baseDataService: BaseDataService) {}
+
+    getAdministrators(
+        take: number = 10,
+        skip: number = 0,
+    ): QueryResult<GetAdministrators, GetAdministratorsVariables> {
+        return this.baseDataService.query<GetAdministrators, GetAdministratorsVariables>(GET_ADMINISTRATORS, {
+            options: {
+                take,
+                skip,
+            },
+        });
+    }
+}

+ 3 - 0
admin-ui/src/app/data/providers/data.service.mock.ts

@@ -30,6 +30,9 @@ export function spyObservable(name: string, returnValue: any = {}): jasmine.Spy
 }
 
 export class MockDataService implements DataServiceMock {
+    administrator = {
+        getAdministrators: spyQueryResult('getAdministrators'),
+    };
     client = {
         startRequest: spyObservable('startRequest'),
         completeRequest: spyObservable('completeRequest'),

+ 3 - 0
admin-ui/src/app/data/providers/data.service.ts

@@ -1,5 +1,6 @@
 import { Injectable } from '@angular/core';
 
+import { AdministratorDataService } from './administrator-data.service';
 import { AuthDataService } from './auth-data.service';
 import { BaseDataService } from './base-data.service';
 import { ClientDataService } from './client-data.service';
@@ -8,12 +9,14 @@ import { ProductDataService } from './product-data.service';
 
 @Injectable()
 export class DataService {
+    administrator: AdministratorDataService;
     auth: AuthDataService;
     product: ProductDataService;
     client: ClientDataService;
     facet: FacetDataService;
 
     constructor(baseDataService: BaseDataService) {
+        this.administrator = new AdministratorDataService(baseDataService);
         this.auth = new AuthDataService(baseDataService);
         this.product = new ProductDataService(baseDataService);
         this.client = new ClientDataService(baseDataService);

+ 1 - 0
admin-ui/src/polyfills.ts

@@ -78,6 +78,7 @@ import 'zone.js/dist/zone'; // Included with Angular CLI.
 import '@clr/icons';
 import '@clr/icons/shapes/commerce-shapes';
 import '@clr/icons/shapes/essential-shapes';
+import '@clr/icons/shapes/technology-shapes';
 import '@webcomponents/custom-elements/custom-elements.min.js';
 // TODO: remove this shim once the newer version of graphql-js is released (14.0.0)
 // and check that the codegen still works (may need to upgrade apollo package).

+ 273 - 173
shared/generated-types.ts

@@ -1,6 +1,51 @@
 /* tslint:disable */
 // This file was automatically generated and should not be edited.
 
+// ====================================================
+// GraphQL query operation: GetAdministrators
+// ====================================================
+
+export interface GetAdministrators_administrators_items_user_roles {
+  __typename: "Role";
+  code: string;
+  description: string;
+  permissions: string[];
+}
+
+export interface GetAdministrators_administrators_items_user {
+  __typename: "User";
+  id: string;
+  identifier: string;
+  lastLogin: string | null;
+  roles: GetAdministrators_administrators_items_user_roles[];
+}
+
+export interface GetAdministrators_administrators_items {
+  __typename: "Administrator";
+  id: string;
+  firstName: string | null;
+  lastName: string | null;
+  emailAddress: string | null;
+  user: GetAdministrators_administrators_items_user | null;
+}
+
+export interface GetAdministrators_administrators {
+  __typename: "AdministratorList";
+  items: GetAdministrators_administrators_items[];
+  totalItems: number;
+}
+
+export interface GetAdministrators {
+  administrators: GetAdministrators_administrators;
+}
+
+export interface GetAdministratorsVariables {
+  options?: AdministratorListOptions | null;
+}
+
+/* tslint:disable */
+// This file was automatically generated and should not be edited.
+
 // ====================================================
 // GraphQL mutation operation: AttemptLogin
 // ====================================================
@@ -31,6 +76,25 @@ export interface AttemptLoginVariables {
 /* tslint:disable */
 // This file was automatically generated and should not be edited.
 
+// ====================================================
+// GraphQL query operation: GetCurrentUser
+// ====================================================
+
+export interface GetCurrentUser_me {
+  __typename: "CurrentUser";
+  id: string;
+  identifier: string;
+  channelTokens: string[];
+  roles: string[];
+}
+
+export interface GetCurrentUser {
+  me: GetCurrentUser_me | null;
+}
+
+/* tslint:disable */
+// This file was automatically generated and should not be edited.
+
 // ====================================================
 // GraphQL mutation operation: CreateFacet
 // ====================================================
@@ -201,6 +265,110 @@ export interface UpdateFacetValuesVariables {
 /* tslint:disable */
 // This file was automatically generated and should not be edited.
 
+// ====================================================
+// GraphQL query operation: GetFacetList
+// ====================================================
+
+export interface GetFacetList_facets_items_translations {
+  __typename: "FacetTranslation";
+  id: string;
+  languageCode: LanguageCode;
+  name: string;
+}
+
+export interface GetFacetList_facets_items_values_translations {
+  __typename: "FacetValueTranslation";
+  id: string;
+  languageCode: LanguageCode;
+  name: string;
+}
+
+export interface GetFacetList_facets_items_values {
+  __typename: "FacetValue";
+  id: string;
+  languageCode: LanguageCode | null;
+  code: string;
+  name: string;
+  translations: GetFacetList_facets_items_values_translations[];
+}
+
+export interface GetFacetList_facets_items {
+  __typename: "Facet";
+  id: string;
+  languageCode: LanguageCode;
+  code: string;
+  name: string;
+  translations: GetFacetList_facets_items_translations[];
+  values: GetFacetList_facets_items_values[];
+}
+
+export interface GetFacetList_facets {
+  __typename: "FacetList";
+  items: GetFacetList_facets_items[];
+  totalItems: number;
+}
+
+export interface GetFacetList {
+  facets: GetFacetList_facets;
+}
+
+export interface GetFacetListVariables {
+  options?: FacetListOptions | null;
+  languageCode?: LanguageCode | null;
+}
+
+/* tslint:disable */
+// This file was automatically generated and should not be edited.
+
+// ====================================================
+// GraphQL query operation: GetFacetWithValues
+// ====================================================
+
+export interface GetFacetWithValues_facet_translations {
+  __typename: "FacetTranslation";
+  id: string;
+  languageCode: LanguageCode;
+  name: string;
+}
+
+export interface GetFacetWithValues_facet_values_translations {
+  __typename: "FacetValueTranslation";
+  id: string;
+  languageCode: LanguageCode;
+  name: string;
+}
+
+export interface GetFacetWithValues_facet_values {
+  __typename: "FacetValue";
+  id: string;
+  languageCode: LanguageCode | null;
+  code: string;
+  name: string;
+  translations: GetFacetWithValues_facet_values_translations[];
+}
+
+export interface GetFacetWithValues_facet {
+  __typename: "Facet";
+  id: string;
+  languageCode: LanguageCode;
+  code: string;
+  name: string;
+  translations: GetFacetWithValues_facet_translations[];
+  values: GetFacetWithValues_facet_values[];
+}
+
+export interface GetFacetWithValues {
+  facet: GetFacetWithValues_facet | null;
+}
+
+export interface GetFacetWithValuesVariables {
+  id: string;
+  languageCode?: LanguageCode | null;
+}
+
+/* tslint:disable */
+// This file was automatically generated and should not be edited.
+
 // ====================================================
 // GraphQL mutation operation: RequestStarted
 // ====================================================
@@ -279,6 +447,56 @@ export interface SetUiLanguageVariables {
 /* tslint:disable */
 // This file was automatically generated and should not be edited.
 
+// ====================================================
+// GraphQL query operation: GetNetworkStatus
+// ====================================================
+
+export interface GetNetworkStatus_networkStatus {
+  __typename: "NetworkStatus";
+  inFlightRequests: number;
+}
+
+export interface GetNetworkStatus {
+  networkStatus: GetNetworkStatus_networkStatus;
+}
+
+/* tslint:disable */
+// This file was automatically generated and should not be edited.
+
+// ====================================================
+// GraphQL query operation: GetUserStatus
+// ====================================================
+
+export interface GetUserStatus_userStatus {
+  __typename: "UserStatus";
+  username: string;
+  isLoggedIn: boolean;
+  loginTime: string;
+}
+
+export interface GetUserStatus {
+  userStatus: GetUserStatus_userStatus;
+}
+
+/* tslint:disable */
+// This file was automatically generated and should not be edited.
+
+// ====================================================
+// GraphQL query operation: GetUiState
+// ====================================================
+
+export interface GetUiState_uiState {
+  __typename: "UiState";
+  language: LanguageCode;
+}
+
+export interface GetUiState {
+  uiState: GetUiState_uiState;
+}
+
+/* tslint:disable */
+// This file was automatically generated and should not be edited.
+
 // ====================================================
 // GraphQL mutation operation: UpdateProduct
 // ====================================================
@@ -757,179 +975,6 @@ export interface ApplyFacetValuesToProductVariantsVariables {
 /* tslint:disable */
 // This file was automatically generated and should not be edited.
 
-// ====================================================
-// GraphQL query operation: GetCurrentUser
-// ====================================================
-
-export interface GetCurrentUser_me {
-  __typename: "CurrentUser";
-  id: string;
-  identifier: string;
-  channelTokens: string[];
-  roles: string[];
-}
-
-export interface GetCurrentUser {
-  me: GetCurrentUser_me | null;
-}
-
-/* tslint:disable */
-// This file was automatically generated and should not be edited.
-
-// ====================================================
-// GraphQL query operation: GetFacetList
-// ====================================================
-
-export interface GetFacetList_facets_items_translations {
-  __typename: "FacetTranslation";
-  id: string;
-  languageCode: LanguageCode;
-  name: string;
-}
-
-export interface GetFacetList_facets_items_values_translations {
-  __typename: "FacetValueTranslation";
-  id: string;
-  languageCode: LanguageCode;
-  name: string;
-}
-
-export interface GetFacetList_facets_items_values {
-  __typename: "FacetValue";
-  id: string;
-  languageCode: LanguageCode | null;
-  code: string;
-  name: string;
-  translations: GetFacetList_facets_items_values_translations[];
-}
-
-export interface GetFacetList_facets_items {
-  __typename: "Facet";
-  id: string;
-  languageCode: LanguageCode;
-  code: string;
-  name: string;
-  translations: GetFacetList_facets_items_translations[];
-  values: GetFacetList_facets_items_values[];
-}
-
-export interface GetFacetList_facets {
-  __typename: "FacetList";
-  items: GetFacetList_facets_items[];
-  totalItems: number;
-}
-
-export interface GetFacetList {
-  facets: GetFacetList_facets;
-}
-
-export interface GetFacetListVariables {
-  options?: FacetListOptions | null;
-  languageCode?: LanguageCode | null;
-}
-
-/* tslint:disable */
-// This file was automatically generated and should not be edited.
-
-// ====================================================
-// GraphQL query operation: GetFacetWithValues
-// ====================================================
-
-export interface GetFacetWithValues_facet_translations {
-  __typename: "FacetTranslation";
-  id: string;
-  languageCode: LanguageCode;
-  name: string;
-}
-
-export interface GetFacetWithValues_facet_values_translations {
-  __typename: "FacetValueTranslation";
-  id: string;
-  languageCode: LanguageCode;
-  name: string;
-}
-
-export interface GetFacetWithValues_facet_values {
-  __typename: "FacetValue";
-  id: string;
-  languageCode: LanguageCode | null;
-  code: string;
-  name: string;
-  translations: GetFacetWithValues_facet_values_translations[];
-}
-
-export interface GetFacetWithValues_facet {
-  __typename: "Facet";
-  id: string;
-  languageCode: LanguageCode;
-  code: string;
-  name: string;
-  translations: GetFacetWithValues_facet_translations[];
-  values: GetFacetWithValues_facet_values[];
-}
-
-export interface GetFacetWithValues {
-  facet: GetFacetWithValues_facet | null;
-}
-
-export interface GetFacetWithValuesVariables {
-  id: string;
-  languageCode?: LanguageCode | null;
-}
-
-/* tslint:disable */
-// This file was automatically generated and should not be edited.
-
-// ====================================================
-// GraphQL query operation: GetNetworkStatus
-// ====================================================
-
-export interface GetNetworkStatus_networkStatus {
-  __typename: "NetworkStatus";
-  inFlightRequests: number;
-}
-
-export interface GetNetworkStatus {
-  networkStatus: GetNetworkStatus_networkStatus;
-}
-
-/* tslint:disable */
-// This file was automatically generated and should not be edited.
-
-// ====================================================
-// GraphQL query operation: GetUserStatus
-// ====================================================
-
-export interface GetUserStatus_userStatus {
-  __typename: "UserStatus";
-  username: string;
-  isLoggedIn: boolean;
-  loginTime: string;
-}
-
-export interface GetUserStatus {
-  userStatus: GetUserStatus_userStatus;
-}
-
-/* tslint:disable */
-// This file was automatically generated and should not be edited.
-
-// ====================================================
-// GraphQL query operation: GetUiState
-// ====================================================
-
-export interface GetUiState_uiState {
-  __typename: "UiState";
-  language: LanguageCode;
-}
-
-export interface GetUiState {
-  uiState: GetUiState_uiState;
-}
-
-/* tslint:disable */
-// This file was automatically generated and should not be edited.
-
 // ====================================================
 // GraphQL query operation: GetProductWithVariants
 // ====================================================
@@ -1074,6 +1119,37 @@ export interface GetProductOptionGroupsVariables {
 /* tslint:disable */
 // This file was automatically generated and should not be edited.
 
+// ====================================================
+// GraphQL fragment: Administrator
+// ====================================================
+
+export interface Administrator_user_roles {
+  __typename: "Role";
+  code: string;
+  description: string;
+  permissions: string[];
+}
+
+export interface Administrator_user {
+  __typename: "User";
+  id: string;
+  identifier: string;
+  lastLogin: string | null;
+  roles: Administrator_user_roles[];
+}
+
+export interface Administrator {
+  __typename: "Administrator";
+  id: string;
+  firstName: string | null;
+  lastName: string | null;
+  emailAddress: string | null;
+  user: Administrator_user | null;
+}
+
+/* tslint:disable */
+// This file was automatically generated and should not be edited.
+
 // ====================================================
 // GraphQL fragment: CurrentUser
 // ====================================================
@@ -1500,6 +1576,30 @@ export enum SortOrder {
   DESC = "DESC",
 }
 
+export interface AdministratorFilterParameter {
+  firstName?: StringOperators | null;
+  lastName?: StringOperators | null;
+  emailAddress?: StringOperators | null;
+  createdAt?: DateOperators | null;
+  updatedAt?: DateOperators | null;
+}
+
+export interface AdministratorListOptions {
+  take?: number | null;
+  skip?: number | null;
+  sort?: AdministratorSortParameter | null;
+  filter?: AdministratorFilterParameter | null;
+}
+
+export interface AdministratorSortParameter {
+  id?: SortOrder | null;
+  createdAt?: SortOrder | null;
+  updatedAt?: SortOrder | null;
+  firstName?: SortOrder | null;
+  lastName?: SortOrder | null;
+  emailAddress?: SortOrder | null;
+}
+
 export interface BooleanOperators {
   eq?: boolean | null;
 }