<class id="asfg" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::search_filter_group" oils_persist:tablename="actor.search_filter_group" reporter:label="Search Filter Group" oils_persist:field_safe="true">
<fields oils_persist:primary="id" oils_persist:sequence="actor.search_filter_group_id_seq">
- <field name="id" reporter:datatype="id" reporter:selector="label"/>
- <field name="owner" reporter:datatype="org_unit"/>
- <field name="code" reporter:datatype="text"/>
- <field name="label" reporter:datatype="text" oils_persist:i18n="true"/>
- <field name="create_date" reporter:datatype="timestamp"/>
- <field name="entries" oils_persist:virtual="true" reporter:datatype="link"/>
+ <field name="id" reporter:datatype="id" reporter:selector="label" reporter:label="ID" oils_obj:required="true"/>
+ <field name="owner" reporter:datatype="org_unit" reporter:label="Owning Org Unit" oils_obj:required="true"/>
+ <field name="code" reporter:datatype="text" reporter:label="Code" oils_obj:required="true"/>
+ <field name="label" reporter:datatype="text" oils_persist:i18n="true" reporter:label="Label" oils_obj:required="true"/>
+ <field name="create_date" reporter:datatype="timestamp" reporter:label="Create Date"/>
+ <field name="entries" oils_persist:virtual="true" reporter:datatype="link" reporter:label="Group Entries"/>
</fields>
<links>
<link field="owner" reltype="has_a" key="id" map="" class="aou"/>
</class>
<class id="asfge" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::search_filter_group_entry" oils_persist:tablename="actor.search_filter_group_entry" reporter:label="Search Filter Group Entry" oils_persist:field_safe="true">
<fields oils_persist:primary="id" oils_persist:sequence="actor.search_filter_group_entry_id_seq">
- <field name="id" reporter:datatype="id"/>
- <field name="grp" reporter:datatype="link"/>
- <field name="pos" reporter:datatype="int"/>
- <field name="query" reporter:datatype="link"/>
+ <field name="id" reporter:datatype="id" reporter:label="ID" oils_obj:required="true"/>
+ <field name="grp" reporter:datatype="link" reporter:label="Search Filter Group" oils_obj:required="true"/>
+ <field name="pos" reporter:datatype="int" reporter:label="Position" oils_obj:required="true"/>
+ <field name="query" reporter:datatype="link" reporter:label="Query" oils_obj:required="true"/>
</fields>
<links>
<link field="grp" reltype="has_a" key="id" map="" class="asfg"/>
<eg-link-table-link i18n-label label="Permission Tree Display Entries"
url="/eg/staff/admin/local/permission/grp_tree_display_entry"></eg-link-table-link>
<eg-link-table-link i18n-label label="Search Filter Groups"
- url="/eg/staff/admin/local/actor/search_filter_group"></eg-link-table-link>
+ routerLink="/staff/admin/local/actor/search_filter_group"></eg-link-table-link>
<eg-link-table-link i18n-label label="Shelving Location Groups"
routerLink="/staff/admin/local/asset/shelving_location_groups"></eg-link-table-link>
<eg-link-table-link i18n-label label="Shelving Location Order"
}, {
path: 'asset/course_module_term_course_map',
component: CourseTermMapComponent
+}, {
+ path: 'actor/search_filter_group',
+ loadChildren: () =>
+ import('./search-filter/search-filter-group.module').then(m => m.SearchFilterGroupModule)
}, {
path: 'config/circ_limit_set',
loadChildren: () =>
--- /dev/null
+<ng-template #dialogContent>
+ <div class="modal-header bg-info">
+ <h4 class="modal-title" i18n>New Query</h4>
+ <button type="button" class="close"
+ i18n-aria-label aria-label="Close"
+ (click)="closeAndReset()">
+ <span aria-hidden="true">×</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <div class="row">
+ <div class="col-lg-3 font-weight-bold" i18n>Query Label</div>
+ <div class="col-lg-9">
+ <input type="text" class="form-control"
+ placeholder="Query Label"
+ i18n-placeholder required
+ [(ngModel)]="newQueryLabel"/>
+ </div>
+ </div>
+ <div class="row mt-3">
+ <div class="col-lg-3 font-weight-bold" i18n>Query Text</div>
+ <div class="col-lg-9">
+ <input type="text" class="form-control"
+ placeholder="Query Text"
+ i18n-placeholder required
+ [(ngModel)]="newQueryText"/>
+ </div>
+ </div>
+ <div class="row mt-3">
+ <div class="col-lg-3 font-weight-bold" i18n>Position</div>
+ <div class="col-lg-9">
+ <input type="number" class="form-control"
+ placeholder="Position"
+ i18n-placeholder required
+ [(ngModel)]="newQueryPosition"/>
+ </div>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-warning"
+ (click)="closeAndReset()" i18n>Cancel</button>
+ <button type="button" class="btn btn-success"
+ (click)="save()" i18n >Save</button>
+ </div>
+</ng-template>
--- /dev/null
+import {Component, OnInit, Input} from '@angular/core';
+import {NetService} from '@eg/core/net.service';
+import {ActivatedRoute} from '@angular/router';
+import {IdlService, IdlObject} from '@eg/core/idl.service';
+import {AuthService} from '@eg/core/auth.service';
+import {DialogComponent} from '@eg/share/dialog/dialog.component';
+import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
+
+@Component({
+ selector: 'eg-query-dialog',
+ templateUrl: './query-dialog.component.html'
+})
+
+export class QueryDialogComponent extends DialogComponent implements OnInit {
+
+ currentId: number;
+ newAsq: IdlObject;
+ newAsfge: IdlObject;
+
+ @Input() mode: 'create' | 'update';
+ @Input() record: IdlObject;
+ @Input() recordId: number;
+ @Input() newQueryLabel: string;
+ @Input() newQueryText: string;
+ @Input() newQueryPosition: string;
+
+ constructor(
+ private modal: NgbModal, // required for passing to parent
+ private route: ActivatedRoute,
+ private idl: IdlService,
+ private net: NetService,
+ private auth: AuthService
+ ) {
+ super(modal); // required for subclassing
+ }
+
+ ngOnInit() {
+ this.currentId = parseInt(this.route.snapshot.paramMap.get('id'), 10);
+ this.newAsfge = this.idl.create('asfge');
+ this.newAsq = this.idl.create('asq');
+ }
+
+ // wipe out all data so next time we start with a clean slate
+ closeAndReset(data) {
+ this.mode = undefined;
+ this.record = undefined;
+ this.recordId = undefined;
+ this.newQueryLabel = undefined;
+ this.newQueryPosition = undefined;
+ this.newQueryText = undefined;
+ this.close(data);
+ }
+
+ save() {
+ if (!this.newQueryLabel || (!this.newQueryPosition && (this.newQueryPosition != 0)) || !this.newQueryText) {
+ this.closeAndReset({notFilledOut: true});
+ }
+ const recToSave = this.prepareRecord();
+ return this.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.filter_group_entry.crud',
+ this.auth.token(),
+ recToSave
+ ).toPromise().then(res => {
+ this.closeAndReset(res);
+ });
+ }
+
+ prepareRecord(): IdlObject {
+ let recToSave;
+ let queryToSave;
+ if (this.mode === 'create') {
+ recToSave = this.idl.clone(this.newAsfge);
+ queryToSave = this.idl.clone(this.newAsq);
+ recToSave.isnew(true);
+ recToSave.query(queryToSave);
+ } else if (this.mode === 'update') {
+ recToSave = this.record;
+ queryToSave = this.record.query();
+ recToSave.ischanged(true);
+ } else {
+ console.debug('Error! No mode defined!');
+ }
+ queryToSave.label(this.newQueryLabel);
+ queryToSave.query_text(this.newQueryText);
+ recToSave.pos(this.newQueryPosition);
+ recToSave.grp(this.currentId);
+ return recToSave;
+ }
+}
--- /dev/null
+<eg-staff-banner bannerText="Search Filter Group" i18n-bannerText></eg-staff-banner>
+
+<div class="col-lg-6 offset-lg-3">
+ <eg-fm-record-editor displayMode="inline" hiddenFieldsList="id,create_date"
+ idlClass="asfg" mode="update" recordId="{{this.currentId}}">
+ </eg-fm-record-editor>
+</div>
+
+<eg-staff-banner bannerText="Search Filter Group Entries" i18n-bannerText></eg-staff-banner>
+
+<eg-grid #grid idlClass="asfge" [dataSource]="dataSource" [sortable]="false"
+ hideFields="grp,query">
+ <eg-grid-column path="query.label" label="Query Label"></eg-grid-column>
+ <eg-grid-column path="query.query_text" label="Query Text"></eg-grid-column>
+ <eg-grid-toolbar-button label="New" i18n-label
+ (onClick)="createQuery()"></eg-grid-toolbar-button>
+ <eg-grid-toolbar-action label="Edit Selected" i18n-label
+ (onClick)="editQuery($event)"></eg-grid-toolbar-action>
+ <eg-grid-toolbar-action label="Delete Selected" i18n-label
+ (onClick)="deleteSelected($event)"></eg-grid-toolbar-action>
+</eg-grid>
+
+<eg-query-dialog #queryDialog ></eg-query-dialog>
+
+<eg-string #createQueryString i18n-text text="New Query Added"></eg-string>
+<eg-string #queryRequiredString i18n-text text="Error! Are all fields filled out?"></eg-string>
+<eg-string #createString i18n-text text="New Search Filter Group Entry Added"></eg-string>
+<eg-string #createErrString i18n-text
+ text="Creation failed or was not allowed"></eg-string>
+<eg-string #deleteFailedString i18n-text
+ text="Delete failed or was not allowed"></eg-string>
+<eg-string #deleteSuccessString i18n-text
+ text="Delete succeeded"></eg-string>
+<eg-string #updateFailedString i18n-text
+ text="Update failed or was not allowed"></eg-string>
+<eg-string #updateSuccessString i18n-text
+ text="Update succeeded"></eg-string>
--- /dev/null
+import {Component, OnInit, Input, ViewChild} from '@angular/core';
+import {ActivatedRoute} from '@angular/router';
+import {GridDataSource} from '@eg/share/grid/grid';
+import {GridComponent} from '@eg/share/grid/grid.component';
+import {Pager} from '@eg/share/util/pager';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {IdlObject} from '@eg/core/idl.service';
+import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
+import {ToastService} from '@eg/share/toast/toast.service';
+import {StringComponent} from '@eg/share/string/string.component';
+import {QueryDialogComponent} from './query-dialog.component';
+
+@Component({
+ templateUrl: './search-filter-group-entries.component.html'
+})
+
+export class SearchFilterGroupEntriesComponent implements OnInit {
+
+ @ViewChild('editDialog') editDialog: FmRecordEditorComponent;
+ @ViewChild('queryDialog') queryDialog: QueryDialogComponent;
+ @ViewChild('grid', { static: true }) grid: GridComponent;
+
+ @ViewChild('updateSuccessString') updateSuccessString: StringComponent;
+ @ViewChild('updateFailedString') updateFailedString: StringComponent;
+ @ViewChild('createString') createString: StringComponent;
+ @ViewChild('createQueryString') createQueryString: StringComponent;
+ @ViewChild('queryRequiredString') queryRequiredString: StringComponent;
+ @ViewChild('createErrString') createErrString: StringComponent;
+ @ViewChild('deleteFailedString') deleteFailedString: StringComponent;
+ @ViewChild('deleteSuccessString') deleteSuccessString: StringComponent;
+
+ @Input() dataSource: GridDataSource;
+
+ currentId: number;
+
+ constructor(
+ private route: ActivatedRoute,
+ private pcrud: PcrudService,
+ private toast: ToastService
+ ) {
+ this.dataSource = new GridDataSource();
+ }
+
+ ngOnInit() {
+ this.currentId = parseInt(this.route.snapshot.paramMap.get('id'), 10);
+ this.dataSource.getRows = (pager: Pager, sort: any[]) => {
+ const searchOps = {
+ offset: pager.offset,
+ limit: pager.limit,
+ order_by: {asfge: 'pos'},
+ flesh: 1,
+ flesh_fields: {asfge: ['query']}
+ };
+ return this.pcrud.search('asfge', {grp: this.currentId}, searchOps);
+ };
+ this.grid.onRowActivate.subscribe(
+ (idlThing: IdlObject) => this.editQuery([idlThing])
+ );
+ }
+
+ createQuery = () => {
+ this.queryDialog.mode = 'create';
+ this.queryDialog.open({size: 'lg'}).subscribe(
+ result => {
+ if (result.notFilledOut) {
+ this.queryRequiredString.current()
+ .then(str => this.toast.danger(str));
+ } else {
+ this.createQueryString.current()
+ .then(str => this.toast.success(str));
+ this.grid.reload();
+ }
+ },
+ error => {
+ this.createErrString.current()
+ .then(str => this.toast.danger(str));
+ }
+ );
+ }
+
+ editQuery = (event) => {
+ const firstRecord = event[0];
+ this.queryDialog.record = firstRecord;
+ this.queryDialog.mode = 'update';
+ this.queryDialog.newQueryLabel = firstRecord.query().label();
+ this.queryDialog.newQueryText = firstRecord.query().query_text();
+ this.queryDialog.newQueryPosition = firstRecord.pos();
+ this.queryDialog.recordId = firstRecord.id();
+ this.queryDialog.open({size: 'lg'}).subscribe(
+ result => {
+ if (result.notFilledOut) {
+ this.queryRequiredString.current()
+ .then(str => this.toast.danger(str));
+ } else {
+ this.updateSuccessString.current()
+ .then(str => this.toast.success(str));
+ this.grid.reload();
+ }
+ },
+ error => {
+ this.updateFailedString.current()
+ .then(str => this.toast.danger(str));
+ }
+ );
+ }
+
+ deleteSelected = (idlThings: IdlObject[]) => {
+ idlThings.forEach(idlThing => idlThing.isdeleted(true));
+ this.pcrud.autoApply(idlThings).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()
+ );
+ }
+}
--- /dev/null
+import {NgModule} from '@angular/core';
+import {RouterModule, Routes} from '@angular/router';
+import {SearchFilterGroupComponent} from './search-filter-group.component';
+import {SearchFilterGroupEntriesComponent} from './search-filter-group-entries.component';
+
+const routes: Routes = [{
+ path: ':id',
+ component: SearchFilterGroupEntriesComponent
+ }, {
+ path: '',
+ component: SearchFilterGroupComponent
+}];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+
+export class SearchFilterGroupRoutingModule {}
--- /dev/null
+<eg-staff-banner bannerText="Search Filter Group Configuration" i18n-bannerText>
+ </eg-staff-banner>
+
+<eg-grid #grid idlClass="asfg" [dataSource]="gridDataSource" [sortable]="true">
+<eg-grid-column label="ID" path="id" name="id" datatype="id" [hidden]="true"></eg-grid-column>
+ <eg-grid-toolbar-button label="New Search Filter Group" i18n-label
+ (onClick)="createNew()"></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>
+
+<eg-fm-record-editor #editDialog idlClass="asfg">
+</eg-fm-record-editor>
+
+<eg-string #createString i18n-text text="New Search Filter Group Added"></eg-string>
+<eg-string #createErrString i18n-text text="Failed to Create New Search Filter Group">
+</eg-string>
+<eg-string #deleteFailedString i18n-text
+ text="Deletion of Search Filter Group failed or was not allowed"></eg-string>
+<eg-string #DeletionSuccessString i18n-text text="Delete of Search Filter Group succeeded">
+</eg-string>
\ No newline at end of file
--- /dev/null
+import {Pager} from '@eg/share/util/pager';
+import {Location} from '@angular/common';
+import {FormatService} from '@eg/core/format.service';
+import {Component, Input, ViewChild, OnInit} from '@angular/core';
+import {Router, ActivatedRoute} from '@angular/router';
+import {IdlService, IdlObject} from '@eg/core/idl.service';
+import {GridDataSource} from '@eg/share/grid/grid';
+import {GridComponent} from '@eg/share/grid/grid.component';
+import {ToastService} from '@eg/share/toast/toast.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {OrgService} from '@eg/core/org.service';
+import {PermService} from '@eg/core/perm.service';
+import {AuthService} from '@eg/core/auth.service';
+import {StringComponent} from '@eg/share/string/string.component';
+import {AdminPageComponent} from '../../../share/admin-page/admin-page.component';
+
+@Component({
+ templateUrl: './search-filter-group.component.html'
+})
+
+export class SearchFilterGroupComponent extends AdminPageComponent implements OnInit {
+
+ @Input() gridDataSource: GridDataSource;
+ @ViewChild('grid', {static: true}) grid: GridComponent;
+ @ViewChild('createString') createString: StringComponent;
+ @ViewChild('createErrString') createErrString: StringComponent;
+ @ViewChild('deleteFailedString') deleteFailedString: StringComponent;
+ @ViewChild('deleteSuccessString') deleteSuccessString: StringComponent;
+
+ constructor(
+ route: ActivatedRoute,
+ ngLocation: Location,
+ format: FormatService,
+ idl: IdlService,
+ org: OrgService,
+ auth: AuthService,
+ pcrud: PcrudService,
+ perm: PermService,
+ toast: ToastService,
+ private router: Router
+ ) {
+ super(route, ngLocation, format, idl, org, auth, pcrud, perm, toast);
+ }
+
+ ngOnInit() {
+ this.gridDataSource = new GridDataSource();
+ this.gridDataSource.getRows = (pager: Pager, sort: any[]) => {
+ const searchOps = {
+ offset: pager.offset,
+ limit: pager.limit,
+ order_by: {}
+ };
+ return this.pcrud.retrieveAll('asfg', searchOps);
+ };
+ this.grid.onRowActivate.subscribe(
+ (idlThing: IdlObject) => {
+ const idToEdit = idlThing.id();
+ this.navigateToEditPage(idToEdit);
+ }
+ );
+ }
+
+ createNew = () => {
+ this.editDialog.mode = 'create';
+ this.editDialog.recordId = null;
+ this.editDialog.record = null;
+ this.editDialog.hiddenFieldsList = ['id', 'create_date'];
+ this.editDialog.open({size: 'lg'}).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 = (sfGroups: IdlObject[]) => {
+ const idToEdit = sfGroups[0].id();
+ this.navigateToEditPage(idToEdit);
+ }
+
+ navigateToEditPage(id: any) {
+ this.router.navigate(['/staff/admin/local/actor/search_filter_group/' + id]);
+ }
+
+ }
--- /dev/null
+import {NgModule} from '@angular/core';
+import {AdminCommonModule} from '@eg/staff/admin/common.module';
+import {SearchFilterGroupComponent} from './search-filter-group.component';
+import {SearchFilterGroupEntriesComponent} from './search-filter-group-entries.component';
+import {SearchFilterGroupRoutingModule} from './search-filter-group-routing.module';
+import {QueryDialogComponent} from './query-dialog.component';
+
+@NgModule({
+ declarations: [
+ SearchFilterGroupComponent,
+ SearchFilterGroupEntriesComponent,
+ QueryDialogComponent
+ ],
+ imports: [
+ AdminCommonModule,
+ SearchFilterGroupRoutingModule,
+ ],
+ exports: [
+ ],
+ providers: [
+ ]
+})
+
+export class SearchFilterGroupModule {}