LP1847800 Admin page builds config_field links WIP user/berick/lp1847800-secondary-admin-pages
authorBill Erickson <berickxx@gmail.com>
Wed, 29 Apr 2020 21:27:23 +0000 (17:27 -0400)
committerBill Erickson <berickxx@gmail.com>
Wed, 29 Apr 2020 21:27:30 +0000 (17:27 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/staff/admin/basic-admin-page.component.ts
Open-ILS/src/eg2/src/app/staff/share/admin-page/admin-page.component.html
Open-ILS/src/eg2/src/app/staff/share/admin-page/admin-page.component.ts

index ceed287..1c9b4c8 100644 (file)
@@ -13,6 +13,7 @@ import {IdlService} from '@eg/core/idl.service';
       <eg-staff-banner bannerText="{{classLabel}} Configuration" i18n-bannerText>
       </eg-staff-banner>
       <eg-admin-page persistKeyPfx="{{persistKeyPfx}}" idlClass="{{idlClass}}"
+        configLinkBasePath="{{configLinkBasePath}}"
         readonlyFields="{{readonlyFields}}"
         [disableOrgFilter]="disableOrgFilter"></eg-admin-page>
     `
@@ -24,6 +25,7 @@ export class BasicAdminPageComponent implements OnInit {
     classLabel: string;
     persistKeyPfx: string;
     readonlyFields = '';
+    configLinkBasePath = '/staff/admin';
 
     // Tell the admin page to disable and hide the automagic org unit filter
     disableOrgFilter: boolean;
@@ -59,6 +61,8 @@ export class BasicAdminPageComponent implements OnInit {
             // ACQ is a special case, because unlike 'server', 'local',
             // 'workstation', the schema ('acq') is the root of the path.
             this.persistKeyPfx = '';
+        } else {
+            this.configLinkBasePath += '/' + this.persistKeyPfx;
         }
 
         // Pass the readonlyFields param if available
index e0ae6c3..bde59fd 100644 (file)
   <ng-container *ngTemplateOutlet="helpTemplate"></ng-container>
 </ng-container>
 
+<ng-template #configFieldLink let-row="row" let-col="col">
+  <a i18n-title title="Link To {{col.label}}"
+     [routerLink]="configFieldRouteLink(row, col)" 
+     [queryParams]="configFieldRouteParams(row, col)">{{col.label}}</a>
+</ng-template>
+
 <eg-grid #grid idlClass="{{idlClass}}" [dataSource]="dataSource" hideFields="{{hideGridFields}}"
     [sortable]="true" persistKey="{{persistKey}}">
   <eg-grid-toolbar-button [disabled]="!canCreate" 
   </eg-grid-toolbar-action>
   <eg-grid-toolbar-action label="Delete Selected" i18n-label (onClick)="deleteSelected($event)">
   </eg-grid-toolbar-action>
+  <ng-container *ngFor="let cf of configFields">
+    <eg-grid-column name="{{cf.name}}" [cellTemplate]="configFieldLink">
+    </eg-grid-column>
+  </ng-container>
 </eg-grid>
 
 <eg-fm-record-editor #editDialog idlClass="{{idlClass}}" 
index 6dd7632..d815680 100644 (file)
@@ -1,7 +1,7 @@
 import {Component, Input, OnInit, TemplateRef, ViewChild} from '@angular/core';
 import {ActivatedRoute} from '@angular/router';
 import {IdlService, IdlObject} from '@eg/core/idl.service';
-import {GridDataSource} from '@eg/share/grid/grid';
+import {GridDataSource, GridColumn} from '@eg/share/grid/grid';
 import {GridComponent} from '@eg/share/grid/grid.component';
 import {TranslateComponent} from '@eg/share/translate/translate.component';
 import {ToastService} from '@eg/share/toast/toast.service';
@@ -83,6 +83,9 @@ export class AdminPageComponent implements OnInit {
     // Override default values for fm-editor
     @Input() defaultNewRecord: IdlObject;
 
+    // Used as the first part of the routerLink path when creating
+    // links to related tables via configField's.
+    @Input() configLinkBasePath: string;
 
     @ViewChild('grid', { static: true }) grid: GridComponent;
     @ViewChild('editDialog', { static: true }) editDialog: FmRecordEditorComponent;
@@ -96,7 +99,7 @@ export class AdminPageComponent implements OnInit {
 
     idlClassDef: any;
     pkeyField: string;
-    configFields: string[];
+    configFields: any[]; // IDL field definitions
 
     // True if any columns on the object support translations
     translateRowIdx: number;
@@ -152,6 +155,7 @@ export class AdminPageComponent implements OnInit {
     }
 
     ngOnInit() {
+
         this.idlClassDef = this.idl.classes[this.idlClass];
         this.pkeyField = this.idlClassDef.pkey || 'id';
 
@@ -244,7 +248,10 @@ export class AdminPageComponent implements OnInit {
 
             const search: any = {};
 
-            search[this.orgField] = this.searchOrgs.orgIds || [this.contextOrg.id()];
+            if (this.orgField) {
+                search[this.orgField] =
+                    this.searchOrgs.orgIds || [this.contextOrg.id()];
+            }
 
             if (this.gridFilters) {
                 // Lay the URL grid filters over our search object.
@@ -370,6 +377,38 @@ export class AdminPageComponent implements OnInit {
 
         this.translator.open({size: 'lg'});
     }
+
+    // Construct a routerLink path for a configField.
+    configFieldRouteLink(row: any, col: GridColumn): string {
+        const cf = this.configFields.filter(field => field.name === col.name)[0];
+        const linkClass = this.idl.classes[cf['class']];
+        const pathParts = linkClass.table.split(/\./); // schema.tablename
+        return `${this.configLinkBasePath}/${pathParts[0]}/${pathParts[1]}`;
+    }
+
+    // Compiles a gridFilter value used when navigating to a linked
+    // class via configField.  The filter ensures the linked page
+    // only shows rows which refer back to the object from which the
+    // link was clicked.
+    configFieldRouteParams(row: any, col: GridColumn): any {
+        const cf = this.configFields.filter(field => field.name === col.name)[0];
+        const linkClass = this.idl.classes[cf['class']];
+
+        // cf.key is the name of the field on the linked object that
+        // refers back to this object.
+
+        // The field definition on the linked class for the cf.key
+        // field has its own key, which refers to the name of the field on the
+        // on this object which provides the other end of the link between
+        // the two objects.  This is typically the primary key field,
+        // but not necessarily.
+        const localField = linkClass.field_map[cf.key].key || this.pkeyField;
+
+        const filter: any = {};
+        filter[cf.key] = row[localField]();
+
+        return {gridFilters : JSON.stringify(filter)};
+    }
 }