--- /dev/null
+
+<eg-title i18n-prefix prefix="Print Template Administration"></eg-title>
+<eg-staff-banner bannerText="Print Template Administration" i18n-bannerText>
+</eg-staff-banner>
+
+<div class="row mb-3">
+ <div class="col-lg-3">
+ <div class="input-group">
+ <div class="input-group-prepend">
+ <span class="input-group-text" i18n>Owner</span>
+ </div>
+ <eg-org-select
+ [limitPerms]="['ADMIN_PRINT_TEMPLATE']"
+ [initialOrg]="contextOrg"
+ (onChange)="orgOnChange($event)">
+ </eg-org-select>
+ </div>
+ </div>
+ <div class="col-lg-3">
+ <div class="input-group">
+ <div class="input-group-prepend">
+ <span class="input-group-text" i18n>Template</span>
+ </div>
+ <eg-combobox [entries]="entries" #templateSelector
+ (onChange)="selectTemplate($event ? $event.id : null)">
+ </eg-combobox>
+ </div>
+ </div>
+ <div class="col-lg-3" *ngIf="localeEntries.length > 0">
+ <div class="input-group">
+ <div class="input-group-prepend">
+ <span class="input-group-text" i18n>Locale</span>
+ </div>
+ <eg-combobox [entries]="localeEntries"
+ [startId]="localeCode"
+ (onChange)="localeOnChange($event ? $event.id : null)">
+ </eg-combobox>
+ </div>
+ </div>
+</div>
+
+<ngb-tabset *ngIf="template" #tabs (tabChange)="onTabChange($event)">
+ <ngb-tab title="Template Info" i18n-title id='info'>
+ <ng-template ngbTabContent>
+ </ng-template>
+ </ngb-tab>
+ <ngb-tab title="Template" i18n-title id='template'>
+ <ng-template ngbTabContent>
+ <div class="row">
+ <div class="col-lg-6 d-flex justify-content-end mt-3">
+ <button class="btn btn-success" (click)="applyChanges()" i18n>
+ Save and Refresh
+ </button>
+ </div>
+ </div>
+ <div class="row mt-2">
+ <div class="col-lg-6">
+ <h4 i18n>Template</h4>
+ <textarea rows="30" class="form-control"
+ spellcheck="false"
+ [ngModel]="template.template()"
+ (ngModelChange)="template.template($event); template.ischanged(true)">
+ </textarea>
+ </div>
+ <div class="col-lg-6">
+ <h4 i18n>Preview</h4>
+ <div class="border border-dark w-100" id="template-preview-pane">
+ </div>
+ <h4 class="mt-3" i18n>Compiled Content</h4>
+ <div class="border border-dark w-100">
+ <pre>{{compiledContent}}</pre>
+ </div>
+ </div>
+ </div>
+ </ng-template>
+ </ngb-tab>
+ <ngb-tab title="Sample Data" i18n-title id='data'>
+ <ng-template ngbTabContent>
+ <textarea rows="20" [(ngModel)]="sampleJson"
+ spellcheck="false" class="form-control">
+ </textarea>
+ </ng-template>
+ </ngb-tab>
+</ngb-tabset>
+
import {Component, OnInit, ViewChild, TemplateRef} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
-import {IdlService} from '@eg/core/idl.service';
-import {FmFieldOptions} from '@eg/share/fm-editor/fm-editor.component';
+import {IdlService, IdlObject} from '@eg/core/idl.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {AuthService} from '@eg/core/auth.service';
+import {OrgService} from '@eg/core/org.service';
+import {ComboboxComponent, ComboboxEntry
+ } from '@eg/share/combobox/combobox.component';
+import {PrintService} from '@eg/share/print/print.service';
+import {LocaleService} from '@eg/core/locale.service';
+import {NgbTabset, NgbTabChangeEvent} from '@ng-bootstrap/ng-bootstrap';
+
+const SAMPLE_JSON_DATA: any = {
+ patron: {
+ first_given_name: 'Leela',
+ second_given_name: '',
+ family_name: 'Turanga'
+ },
+ address: {
+ street1: '123 Pineapple Rd',
+ city: 'North Southland',
+ state: 'HI',
+ post_code: 12321
+ }
+};
+
+const SAMPLE_TEMPLATE_DATA: any = {
+ 'address-label': {
+ patron: SAMPLE_JSON_DATA.patron,
+ address: SAMPLE_JSON_DATA.address
+ }
+};
+
/**
- * Generic IDL class editor page.
+ * Print Template Admin Page
*/
@Component({
- template: `
- <eg-title i18n-prefix prefix="{{classLabel}} Administration"></eg-title>
- <ng-template #templateTemplate let-record="record">
- <textarea class="form-control" rows="20" [ngModel]="record.template()"
- (ngModelChange)="record.template($event)"></textarea>
- </ng-template>
- <eg-staff-banner bannerText="{{classLabel}} Configuration" i18n-bannerText>
- </eg-staff-banner>
- <eg-admin-page idlClass="cpt" [fieldOptions]="fieldOptions"></eg-admin-page>
- `
+ templateUrl: 'print-template.component.html'
})
export class PrintTemplateComponent implements OnInit {
- idlClass: string;
- classLabel: string;
- persistKeyPfx: string;
- fieldOptions: {[field: string]: FmFieldOptions};
+ contextOrg: IdlObject;
+ entries: ComboboxEntry[];
+ template: IdlObject;
+ sampleJson: string;
+ localeCode: string;
+ localeEntries: ComboboxEntry[];
+ compiledContent: string;
+
+ @ViewChild('templateSelector') templateSelector: ComboboxComponent;
+ @ViewChild('tabs') tabs: NgbTabset;
- @ViewChild('templateTemplate') templateTemplate: TemplateRef<any>;
+ // Define some sample data that can be used for various templates
constructor(
private route: ActivatedRoute,
- private idl: IdlService) {}
+ private idl: IdlService,
+ private org: OrgService,
+ private pcrud: PcrudService,
+ private auth: AuthService,
+ private locale: LocaleService,
+ private printer: PrintService
+ ) {
+ this.entries = [];
+ this.localeEntries = [];
+ }
ngOnInit() {
+ this.contextOrg = this.org.get(this.auth.user().ws_ou());
+ this.localeCode = this.locale.currentLocaleCode();
+ this.locale.supportedLocales().subscribe(
+ l => this.localeEntries.push({id: l.code(), label: l.name()}));
+ this.setTemplateInfo();
+ }
+
+ onTabChange(evt: NgbTabChangeEvent) {
+ if (evt.nextId === 'template') {
+ this.refreshPreview();
+ }
+ }
+
+
+ container(): any {
+ // Only present when its tab is visible
+ return document.getElementById('template-preview-pane');
+ }
+
+ orgOnChange(org: IdlObject) {
+ this.contextOrg = org;
+ this.setTemplateInfo();
+ }
+
+ localeOnChange(code: string) {
+ if (code) {
+ this.localeCode = code;
+ this.setTemplateInfo();
+ }
+ }
+
+ // Fetch name/id for all templates in range.
+ // Avoid fetching the template content until needed.
+ setTemplateInfo() {
+ this.entries = [];
+ this.template = null;
+ this.templateSelector.applyEntryId(null);
+ this.compiledContent = '';
+
+ this.pcrud.search('cpt',
+ {
+ owner: this.contextOrg.id(),
+ locale: this.localeCode
+ },
+ {
+ select: {cpt: ['id', 'label']},
+ order_by: {cpt: 'label'}
+ }
+ ).subscribe(tmpl =>
+ this.entries.push({id: tmpl.id(), label: tmpl.label()})
+ );
+ }
- this.fieldOptions = {
- template: {
- customTemplate: {
- template: this.templateTemplate
- }
+ selectTemplate(id: number) {
+ this.pcrud.retrieve('cpt', id).subscribe(t => {
+ this.template = t;
+ const data = SAMPLE_TEMPLATE_DATA[t.name()];
+ if (data) {
+ this.sampleJson = JSON.stringify(data, null, 2);
}
- };
+ });
+ }
+
+ refreshPreview() {
+ if (!this.sampleJson) return;
+ this.compiledContent = '';
+
+ let data;
+ try {
+ data = JSON.parse(this.sampleJson);
+ } catch (E) {
+ // TODO: i18n/AlertDialog
+ alert('Invalid Sample Data JSON');
+ }
+
+ this.printer.compileRemoteTemplate({
+ templateId: this.template.id(),
+ contextData: data,
+ printContext: 'default' // required, has no impact here
+
+ }).then(response => {
+
+ this.compiledContent = response.content;
+ if (response.contentType === 'text/html') {
+ this.container().innerHTML = response.content;
+ } else {
+ // Assumes text/plain or similar
+ this.container().innerHTML = '<pre>' + response.content + '</pre>';
+ }
+ });
+ }
- this.idlClass = 'cpt';
- const classDef = this.idl.classes[this.idlClass];
- this.classLabel = classDef.label;
+ applyChanges() {
+ this.container().innerHTML = '';
+ this.pcrud.update(this.template).toPromise()
+ .then(() =>this.refreshPreview());
}
}
# Let pcrud handle the authz
$e->personality('open-ils.pcrud');
- my $owner = $e->requestor->ws_ou;
+ my $template_id = $cgi->param('template_id');
+ my $owner = $cgi->param('owner') || $e->requestor->ws_ou;
my $locale = $cgi->param('locale') || 'en-US';
my $template_name = $cgi->param('template_name');
my $template_data = $cgi->param('template_data');
- return Apache2::Const::FORBIDDEN unless $template_name;
+ return Apache2::Const::FORBIDDEN unless $template_name || $template_id;
- my $template = find_template($e, $template_name, $locale, $owner)
+ my $template = find_template($e, $template_id, $template_name, $locale, $owner)
or return Apache2::Const::NOT_FOUND;
my $output = '';
# Find the template closest to the specific org unit owner.
my %template_cache;
sub find_template {
- my ($e, $name, $locale, $owner) = @_;
+ my ($e, $template_id, $name, $locale, $owner) = @_;
+
+ if ($template_id) {
+ # Requesting by ID, generally used for testing,
+ # always pulls the latest value.
+ return $e->retrieve_config_print_template($template_id);
+ }
return $template_cache{$owner}{$name}{$locale}
if $template_cache{$owner} &&