</a>
</div>
</div>
- <div class="">
+ <div class="pr-1">
<div ngbDropdown placement="bottom-right">
<button class="btn btn-light" id="basketActions"
[disabled]="!basketCount()"
ngbDropdownToggle i18n>Basket Actions</button>
<div ngbDropdownMenu aria-labelledby="basketActions">
- <button class="dropdown-item"
- (click)="applyAction('view')" i18n>View Basket</button>
- <button class="dropdown-item"
- (click)="applyAction('hold')" i18n>Place Hold</button>
- <button class="dropdown-item"
- (click)="applyAction('print')" i18n>Print Title Details</button>
- <button class="dropdown-item"
- (click)="applyAction('email')" i18n>Email Title Details</button>
- <button class="dropdown-item"
- (click)="applyAction('bucket')" i18n>Add Basket to Bucket</button>
- <button class="dropdown-item"
- (click)="applyAction('export_marc')" i18n>Export Records</button>
- <button class="dropdown-item"
- (click)="applyAction('clear')" i18n>Clear Basket</button>
+ <button class="dropdown-item"
+ (click)="applyAction('view')" i18n>View Basket</button>
+ <button class="dropdown-item"
+ (click)="applyAction('hold')" i18n>Place Hold</button>
+ <button class="dropdown-item"
+ (click)="applyAction('print')" i18n>Print Title Details</button>
+ <button class="dropdown-item"
+ (click)="applyAction('email')" i18n>Email Title Details</button>
+ <button class="dropdown-item"
+ (click)="applyAction('bucket')" i18n>Add Basket to Bucket</button>
+ <button class="dropdown-item"
+ (click)="applyAction('export_marc')" i18n>Export Records</button>
+ <button class="dropdown-item"
+ (click)="applyAction('clear')" i18n>Clear Basket</button>
+ </div>
</div>
</div>
+ <div>
+ <!-- Note this Prefernces links is not specific to Basket handling,
+ but it's here since it allowed for consistent formatting -->
+ <a routerLink="/staff/catalog/prefs" queryParamsHandling="merge">
+ <button class="btn btn-light" i18n>Catalog Preferences</button>
+ </a>
+ </div>
</div>
import {CnBrowseResultsComponent} from './cnbrowse/results.component';
import {SearchTemplatesComponent} from './search-templates.component';
import {MarcEditModule} from '@eg/staff/share/marc-edit/marc-edit.module';
+import {PreferencesComponent} from './prefs.component';
@NgModule({
declarations: [
SearchTemplatesComponent,
CnBrowseComponent,
OpacViewComponent,
+ PreferencesComponent,
CnBrowseResultsComponent
],
imports: [
// TODO: does unapi support pref-lib for result-page copy counts?
prefOrg: IdlObject;
+ // Default search tab
+ defaultTab: string;
+
// Cache the currently selected detail record (i.g. catalog/record/123)
// summary so the record detail component can avoid duplicate fetches
// during record tab navigation.
--- /dev/null
+<eg-catalog-search-form #searchForm></eg-catalog-search-form>
+
+<eg-staff-banner bannerText="Catalog Preferences"></eg-staff-banner>
+
+<eg-string #successMsg i18n-text text="Setting Update Succeeded"></eg-string>
+<eg-string #failMsg i18n-text text="Setting Update Failed"></eg-string>
+
+<div class="row border-bottom border-secondary p-2 m-2">
+ <div class="col-lg-2 offset-lg-1">
+ <label for="default-lib-selector" class="font-weight-bold" i18n>
+ Default Search Library
+ </label>
+ </div>
+ <div class="col-lg-2">
+ <eg-org-select domId="default-lib-selector"
+ (onChange)="orgChanged($event, 'eg.search.search_lib')"
+ [applyOrgId]="settings['eg.search.search_lib']">
+ </eg-org-select>
+ </div>
+ <div class="col-lg-6" i18n>
+ The default search library setting determines what library is
+ searched from the advanced search screen and portal page by
+ default. Manual selection of a search library will override it. One
+ recommendation is to set the search library to the highest point you
+ would normally want to search.
+ </div>
+</div>
+
+<div class="row border-bottom border-secondary p-2 m-2">
+ <div class="col-lg-2 offset-lg-1">
+ <label for="pref-lib-selector" class="font-weight-bold" i18n>
+ Preferred Library
+ </label>
+ </div>
+ <div class="col-lg-2">
+ <eg-org-select domId="pref-lib-selector"
+ (onChange)="orgChanged($event, 'eg.search.pref_lib')"
+ [applyOrgId]="settings['eg.search.pref_lib']">
+ </eg-org-select>
+ </div>
+ <div class="col-lg-6" i18n>
+ The preferred library is used to show copies and URIs regardless
+ of the library searched. One recommendation is to set this to your
+ workstation library so that local copies show up first in search
+ results.
+ </div>
+</div>
+
+<div class="row border-bottom border-secondary p-2 m-2">
+ <div class="col-lg-2 offset-lg-1">
+ <label for="def-pane-selector" class="font-weight-bold" i18n>
+ Default Search Pane
+ </label>
+ </div>
+ <div class="col-lg-2">
+ <eg-combobox [selectedId]="settings['eg.search.adv_pane']"
+ (onChange)="paneChanged($event)">
+ <eg-combobox-entry entryId="advanced" entryLabel="Keyword Search"></eg-combobox-entry>
+ <eg-combobox-entry entryId="numeric" entryLabel="Numeric Search"></eg-combobox-entry>
+ <eg-combobox-entry entryId="expert" entryLabel="MARC Search"></eg-combobox-entry>
+ <eg-combobox-entry entryId="browse" entryLabel="Browse"></eg-combobox-entry>
+ <eg-combobox-entry entryId="cnbrowse" entryLabel="Shelf Browse"></eg-combobox-entry>
+ </eg-combobox>
+ </div>
+ <div class="col-lg-6" i18n>
+ Focus this search tab by default when opening new catalog pages.
+ </div>
+</div>
+
+<div class="row border-bottom border-secondary p-2 m-2">
+ <div class="col-lg-2 offset-lg-1">
+ <label for="pref-lib-selector" class="font-weight-bold" i18n>
+ Search Results Per Page
+ </label>
+ </div>
+ <div class="col-lg-2">
+ <input type="number" min="1" max="100" class="form-control"
+ [(ngModel)]="settings['eg.catalog.results.count']"
+ (change)="countChanged()"/>
+ </div>
+ <div class="col-lg-6" i18n>
+ The number of search results to display per page.
+ </div>
+</div>
--- /dev/null
+import {Component, OnInit, ViewChild} from '@angular/core';
+import {IdlObject} from '@eg/core/idl.service';
+import {StaffCatalogService} from './catalog.service';
+import {ServerStoreService} from '@eg/core/server-store.service';
+import {ToastService} from '@eg/share/toast/toast.service';
+import {StringComponent} from '@eg/share/string/string.component';
+import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
+
+/* Component for managing catalog preferences */
+
+const CATALOG_PREFS = [
+ 'eg.search.search_lib',
+ 'eg.search.pref_lib',
+ 'eg.search.adv_pane',
+ 'eg.catalog.results.count'
+];
+
+@Component({
+ templateUrl: 'prefs.component.html'
+})
+export class PreferencesComponent implements OnInit {
+
+ settings: Object = {};
+
+ @ViewChild('successMsg', {static: false}) successMsg: StringComponent;
+ @ViewChild('failMsg', {static: false}) failMsg: StringComponent;
+
+ constructor(
+ private store: ServerStoreService,
+ private toast: ToastService,
+ private staffCat: StaffCatalogService,
+ ) {}
+
+ ngOnInit() {
+ this.staffCat.createContext();
+
+ // Pre-fetched by the resolver.
+ this.store.getItemBatch(CATALOG_PREFS)
+ .then(settings => this.settings = settings);
+ }
+
+ orgChanged(org: IdlObject, setting: string) {
+ const localVar = setting === 'eg.search.search_lib' ?
+ 'defaultSearchOrg' : 'prefOrg';
+
+ this.updateValue(setting, org ? org.id() : null)
+ .then(val => this.staffCat[localVar] = val);
+ }
+
+ paneChanged(entry: ComboboxEntry) {
+ this.updateValue('eg.search.adv_pane', entry ? entry.id : null)
+ .then(value => this.staffCat.defaultTab = value);
+ }
+
+ countChanged() {
+ this.updateValue('eg.catalog.results.count',
+ this.settings['eg.catalog.results.count'] || null)
+ .then(value => {
+ this.staffCat.searchContext.pager.limit = value || 20;
+ });
+ }
+
+ updateValue(setting: string, value: any): Promise<any> {
+ const promise = (value === null) ?
+ this.store.removeItem(setting) :
+ this.store.setItem(setting, value);
+
+ return promise
+ .then(_ => this.toast.success(this.successMsg.text))
+ .then(_ => value);
+ }
+}
+
return this.store.getItemBatch([
'eg.search.search_lib',
'eg.search.pref_lib',
+ 'eg.search.adv_pane',
+ 'eg.catalog.results.count',
'cat.holdings_show_empty_org',
'cat.holdings_show_empty',
'cat.marcedit.stack_subfields',
'cat.marcedit.flateditor',
'cat.holdings_show_copies',
'cat.holdings_show_vols',
+ 'opac.staff_saved_search.size',
+ 'eg.catalog.search_templates',
'opac.staff_saved_search.size'
]).then(settings => {
this.staffCat.defaultSearchOrg =
this.org.get(settings['eg.search.search_lib']);
this.staffCat.prefOrg =
this.org.get(settings['eg.search.pref_lib']);
+ this.staffCat.defaultTab = settings['eg.search.adv_pane'];
+ if (settings['eg.catalog.results.count']) {
+ this.staffCat.defaultSearchLimit =
+ Number(settings['eg.catalog.results.count']);
+ }
});
}
}
import {BrowseComponent} from './browse.component';
import {CnBrowseComponent} from './cnbrowse.component';
import {CanDeactivateGuard} from '@eg/share/util/can-deactivate.guard';
+import {PreferencesComponent} from './prefs.component';
const routes: Routes = [{
path: '',
path: 'cnbrowse',
component: CnBrowseComponent,
resolve: {catResolver : CatalogResolver}
+ }, {
+ path: 'prefs',
+ component: PreferencesComponent,
+ resolve: {catResolver : CatalogResolver}
}
];
import {StaffCatalogService} from './catalog.service';
import {NgbTabset, NgbTabChangeEvent} from '@ng-bootstrap/ng-bootstrap';
+// Maps opac-style default tab names to local tab names.
+const LEGACY_TAB_NAME_MAP = {
+ expert: 'marc',
+ numeric: 'ident',
+ advanced: 'term'
+};
+
@Component({
selector: 'eg-catalog-search-form',
styleUrls: ['search-form.component.css'],
this.searchTab = 'ident';
} else if (this.context.browseSearch.isSearchable()) {
this.searchTab = 'browse';
- } else {
- // Default tab
+ } else if (this.context.termSearch.isSearchable()) {
this.searchTab = 'term';
+
+ } else {
+
+ this.searchTab =
+ LEGACY_TAB_NAME_MAP[this.staffCat.defaultTab]
+ || this.staffCat.defaultTab || 'term';
+
+ }
+
+ if (this.searchTab === 'term') {
this.refreshCopyLocations();
}
}
ngOnInit() {
this.context = this.staffCat.searchContext;
- console.log('ngOnInit() with selected = ', this.staffCat.selectedTemplate);
- this.org.settings('opac.staff_saved_search.size').then(sets => {
- const size = sets['opac.staff_saved_search.size'] || 0;
+ this.serverStore.getItem('opac.staff_saved_search.size')
+ .then(size => {
if (!size) { return; }
this.recentSearchesCount = Number(size);
)
);
+INSERT INTO config.workstation_setting_type (name, grp, datatype, label)
+VALUES (
+ 'eg.catalog.results.count', 'gui', 'integer',
+ oils_i18n_gettext(
+ 'eg.catalog.results.count',
+ 'Catalog Results Page Size',
+ 'cwst', 'label'
+ )
+);
+
--- /dev/null
+BEGIN;
+
+-- SELECT evergreen.upgrade_deps_block_check('TODO', :eg_version);
+
+INSERT INTO config.workstation_setting_type (name, grp, datatype, label)
+VALUES (
+ 'eg.catalog.results.count', 'gui', 'integer',
+ oils_i18n_gettext(
+ 'eg.catalog.results.count',
+ 'Catalog Results Page Size',
+ 'cwst', 'label'
+ )
+);
+
+COMMIT;