LP#1849212 Course List Ui
authorZavier Banks <zbanks@catalyte.io>
Thu, 24 Oct 2019 18:26:40 +0000 (18:26 +0000)
committerGalen Charlton <gmc@equinoxinitiative.org>
Mon, 14 Sep 2020 22:16:03 +0000 (18:16 -0400)
Added a grid component that displays the available data, specified
by the class, while also modifying the routing, so the admin splash
page links to the created component.

Signed-off-by: Zavier Banks <zbanks@catalyte.io>
Signed-off-by: Jane Sandberg <sandbej@linnbenton.edu>
Signed-off-by: Michele Morgan <mmorgan@noblenet.org>
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>
Open-ILS/src/eg2/src/app/staff/admin/server/admin-server-splash.component.html
Open-ILS/src/eg2/src/app/staff/admin/server/course-reserves/course-list.component.html [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/admin/server/course-reserves/course-list.component.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/admin/server/course-reserves/course-reserves.module.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/admin/server/course-reserves/routing.module.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/admin/server/routing.module.ts

index de399d6..df5b9ef 100644 (file)
@@ -39,6 +39,8 @@
       routerLink="/staff/admin/server/config/circ_modifier"></eg-link-table-link>
     <eg-link-table-link i18n-label label="Circulation Recurring Fine Rules"  
       routerLink="/staff/admin/server/config/rule_recurring_fine"></eg-link-table-link>
+    <eg-link-table-link i18n-label label="Course Reserves List"  
+      routerLink="/staff/admin/server/asset/course_list"></eg-link-table-link>
     <eg-link-table-link i18n-label label="Custom Org Unit Trees"  
       url="/eg/staff/admin/server/actor/org_unit_custom_tree"></eg-link-table-link>
     <eg-link-table-link i18n-label label="Floating Groups"  
diff --git a/Open-ILS/src/eg2/src/app/staff/admin/server/course-reserves/course-list.component.html b/Open-ILS/src/eg2/src/app/staff/admin/server/course-reserves/course-list.component.html
new file mode 100644 (file)
index 0000000..471a94e
--- /dev/null
@@ -0,0 +1,30 @@
+<eg-staff-banner bannerText="Course List" i18n-bannerText>
+</eg-staff-banner>
+
+<eg-string #successString i18n-text text="{{table_name}} Update Succeeded"></eg-string>
+<eg-string #createString i18n-text text="{{table_name}} Was Created Successfully"></eg-string>
+<eg-string #deleteFailedString i18n-text text="Delete of {{table_name}} failed or was not allowed"></eg-string>
+<eg-string #deleteSuccessString i18n-text text="Delete of {{table_name}} succeeded"></eg-string>
+<eg-string #flairTooltip i18n-text text="Limited Editing"></eg-string>
+
+<div class="w-100 mt-2 mb-2">
+  <eg-grid #grid idlClass={{idl_class}}
+    [dataSource]="grid_source"
+    [rowFlairIsEnabled]="true"
+    [rowFlairCallback]="rowFlairCallback"
+    [cellClassCallback]="gridCellClassCallback"
+    [sortable]="true">
+    <eg-grid-toolbar-button
+      label="Create {{table_name}}" (onClick)="createNew()" i18n-label>
+    </eg-grid-toolbar-button>
+    <eg-grid-toolbar-action label="Edit Selected" i18n-label (onClick)="editSelected($event)">
+    </eg-grid-toolbar-action>
+    <eg-grid-toolbar-action label="Delete Selected" i18n-label (onClick)="deleteSelected($event)">
+    </eg-grid-toolbar-action>
+  </eg-grid>
+</div>
+
+<eg-fm-record-editor #editDialog
+  idlClass={{idl_class}}
+  [preloadLinkedValues]="true">
+</eg-fm-record-editor>
diff --git a/Open-ILS/src/eg2/src/app/staff/admin/server/course-reserves/course-list.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/server/course-reserves/course-list.component.ts
new file mode 100644 (file)
index 0000000..9e4bb40
--- /dev/null
@@ -0,0 +1,149 @@
+import {Component, Input, ViewChild, OnInit} from '@angular/core';
+import {IdlObject} from '@eg/core/idl.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {GridComponent} from '@eg/share/grid/grid.component';
+import {Pager} from '@eg/share/util/pager';
+import {GridDataSource, GridColumn, GridRowFlairEntry} from '@eg/share/grid/grid';
+import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
+import {StringComponent} from '@eg/share/string/string.component';
+import {ToastService} from '@eg/share/toast/toast.service';
+
+@Component({
+    templateUrl: './course-list.component.html'
+})
+
+export class CourseListComponent implements OnInit { 
+    @ViewChild('editDialog', { static: true }) editDialog: FmRecordEditorComponent;
+    @ViewChild('grid', { static: true }) grid: GridComponent;
+    @ViewChild('successString', { static: true }) successString: StringComponent;
+    @ViewChild('createString', { static: false }) createString: StringComponent;
+    @ViewChild('createErrString', { static: false }) createErrString: StringComponent;
+    @ViewChild('updateFailedString', { static: false }) updateFailedString: StringComponent;
+    @ViewChild('deleteFailedString', { static: true }) deleteFailedString: StringComponent;
+    @ViewChild('deleteSuccessString', { static: true }) deleteSuccessString: StringComponent;
+    @ViewChild('flairTooltip', { static: true }) private flairTooltip: StringComponent;
+    rowFlairCallback: (row: any) => GridRowFlairEntry;
+    @Input() sort_field: string;
+    @Input() idl_class = "acmc";
+    @Input() dialog_size: 'sm' | 'lg' = 'lg';
+    @Input() table_name = "Course";
+    grid_source: GridDataSource = new GridDataSource();
+    search_value = '';
+
+    constructor(
+            private pcrud: PcrudService,
+            private toast: ToastService,
+    ){}
+
+    ngOnInit() {
+        this.getSource();
+        this.rowFlair();
+    }
+
+    /**
+     * Gets the data, specified by the class, that is available.
+     */
+    getSource() {
+        this.grid_source.getRows = (pager: Pager, sort: any[]) => {
+            const orderBy: any = {};
+            if (sort.length) {
+                // Sort specified from grid
+                orderBy[this.idl_class] = sort[0].name + ' ' + sort[0].dir;
+            } else if (this.sort_field) {
+                // Default sort field
+                orderBy[this.idl_class] = this.sort_field;
+            }
+            const searchOps = {
+                offset: pager.offset,
+                limit: pager.limit,
+                order_by: orderBy
+            };
+            return this.pcrud.retrieveAll(this.idl_class, searchOps, {fleshSelectors: true});
+        };
+    }
+
+    rowFlair() {
+        this.rowFlairCallback = (row: any): GridRowFlairEntry => {
+            const flair = {icon: null, title: null};
+            if (row.id() < 100) {
+                flair.icon = 'not_interested';
+                flair.title = this.flairTooltip.text;
+            }
+            return flair;
+        };
+    }
+
+    gridCellClassCallback = (row: any, col: GridColumn): string => {
+        if (col.name === 'id' && row.a[0] < 100) {
+            return 'text-danger';
+        }
+        return '';
+    }
+
+    showEditDialog(standingPenalty: IdlObject): Promise<any> {
+        this.editDialog.mode = 'update';
+        this.editDialog.recordId = standingPenalty['id']();
+        return new Promise((resolve, reject) => {
+            this.editDialog.open({size: this.dialog_size}).subscribe(
+                result => {
+                    this.successString.current()
+                        .then(str => this.toast.success(str));
+                    this.grid.reload();
+                    resolve(result);
+                },
+                error => {
+                    this.updateFailedString.current()
+                        .then(str => this.toast.danger(str));
+                    reject(error);
+                }
+            );
+        });
+    }
+
+    createNew() {
+        this.editDialog.mode = 'create';
+        this.editDialog.recordId = null;
+        this.editDialog.record = null;
+        this.editDialog.open({size: this.dialog_size}).subscribe(
+            ok => {
+                this.createString.current()
+                    .then(str => this.toast.success(str));
+                this.grid.reload();
+            },
+            rejection => {
+                if (!rejection.dismissed) {
+                    this.createErrString.current()
+                        .then(str => this.toast.danger(str));
+                }
+            }
+        );
+    }
+
+    editSelected(fields: IdlObject[]) {
+        // Edit each IDL thing one at a time
+        const editOneThing = (field_object: IdlObject) => {
+            if (!field_object) { return; }
+            this.showEditDialog(field_object).then(
+                () => editOneThing(fields.shift()));
+        };
+        editOneThing(fields.shift());
+    }
+
+    deleteSelected(idl_object: IdlObject[]) {
+            idl_object.forEach(idl_object => idl_object.isdeleted(true));
+            this.pcrud.autoApply(idl_object).subscribe(
+                val => {
+                    console.debug('deleted: ' + val);
+                    this.deleteSuccessString.current()
+                        .then(str => this.toast.success(str));
+                },
+                err => {
+                    this.deleteFailedString.current()
+                        .then(str => this.toast.danger(str));
+                },
+                ()  => this.grid.reload()
+            );
+        };
+}
+
diff --git a/Open-ILS/src/eg2/src/app/staff/admin/server/course-reserves/course-reserves.module.ts b/Open-ILS/src/eg2/src/app/staff/admin/server/course-reserves/course-reserves.module.ts
new file mode 100644 (file)
index 0000000..1702ba8
--- /dev/null
@@ -0,0 +1,23 @@
+import {NgModule} from '@angular/core';
+import {TreeModule} from '@eg/share/tree/tree.module';
+import {AdminCommonModule} from '@eg/staff/admin/common.module';
+import {CourseListComponent} from './course-list.component';
+import {CourseReservesRoutingModule} from './routing.module';
+
+@NgModule({
+  declarations: [
+    CourseListComponent
+  ],
+  imports: [
+    AdminCommonModule,
+    CourseReservesRoutingModule,
+    TreeModule
+  ],
+  exports: [
+  ],
+  providers: [
+  ]
+})
+
+export class CourseReservesModule {
+}
diff --git a/Open-ILS/src/eg2/src/app/staff/admin/server/course-reserves/routing.module.ts b/Open-ILS/src/eg2/src/app/staff/admin/server/course-reserves/routing.module.ts
new file mode 100644 (file)
index 0000000..84e74ff
--- /dev/null
@@ -0,0 +1,15 @@
+import {NgModule} from '@angular/core';
+import {RouterModule, Routes} from '@angular/router';
+import {CourseListComponent} from './course-list.component';
+
+const routes: Routes = [{
+    path: '',
+    component: CourseListComponent
+}];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule]
+})
+
+export class CourseReservesRoutingModule {}
\ No newline at end of file
index 194a979..fe4d354 100644 (file)
@@ -23,6 +23,9 @@ const routes: Routes = [{
     path: 'permission/grp_tree',
     component: PermGroupTreeComponent
 }, {
+    path: 'asset/course_list',
+    loadChildren: '@eg/staff/admin/server/course-reserves/course-reserves.module#CourseReservesModule'
+}, {
     path: 'actor/org_unit',
     loadChildren: () =>
       import('./org-unit.module').then(m => m.OrgUnitModule)