LP#1775466 Date select / hard due date example
authorBill Erickson <berickxx@gmail.com>
Fri, 11 May 2018 22:16:51 +0000 (18:16 -0400)
committerBill Erickson <berickxx@gmail.com>
Wed, 6 Jun 2018 20:59:26 +0000 (16:59 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
15 files changed:
Open-ILS/src/eg2/src/app/share/date-select/date-select.component.html [new file with mode: 0644]
Open-ILS/src/eg2/src/app/share/date-select/date-select.component.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/share/fm-editor/fm-editor.component.html
Open-ILS/src/eg2/src/app/share/fm-editor/fm-editor.component.ts
Open-ILS/src/eg2/src/app/share/grid/grid-toolbar.component.html
Open-ILS/src/eg2/src/app/share/grid/grid.component.html
Open-ILS/src/eg2/src/app/share/grid/grid.component.ts
Open-ILS/src/eg2/src/app/staff/admin/server/config/billing_type.component.ts
Open-ILS/src/eg2/src/app/staff/admin/server/config/config.module.ts
Open-ILS/src/eg2/src/app/staff/admin/server/config/hard_due_date.component.html [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/admin/server/config/hard_due_date.component.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/admin/server/config/routing.module.ts
Open-ILS/src/eg2/src/app/staff/common.module.ts
Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html
Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts

diff --git a/Open-ILS/src/eg2/src/app/share/date-select/date-select.component.html b/Open-ILS/src/eg2/src/app/share/date-select/date-select.component.html
new file mode 100644 (file)
index 0000000..c686be4
--- /dev/null
@@ -0,0 +1,21 @@
+
+<div class="input-group">
+  <input 
+    class="form-control" 
+    ngbDatepicker
+    #datePicker="ngbDatepicker"
+    placeholder="yyyy-mm-dd"
+    class="form-control"
+    name="{{fieldName}}"
+    [required]="required"
+    [(ngModel)]="current"
+    (dateSelect)="onDateSelect($event)">
+  <div class="input-group-append">
+    <button class="btn btn-outline-secondary" 
+      (click)="datePicker.toggle()" type="button">
+      <span title="Select Date" i18n-title                       
+        class="material-icons mat-icon-in-button">calendar_today</span>
+    </button>
+  </div>
+</div>
+
diff --git a/Open-ILS/src/eg2/src/app/share/date-select/date-select.component.ts b/Open-ILS/src/eg2/src/app/share/date-select/date-select.component.ts
new file mode 100644 (file)
index 0000000..7cc188f
--- /dev/null
@@ -0,0 +1,65 @@
+import {Component, OnInit, Input, Output, ViewChild, EventEmitter} from '@angular/core';
+import {NgbDateStruct} from '@ng-bootstrap/ng-bootstrap';
+
+@Component({
+  selector: 'eg-date-select',
+  templateUrl: './date-select.component.html'
+})
+export class EgDateSelectComponent implements OnInit {
+
+    @Input() initialIso: string; // ISO string
+    @Input() initialYmd: string; // YYYY-MM-DD (uses local time zone)
+    @Input() initialDate: Date;  // Date object
+    @Input() required: boolean;
+    @Input() fieldName: string;
+
+    current: NgbDateStruct;
+
+    @Output() onChangeAsDate: EventEmitter<Date>;
+    @Output() onChangeAsIso: EventEmitter<string>;
+    @Output() onChangeAsYmd: EventEmitter<string>;
+
+    constructor() {
+        this.onChangeAsDate = new EventEmitter<Date>();
+        this.onChangeAsIso = new EventEmitter<string>();
+        this.onChangeAsYmd = new EventEmitter<string>();
+    }
+    
+    ngOnInit() {
+
+        if (this.initialYmd) {
+            this.initialDate = this.localDateFromYmd(this.initialYmd);
+
+        } else if (this.initialIso) {
+            this.initialDate = new Date(this.initialIso);
+        }
+
+        if (!this.initialDate)
+            this.initialDate = new Date();
+
+        this.current = {
+            year: this.initialDate.getFullYear(), 
+            month: this.initialDate.getMonth() + 1, 
+            day: this.initialDate.getDate()
+        };
+    }
+
+    onDateSelect(evt) {
+        let ymd = `${evt.year}-${evt.month}-${evt.day}`;
+        let date = this.localDateFromYmd(ymd);
+        let iso = date.toISOString();
+        this.onChangeAsDate.emit(date);
+        this.onChangeAsYmd.emit(ymd);
+        this.onChangeAsIso.emit(iso);
+    }
+
+    // Create a date in the local time zone with selected YMD values.
+    // TODO: Consider moving this to a date service...
+    localDateFromYmd(ymd: string): Date {
+        var parts = ymd.split('-');                                            
+        return new Date(
+            Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
+    }
+}
+
+
index 5b582db..3da8b1b 100644 (file)
               [required]="field.isRequired()"
               [ngModel]="record[field.name]()"
               (ngModelChange)="record[field.name]($event)"/>
-  
+
+            <span *ngIf="field.datatype == 'timestamp'">
+              <eg-date-select
+                (onChangeAsIso)="record[field.name]($event)"
+                initialIso="record[field.name]()">
+              </eg-date-select>
+            </span>
+
             <input *ngIf="field.datatype == 'int'"
               class="form-control"
               type="number"
index ea46953..3942bd5 100644 (file)
@@ -188,7 +188,8 @@ export class FmRecordEditorComponent
             if (field.datatype == 'bool') {
                 if (rec[field.name]() == true) {
                     rec[field.name]('t');
-                } else if (rec[field.name]() == false) {
+                //} else if (rec[field.name]() == false) {
+                } else { // TODO: some bools can be NULL
                     rec[field.name]('f');
                 }
             } else if (field.datatype == 'org_unit') {
index 9924e09..316c095 100644 (file)
@@ -1,5 +1,5 @@
 
-<div class="eg-grid-toolbar">
+<div class="eg-grid-toolbar mb-2">
 
   <div class="btn-toolbar" *ngIf="toolbarButtons.length">
     <div class="btn-grp">
index 52a58d4..8fb597a 100644 (file)
   </eg-grid-header>
   <eg-grid-column-width #colWidthConfig [columnSet]="columnSet"></eg-grid-column-width>
 
+  <div class="row" *ngIf="dataSource.data.length == 0">
+    <div class="col-lg-12 text-center alert alert-light font-italic" i18n>
+      Nothing to Display
+    </div>
+  </div>
+
   <div class="eg-grid-row eg-grid-body-row"
     [ngClass]="{'selected': rowSelector.contains(getRowIndex(row))}"
     *ngFor="let row of dataSource.getPageOfRows(pager); let idx = index">
index aa4ce60..031694f 100644 (file)
@@ -1,4 +1,4 @@
-import {Component, Input, OnInit, AfterViewInit, EventEmitter, OnDestroy
+import {Component, Input, OnInit, AfterViewInit, EventEmitter, OnDestroy,
     HostListener, ViewEncapsulation} from '@angular/core';
 import {Subscription} from "rxjs/Subscription";
 import {EgGridDataSource} from './grid-data-source';
@@ -28,7 +28,7 @@ export class EgGridComponent implements OnInit, AfterViewInit, OnDestroy {
     pager: Pager;
     columnSet: EgGridColumnSet;
     rowSelector: EgGridRowSelector;
-    onRowDblClick$: EventEmitter<any>;
+    onRowActivate$: EventEmitter<any>;
     onRowClick$: EventEmitter<any>;
     toolbarButtons: EgGridToolbarButton[];
     toolbarActions: EgGridToolbarAction[];
@@ -39,7 +39,7 @@ export class EgGridComponent implements OnInit, AfterViewInit, OnDestroy {
         this.pager = new Pager();
         this.rowSelector = new EgGridRowSelector();
         this.pager.limit = 10; // TODO config
-        this.onRowDblClick$ = new EventEmitter<any>();
+        this.onRowActivate$ = new EventEmitter<any>();
         this.onRowClick$ = new EventEmitter<any>();
         this.toolbarButtons = [];
         this.toolbarActions = [];
@@ -142,7 +142,7 @@ export class EgGridComponent implements OnInit, AfterViewInit, OnDestroy {
     }
 
     onRowDblClick(row: any) {
-        this.onRowDblClick$.emit(row);
+        this.onRowActivate$.emit(row);
     }
 
     onRowClick($event: any, row: any, idx: number) {
index 4f19a2c..fd6494f 100644 (file)
@@ -56,7 +56,7 @@ export class BillingTypeComponent implements OnInit {
             });
         }
 
-        this.btGrid.onRowDblClick$.subscribe(
+        this.btGrid.onRowActivate$.subscribe(
             bt => {
                 this.btEditDialog.mode = 'update';
                 this.btEditDialog.recId = bt.id();
@@ -76,7 +76,7 @@ export class BillingTypeComponent implements OnInit {
             this.btEditDialog.open().then(
                 ok => {
                     this.createString.current()
-                    .then(str => this.toast.success(str));
+                        .then(str => this.toast.success(str));
                     this.btGrid.reload();
                 },
                 err => { }
index 6bca1db..dcc6ef0 100644 (file)
@@ -3,10 +3,12 @@ import {EgStaffCommonModule} from '@eg/staff/common.module';
 import {EgAdminServerConfigRoutingModule} from './routing.module';
 import {EgGridModule} from '@eg/share/grid/grid.module';
 import {BillingTypeComponent} from './billing_type.component';
+import {HardDueDateComponent} from './hard_due_date.component';
 
 @NgModule({
   declarations: [
-      BillingTypeComponent
+      BillingTypeComponent,
+      HardDueDateComponent
   ],
   imports: [
     EgStaffCommonModule,
diff --git a/Open-ILS/src/eg2/src/app/staff/admin/server/config/hard_due_date.component.html b/Open-ILS/src/eg2/src/app/staff/admin/server/config/hard_due_date.component.html
new file mode 100644 (file)
index 0000000..4b31604
--- /dev/null
@@ -0,0 +1,35 @@
+<eg-staff-banner bannerText="Hard Due Date Configuration" i18n-bannerText>
+</eg-staff-banner>
+
+<div class="row">
+  <div class="input-group">
+    <div class="input-group-prepend">
+      <span class="input-group-text" i18n>Owning Library</span>
+    </div>
+    <eg-org-select 
+      [initialOrg]="contextOrg"
+      (onChange)="orgOnChange($event)">
+    </eg-org-select>
+  </div>
+</div>
+
+<hr/>
+
+<eg-grid #hddGrid idlClass="chdd" [dataSource]="dataSource" 
+    [isSortable]="true" persistKey="admin.server.config.hard_due_date">
+  <eg-grid-toolbar-button label="New Hard Due Date" i18n-label [action]="createHardDueDate">
+  </eg-grid-toolbar-button>
+  <eg-grid-toolbar-action label="Delete Selected" i18n-label [action]="deleteSelected">
+  </eg-grid-toolbar-action>
+</eg-grid>
+
+<fm-record-editor #hddEditDialog idlClass="chdd" requiredFields="name,org_unit">
+</fm-record-editor>
+
+<ng-template #successStrTmpl i18n>Hard Due Date Update Succeeded</ng-template>
+<eg-string #successString [template]="successStrTmpl"></eg-string>
+
+<ng-template #createStrTmpl i18n>Hard Due Date Succeessfully Created</ng-template>
+<eg-string #createString [template]="createStrTmpl"></eg-string>
+
+
diff --git a/Open-ILS/src/eg2/src/app/staff/admin/server/config/hard_due_date.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/server/config/hard_due_date.component.ts
new file mode 100644 (file)
index 0000000..89945b7
--- /dev/null
@@ -0,0 +1,97 @@
+import {Component, OnInit, TemplateRef, ViewChild} from '@angular/core';
+import {EgIdlObject} from '@eg/core/idl.service';
+import {EgGridDataSource} from '@eg/share/grid/grid-data-source';
+import {EgGridComponent} from '@eg/share/grid/grid.component';
+import {EgToastService} from '@eg/share/toast/toast.service';
+import {Pager} from '@eg/share/util/pager';
+import {EgPcrudService} from '@eg/core/pcrud.service';
+import {EgOrgService} from '@eg/core/org.service';
+import {EgAuthService} from '@eg/core/auth.service';
+import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
+import {EgStringComponent} from '@eg/share/string/string.component';
+
+@Component({
+    templateUrl: './hard_due_date.component.html'
+})
+
+export class HardDueDateComponent implements OnInit {
+
+    dataSource: EgGridDataSource;
+    @ViewChild('hddGrid') hddGrid: EgGridComponent;
+    @ViewChild('hddEditDialog') hddEditDialog: FmRecordEditorComponent;
+    @ViewChild('successString') successString: EgStringComponent;
+    @ViewChild('createString') createString: EgStringComponent;
+    contextOrg: EgIdlObject;
+    createHardDueDate: () => void;
+    deleteSelected: (rows: any) => void;
+
+    constructor(
+        private org: EgOrgService,
+        private auth: EgAuthService,
+        private pcrud: EgPcrudService,
+        private toast: EgToastService
+    ) {
+        this.dataSource = new EgGridDataSource();
+    }
+
+    orgOnChange(org: EgIdlObject) {
+        this.contextOrg = org;
+        this.hddGrid.reload();
+    }
+
+    ngOnInit() {
+        this.contextOrg = this.org.get(this.auth.user().ws_ou());
+
+        this.dataSource.getRows = (pager: Pager, sort: any[]) => {
+            let searchOrgs = this.org.fullPath(this.contextOrg, true);
+
+            let orderBy = {};
+            if (sort.length) 
+                orderBy = {chdd: sort[0].name + ' ' + sort[0].dir};
+
+            return this.pcrud.search('chdd', {owner : searchOrgs}, {
+                offset: pager.offset, 
+                limit: pager.limit,
+                order_by: orderBy
+            });
+        }
+
+        this.hddGrid.onRowActivate$.subscribe(
+            bt => {
+                this.hddEditDialog.mode = 'update';
+                this.hddEditDialog.recId = bt.id();
+                this.hddEditDialog.open().then(
+                    ok => {
+                        this.successString.current()
+                            .then(str => this.toast.success(str));
+                        this.hddGrid.reload();
+                    },
+                    err => { }
+                );
+            }
+        );
+
+        this.createHardDueDate = () => {
+            this.hddEditDialog.mode = 'create';
+            this.hddEditDialog.open().then(
+                ok => {
+                    this.createString.current()
+                        .then(str => this.toast.success(str));
+                    this.hddGrid.reload();
+                },
+                err => { }
+            );
+        }
+
+        this.deleteSelected = (hardDueDates) => {
+            hardDueDates.forEach(hdd => hdd.isdeleted(true));
+            this.pcrud.autoApply(hardDueDates).subscribe(
+                val => console.debug('deleted: ' + val),
+                err => {},
+                ()  => this.hddGrid.reload()
+            );
+        }
+    }
+}
+
+
index f8717f4..d79bb9a 100644 (file)
@@ -1,10 +1,14 @@
 import {NgModule}             from '@angular/core';
 import {RouterModule, Routes} from '@angular/router';
 import {BillingTypeComponent} from './billing_type.component';
+import {HardDueDateComponent} from './hard_due_date.component';
 
 const routes: Routes = [{ 
   path: 'billing_type',
   component: BillingTypeComponent 
+}, {
+  path: 'hard_due_date',
+  component: HardDueDateComponent 
 }];
 
 @NgModule({
index e269966..4347c64 100644 (file)
@@ -15,6 +15,7 @@ import {EgToastComponent} from '@eg/share/toast/toast.component';
 import {EgStringComponent} from '@eg/share/string/string.component';
 import {EgStringService} from '@eg/share/string/string.service';
 import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
+import {EgDateSelectComponent} from '@eg/share/date-select/date-select.component';
 
 /**
  * Imports the EG common modules and adds modules common to all staff UI's.
@@ -33,7 +34,8 @@ import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
     EgToastComponent,
     EgStringComponent,
     EgOpChangeComponent,
-    FmRecordEditorComponent
+    FmRecordEditorComponent,
+    EgDateSelectComponent
   ],
   imports: [
     EgCommonModule
@@ -51,7 +53,8 @@ import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
     EgToastComponent,
     EgStringComponent,
     EgOpChangeComponent,
-    FmRecordEditorComponent
+    FmRecordEditorComponent,
+    EgDateSelectComponent
   ]
 })
 
index f2ae275..fedfd06 100644 (file)
     <button class="btn btn-success" (click)="testStrings()">Test Strings</button>
 </div>
 
+<div class="row">
+  <div class="form-group">
+    <eg-date-select (onChangeAsDate)="changeDate($event)"
+        initialYmd="2017-03-04">
+    </eg-date-select>
+  </div>
+  <div>HERE: {{testDate}}</div>
+</div>
+
 
 <!-- grid stuff -->
 
index 78d2263..fe35949 100644 (file)
@@ -7,6 +7,7 @@ import {EgGridDataSource} from '@eg/share/grid/grid-data-source';
 import {EgIdlService, EgIdlObject} from '@eg/core/idl.service';
 import {EgPcrudService} from '@eg/core/pcrud.service';
 import {Pager} from '@eg/share/util/pager';
+import {EgDateSelectComponent} from '@eg/share/date-select/date-select.component';
 
 @Component({
   templateUrl: 'sandbox.component.html'
@@ -16,12 +17,17 @@ export class EgSandboxComponent implements OnInit {
     @ViewChild('progressDialog')
     private progressDialog: EgProgressDialogComponent;
 
+    @ViewChild('dateSelect')
+    private dateSelector: EgDateSelectComponent;
+
     //@ViewChild('helloStr') private helloStr: EgStringComponent;
 
     gridDataSource: EgGridDataSource = new EgGridDataSource();
 
     btSource: EgGridDataSource = new EgGridDataSource();
 
+    testDate: any;
+
     testStr: string;
     @Input() set testString(str: string) {
         this.testStr = str;
@@ -53,6 +59,11 @@ export class EgSandboxComponent implements OnInit {
         }
     }
 
+    changeDate(date) {
+        console.log('HERE WITH ' + date);
+        this.testDate = date;
+    }
+
     showProgress() {
         this.progressDialog.open();