LP#1775466 grid columns config
authorBill Erickson <berickxx@gmail.com>
Thu, 3 May 2018 19:41:25 +0000 (15:41 -0400)
committerBill Erickson <berickxx@gmail.com>
Wed, 6 Jun 2018 20:59:25 +0000 (16:59 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
13 files changed:
Open-ILS/src/eg2/src/app/core/auth.service.ts
Open-ILS/src/eg2/src/app/share/grid/grid-column-config.component.html [new file with mode: 0644]
Open-ILS/src/eg2/src/app/share/grid/grid-column-config.component.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/share/grid/grid-header.component.html
Open-ILS/src/eg2/src/app/share/grid/grid-header.component.ts
Open-ILS/src/eg2/src/app/share/grid/grid-toolbar-button.component.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/share/grid/grid-toolbar.component.html
Open-ILS/src/eg2/src/app/share/grid/grid-toolbar.component.ts
Open-ILS/src/eg2/src/app/share/grid/grid.component.css
Open-ILS/src/eg2/src/app/share/grid/grid.component.html
Open-ILS/src/eg2/src/app/share/grid/grid.module.ts
Open-ILS/src/eg2/src/app/share/grid/grid.service.ts
Open-ILS/src/eg2/src/styles.css

index 84de51a..958e176 100644 (file)
@@ -214,6 +214,8 @@ export class EgAuthService {
         // to expire on the server.
         let pollTime = this.authtime() * 1000 + 5000;
 
+        console.debug('polling with timeout ' + pollTime);
+
         this.pollTimeout = setTimeout(() => {
             this.net.request(
                 'open-ils.auth',
@@ -224,7 +226,10 @@ export class EgAuthService {
 
             // EgNetService intercepts NO_SESSION events.
             // If the promise resolves, the session is valid.
-            ).toPromise().then(user => this.sessionPoll())
+            ).subscribe(
+                user => this.sessionPoll(),
+                err  => console.warn('auth poll error: ' + err)
+            );
 
         }, pollTime);
     }
diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid-column-config.component.html b/Open-ILS/src/eg2/src/app/share/grid/grid-column-config.component.html
new file mode 100644 (file)
index 0000000..3589461
--- /dev/null
@@ -0,0 +1,72 @@
+<ng-template #dialogContent>
+  <div class="modal-header bg-info">
+    <h4 class="modal-title" i18n>Grid Columns Configuration</h4>
+    <button type="button" class="close" 
+      i18n-aria-label aria-label="Close" 
+      (click)="dismiss('cross_click')">
+      <span aria-hidden="true">&times;</span>
+    </button>
+  </div>
+  <div class="modal-body eg-grid-column-config-dialog">
+
+    <div class="row">
+      <div class="col-lg-1 eg-grid-header-cell">Visible</div>
+      <div class="col-lg-3 eg-grid-header-cell">Column Name</div>
+      <div class="col-lg-1 eg-grid-header-cell">Move Up</div>
+      <div class="col-lg-1 eg-grid-header-cell">Move Down</div>
+      <div class="col-lg-1 eg-grid-header-cell">First Visible</div>
+      <div class="col-lg-1 eg-grid-header-cell">Last Visible</div>
+      <div class="col-lg-1 eg-grid-header-cell" *ngIf="!disableMultiSort">Sort Priority</div>
+      <div class="col-lg-3 eg-grid-header-cell">
+        <button class="btn btn-info" ng-click="elevateVisible()">
+          Visible Columns To Top
+        </button>
+      </div>
+    </div>
+    <div class="row" *ngFor="let col of columnSet.columns"
+      [ngClass]="{visible : !col.visible}">
+      <div class="col-lg-1" (click)="col.hidden=!col.hidden">
+        <span *ngIf="!col.hidden" class="badge badge-success">&#x2713;</span>
+        <span *ngIf="col.hidden" class="badge badge-warning">&#x2717;</span>
+      </div>
+      <div class="col-lg-3" (click)="col.hidden=!col.hidden">{{col.label}}</div>
+    <!--
+      <div class="col-lg-1">
+        <a href title="[% l('Move column up') %]"
+          ng-click="modifyColumnPos(col, -1)">
+          <span class="glyphicon glyphicon-arrow-up"></span>
+        </a>
+      </div>
+      <div class="col-lg-1">
+        <a href title="[% l('Move column down') %]"
+          ng-click="modifyColumnPos(col, 1)">
+          <span class="glyphicon glyphicon-arrow-down"></span>
+        </a>
+      </div>
+      <div class="col-lg-1">
+        <a href title="[% l('Make first visible') %]"
+          ng-click="modifyColumnPos(col, -10000)">
+          <span class="glyphicon glyphicon-open"></span>
+        </a>
+      </div>
+      <div class="col-lg-1">
+        <a href title="[% l('Make last visible') %]"
+          ng-click="modifyColumnPos(col, 10000)">
+          <span class="glyphicon glyphicon-save"></span>
+        </a>
+      </div>
+      <div class="col-lg-1" ng-if="!disableMultiSort">
+        <div ng-if="col.multisortable">
+          <input type='number' ng-model="col.sort"
+            title="[% l('Sort Priority / Direction') %]" style='width:2.3em'/>
+        </div>
+      </div>
+    -->
+
+    </div>
+  </div>
+  <div class="modal-footer">
+    <button type="button" class="btn btn-success" 
+      (click)="close('confirmed')" i18n>Close</button>
+  </div>
+</ng-template>
diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid-column-config.component.ts b/Open-ILS/src/eg2/src/app/share/grid/grid-column-config.component.ts
new file mode 100644 (file)
index 0000000..80795b1
--- /dev/null
@@ -0,0 +1,17 @@
+import {Component, Input, ViewChild, TemplateRef} from '@angular/core';
+import {EgDialogComponent} from '@eg/share/dialog/dialog.component';
+import {EgGridService, EgGridColumn, EgGridColumnSet} from './grid.service';
+
+@Component({
+  selector: 'eg-grid-column-config',
+  templateUrl: './grid-column-config.component.html'
+})
+
+/**
+ */
+export class EgGridColumnConfigComponent extends EgDialogComponent {
+    @Input() columnSet: EgGridColumnSet;
+
+}
+
+
index dc4176b..d2e419a 100644 (file)
@@ -6,9 +6,15 @@
   <div class="eg-grid-cell eg-grid-header-cell eg-grid-number-cell eg-grid-cell-skinny">
     <span i18n="number|Row Number Header">#</span>
   </div>
-    <div *ngFor="let col of columnSet.displayColumns()" 
-      class="eg-grid-cell eg-grid-header-cell" [ngStyle]="{flex:col.flex}">
-      {{col.label}}
-    </div>
+  <div *ngFor="let col of columnSet.displayColumns()" 
+    draggable="true" 
+    (dragstart)="dragColumn = col"
+    (drop)="onColumnDrop(col)"
+    (dragover)="onColumnDragEnter($event, col)"
+    (dragleave)="onColumnDragLeave($event, col)"
+    [ngClass]="{'eg-grid-header-cell dragover' : col.isDragTarget}"
+    class="eg-grid-cell eg-grid-header-cell" [ngStyle]="{flex:col.flex}">
+    {{col.label}}
+  </div>
 </div>
 
index 254c538..aaadba3 100644 (file)
@@ -1,4 +1,4 @@
-import {Component, Input, OnInit} from '@angular/core';
+import {Component, Input, OnInit, HostListener} from '@angular/core';
 import {EgGridService, EgGridColumn, EgGridColumnSet} from './grid.service';
 
 @Component({
@@ -10,10 +10,27 @@ export class EgGridHeaderComponent implements OnInit {
 
     @Input() columnSet: EgGridColumnSet;
     @Input() selected: {[idx:number] : boolean};
+    dragColumn: EgGridColumn;
 
     constructor(private gridSvc: EgGridService) { }
 
     ngOnInit() {
     }
+
+    onColumnDragEnter($event: any, col: any) {
+        if (this.dragColumn && this.dragColumn.name != col.name)
+            col.isDragTarget = true;
+        $event.preventDefault();
+    }
+
+    onColumnDragLeave($event: any, col: any) {
+        col.isDragTarget = false;
+        $event.preventDefault();
+    }
+
+    onColumnDrop(col: EgGridColumn) {
+        this.columnSet.insertBefore(this.dragColumn, col);
+        this.columnSet.columns.forEach(c => c.isDragTarget = false);
+    }
 }
 
diff --git a/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar-button.component.ts b/Open-ILS/src/eg2/src/app/share/grid/grid-toolbar-button.component.ts
new file mode 100644 (file)
index 0000000..c353fc9
--- /dev/null
@@ -0,0 +1,36 @@
+import {Component, Input, OnInit, Host, TemplateRef} from '@angular/core';
+import {EgGridService, EgGridToolbarButton} from './grid.service';
+import {EgGridComponent} from './grid.component';
+
+@Component({
+  selector: 'eg-grid-toolbar-button',
+  template: '<ng-template></ng-template>'
+})
+
+export class EgGridToolbarButtonComponent implements OnInit {
+
+    // Note most input fields should match class fields for EgGridColumn
+    @Input() label: string;
+    @Input() action: () => any;
+
+    // get a reference to our container grid.
+    constructor(
+        private gridSvc: EgGridService,
+        @Host() private grid: EgGridComponent) {
+    }
+
+    ngOnInit() {
+
+        if (!this.grid) {
+            console.warn('EgGridToolbarButtonComponent needs a [grid]');
+            return;
+        }
+
+        let btn = new EgGridToolbarButton();
+        btn.label = this.label;
+        btn.action = this.action;
+
+        this.grid.toolbarButtons.push(btn);
+    }
+}
+
index 77f38c2..a73f0b9 100644 (file)
     </div>
   </div>
 
+  <eg-grid-column-config #columnConfDialog [columnSet]="columnSet">
+  </eg-grid-column-config>
+  <div ngbDropdown class="ml-1" placement="bottom-right">
+    <button ngbDropdownToggle class="btn btn-light no-dropdown-caret">
+      <span title="Show Grid Options" i18n-title class="material-icons">arrow_drop_down</span>
+    </button>
+    <div class="dropdown-menu" ngbDropdownMenu>
+      <a class="dropdown-item" (click)="columnConfDialog.open({size:'lg'})">
+        <span class="material-icons">build</span>
+        <span i18n>Manage Columns</span>
+      </a>
+    </div>
+  </div>
+
 <div>
 
+
+
index 5920d97..5f1f828 100644 (file)
@@ -3,6 +3,7 @@ import {EgGridDataSource} from './grid-data-source';
 import {Pager} from '@eg/share/util/pager';
 import {EgGridService, EgGridColumn, EgGridColumnSet, EgGridToolbarButton} 
   from '@eg/share/grid/grid.service';
+import {EgDialogComponent} from '@eg/share/dialog/dialog.component';
 
 @Component({
   selector: 'eg-grid-toolbar',
@@ -14,6 +15,7 @@ export class EgGridToolbarComponent implements OnInit {
     @Input() dataSource: EgGridDataSource;
     @Input() pager: Pager;
     @Input() toolbarButtons: EgGridToolbarButton[];
+    @Input() columnSet: EgGridColumnSet;
 
     ngOnInit() {
 
index 8969cb1..8e41b2b 100644 (file)
     font-weight: bold;
 }
 
+.eg-grid-header-cell.dragover {
+    background-color: #cce5ff;
+    border-color: #b8daff;
+}
+
 .eg-grid-cell {
     flex: 1; /* applied per column */
     padding: 6px;
   flex: none;
 }
 
+.eg-grid-column-config-dialog.visible {
+  color: #000;
+  background-color: rgb(201, 221, 225);
+  border-bottom: 1px solid #888;
+}
+
 
index 60a48fc..ad655cb 100644 (file)
@@ -1,7 +1,7 @@
 
 <div class="eg-grid">
   <eg-grid-toolbar [dataSource]="dataSource" [pager]="pager" 
-    [toolbarButtons]="toolbarButtons"></eg-grid-toolbar>
+    [toolbarButtons]="toolbarButtons" [columnSet]="columnSet"></eg-grid-toolbar>
   <eg-grid-header [columnSet]="columnSet"></eg-grid-header>
 
   <div class="eg-grid-row eg-grid-body-row"
index cbba8dd..bd36327 100644 (file)
@@ -1,12 +1,14 @@
 import {NgModule} from '@angular/core';
-import {CommonModule} from '@angular/common';
-import {FormsModule} from '@angular/forms';
+import {EgCommonModule} from '@eg/common.module';
+//import {EgDialogComponent} from '@eg/share/dialog/dialog.component';
 import {EgGridComponent} from './grid.component';
 import {EgGridColumnComponent} from './grid-column.component';
 import {EgGridHeaderComponent} from './grid-header.component';
 import {EgGridToolbarComponent} from './grid-toolbar.component';
 import {EgGridService} from './grid.service';
 import {EgGridToolbarButtonComponent} from './grid-toolbar-button.component';
+import {EgGridColumnConfigComponent} from './grid-column-config.component';
+
 
 @NgModule({
     declarations: [
@@ -15,11 +17,11 @@ import {EgGridToolbarButtonComponent} from './grid-toolbar-button.component';
         EgGridColumnComponent,
         EgGridHeaderComponent,
         EgGridToolbarComponent,
-        EgGridToolbarButtonComponent
+        EgGridToolbarButtonComponent,
+        EgGridColumnConfigComponent
     ],
     imports: [
-        CommonModule,
-        FormsModule
+        EgCommonModule
     ],
     exports: [
         // public components
index 2bab414..6b10fc0 100644 (file)
@@ -80,6 +80,7 @@ export class EgGridColumn {
     idlFieldDef: any;
     cellTemplate: TemplateRef<any>;
     isPkey: boolean;
+    isDragTarget: boolean;
 }
 
 
@@ -103,6 +104,22 @@ export class EgGridColumnSet {
     displayColumns(): EgGridColumn[] {
         return this.columns.filter(c => !c.hidden);
     }
+
+    insertBefore(source: EgGridColumn, target: EgGridColumn) {
+        let targetIdx = 0;
+        let sourceIdx = 0;
+        this.columns.forEach((col, idx) => {
+            if (col.name == target.name) targetIdx = idx; });
+
+        this.columns.forEach((col, idx) => {
+            if (col.name == source.name) sourceIdx = idx; });
+
+        if (sourceIdx)
+            this.columns.splice(sourceIdx, 1);
+
+        this.columns.splice(targetIdx, 0, source);
+    }
+
 }
 
 export class EgGridToolbarButton {
index 9db4fe8..fef7747 100644 (file)
@@ -61,6 +61,11 @@ h5 {font-size: .95rem}
     align-items: center;
 }
 
+/* dropdown menu link/button with no downward carrot icon */
+.no-dropdown-caret::after {
+    display: none;
+}
+
 /* Default .card padding is extreme */
 .tight-card .card-body,
 .tight-card .list-group-item {