<div class="row ml-2 mt-4">
<span class="mr-2" i18n>Add New:</span>
<button class="btn btn-outline-dark mr-2" *ngIf="matchSetType=='biblio'"
- (click)="setNewPointType('attr')" i18n>Record Attribute</button>
+ (click)="newPointType='attr'" i18n>Record Attribute</button>
<button class="btn btn-outline-dark mr-2"
- (click)="setNewPointType('marc')" i18n>MARC Tag and Subfield</button>
+ (click)="newPointType='marc'" i18n>MARC Tag and Subfield</button>
<button class="btn btn-outline-dark mr-2" *ngIf="matchSetType=='authority'"
- (click)="setNewPointType('heading')" i18n>Normalized Authority Heading</button>
+ (click)="newPointType='heading'" i18n>Normalized Authority Heading</button>
<button class="btn btn-outline-dark mr-2"
- (click)="setNewPointType('bool')" i18n>Boolean Operator</button>
+ (click)="newPointType='bool'" i18n>Boolean Operator</button>
</div>
- <div class="row ml-2 mt-4 p-2 border border-secondary" *ngIf="newPointType">
- <div class="col-lg-12 common-form striped-odd form-validated">
- <ng-container *ngIf="newPointType=='attr'">
- <div class="row mb-1">
- <div class="col-lg-3" i18n>Record Attribute:</div>
- <div class="col-lg-4">
- <eg-combobox [entries]="bibAttrDefEntries"
- [required]="true"
- (onChange)="newRecordAttr=$event ? $event.id : ''"
- placeholder="Record Attribute..." i18n-placeholder>
- </eg-combobox>
- </div>
- </div>
- </ng-container>
- <ng-container *ngIf="newPointType=='marc'">
- <div class="row mb-1">
- <div class="col-lg-3" i18n>Tag:</div>
- <div class="col-lg-2">
- <input required type="text" class="form-control" [(ngModel)]="newMarcTag"/>
- </div>
- </div>
- <div class="row mb-1">
- <div class="col-lg-3" i18n>Subfield ‡:</div>
- <div class="col-lg-2">
- <input required type="text" class="form-control" [(ngModel)]="newMarcSf"/>
- </div>
- </div>
- </ng-container>
- <ng-container *ngIf="newPointType=='heading'">
- <div class="row mb-1">
- <div class="col-lg-3" i18n>Normalized Heading:</div>
- <div class="col-lg-2">
- <input type="checkbox" class="form-check-input" checked disabled/>
- </div>
- </div>
- </ng-container>
- <ng-container *ngIf="newPointType!='bool'">
- <div class="row mb-1">
- <div class="col-lg-3">Match Score:</div>
- <div class="col-lg-2">
- <input required type="number" class="form-control"
- [(ngModel)]="newMatchScore" step="0.1"/>
- </div>
- </div>
- <div class="row mb-1">
- <div class="col-lg-3">Negate:</div>
- <div class="col-lg-2">
- <input type="checkbox"
- class="form-check-input" [(ngModel)]="newNegate"/>
- </div>
- </div>
- </ng-container>
- <ng-container *ngIf="newPointType=='bool'">
- <div class="row mb-1">
- <div class="col-lg-3">Operator:</div>
- <div class="col-lg-2">
- <select class="form-control" [(ngModel)]="newBoolOp">
- <option value='AND' i18n>AND</option>
- <option value='OR' i18n>OR</option>
- </select>
- </div>
- </div>
- </ng-container>
- <div class="row mt-2">
- <button class="btn btn-success" (click)="addChildNode()"
- [disabled]="!selectedIsBool()" i18n>
- Add To Selected Node
- </button>
- </div>
- <div class="row mt-2 font-italic">
- <ol i18n>
- <li>Define a new match point using the above fields.</li>
- <li>Select a boolean node in the tree.</li>
- <li>Click the "Add..." button to add the new matchpoint
- as a child of the selected node.</li>
- </ol>
- </div>
- </div>
+ <eg-match-set-new-point #newPoint [pointType]="newPointType">
+ </eg-match-set-new-point>
+ <div class="row mt-2 ml-2" *ngIf="newPointType">
+ <button class="btn btn-success" (click)="addChildNode()"
+ [disabled]="!selectedIsBool()" i18n>
+ Add To Selected Node
+ </button>
+ </div>
+ <div class="row mt-2 ml-2 font-italic" *ngIf="newPointType">
+ <ol i18n>
+ <li>Define a new match point using the above fields.</li>
+ <li>Select a boolean node in the tree.</li>
+ <li>Click the "Add..." button to add the new matchpoint
+ as a child of the selected node.</li>
+ </ol>
</div>
</div>
<div class="col-lg-5">
import {Component, OnInit, ViewChild, AfterViewInit, Input} from '@angular/core';
import {IdlObject, IdlService} from '@eg/core/idl.service';
import {PcrudService} from '@eg/core/pcrud.service';
+import {NetService} from '@eg/core/net.service';
+import {AuthService} from '@eg/core/auth.service';
import {OrgService} from '@eg/core/org.service';
import {Tree, TreeNode} from '@eg/share/tree/tree';
import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
import {StringService} from '@eg/share/string/string.service';
+import {MatchSetNewPointComponent} from './match-set-new-point.component';
@Component({
selector: 'eg-match-set-expression',
tree: Tree;
initDone: boolean;
- matchSetPoints: {[id: string]: IdlObject};
matchSetType: string;
changesMade: boolean;
// Current type of new match point
newPointType: string;
- newRecordAttr: string;
- newMatchScore: number;
- newNegate: boolean;
- newMarcTag: string;
- newMarcSf: string;
- newHeading: string;
- newBoolOp: string;
newId: number;
- bibAttrDefs: IdlObject[];
- bibAttrDefEntries: ComboboxEntry[];
+ @ViewChild('newPoint') newPoint: MatchSetNewPointComponent;
constructor(
private idl: IdlService,
private pcrud: PcrudService,
+ private net: NetService,
+ private auth: AuthService,
private org: OrgService,
private strings: StringService
) {
- this.bibAttrDefs = [];
- this.bibAttrDefEntries = [];
- this.matchSetPoints = {};
this.newId = -1;
}
- ngOnInit() {
-
- this.pcrud.retrieveAll('crad', {order_by: {crad: 'label'}})
- .subscribe(attr => {
- this.bibAttrDefs.push(attr);
- this.bibAttrDefEntries.push({id: attr.name(), label: attr.label()});
- });
- }
+ ngOnInit() {}
refreshTree(): Promise<any> {
if (!this.matchSet_) { return; }
- this.matchSetPoints = {};
return this.pcrud.search('vmsp',
{match_set: this.matchSet_.id()}, {},
const idmap: any = {};
points.forEach(point => {
- // Track the from-database point objects
- this.matchSetPoints[point.id()] = point;
-
point.negate(point.negate() === 't' ? true : false);
point.heading(point.heading() === 't' ? true : false);
+ point.children([]);
const node = new TreeNode({
id: point.id(),
deleteNode() {
this.changesMade = true;
const node = this.tree.selectedNode()
- const point = this.matchSetPoints[node.id];
- if (point) {
- // point won't be cached if it's new during this session.
- point.isdeleted(true);
- }
this.tree.removeNode(node);
}
point.isnew(true);
point.parent(pnode.id);
point.match_set(this.matchSet_.id());
+ point.children([]);
+
+ const ptype = this.newPoint.values.pointType;
- if (this.newPointType === 'bool') {
- point.bool_op(this.newBoolOp);
+ if (ptype === 'bool') {
+ point.bool_op(this.newPoint.values.boolOp);
} else {
- if (this.newPointType == 'attr') {
- point.svf(this.newRecordAttr);
+ if (ptype == 'attr') {
+ point.svf(this.newPoint.values.recordAttr);
- } else if (this.newPointType == 'marc') {
- point.tag(this.newMarcTag);
- point.subfield(this.newMarcSf ? this.newMarcSf : null);
- } else if (this.newPointType == 'heading') {
+ } else if (ptype == 'marc') {
+ point.tag(this.newPoint.values.marcTag);
+ point.subfield(this.newPoint.values.marcSf);
+ } else if (ptype == 'heading') {
point.heading(true);
}
- point.negate(this.newNegate);
- point.quality(this.newMatchScore);
+ point.negate(this.newPoint.values.negate);
+ point.quality(this.newPoint.values.matchScore);
}
const node: TreeNode = new TreeNode({
this.setNodeLabel(node, point).then(() => pnode.children.push(node));
}
- setNewPointType(type_: string) {
- this.newPointType = type_;
- this.newRecordAttr = '';
- this.newMatchScore = 1;
- this.newNegate = false;
- this.newMarcTag = '';
- this.newMarcSf = '';
- this.newBoolOp = 'AND';
- }
-
expressionAsString(): string {
if (!this.tree) { return ''; }
return renderNode(this.tree.rootNode);
}
+ // Server API deletes and recreates the tree on update.
+ // It manages parent/child relationships via the children array.
+ // We only need send the current tree in a form the API recognizes.
saveTree(): Promise<any> {
- // New nodes
- let nodes = this.tree.nodeList()
- .filter(node => node.callerData.point.isnew())
- .map(node => node.callerData.point);
- // Deleted nodes
- nodes = nodes.concat(
- Object.values(this.matchSetPoints)
- .filter(point => point.isdeleted())
- );
+ const compileTree = (node?: TreeNode) => {
+
+ if (!node) { node = this.tree.rootNode; }
+
+ const point = node.callerData.point;
+
+ node.children.forEach(child =>
+ point.children().push(compileTree(child)));
- return this.pcrud.autoApply(nodes)
- .toPromise().then(() => this.refreshTree())
+ return point;
+ };
+
+ const rootPoint: IdlObject = compileTree();
+
+ return this.net.request(
+ 'open-ils.vandelay',
+ 'open-ils.vandelay.match_set.update',
+ this.auth.token(), this.matchSet_.id(), rootPoint
+ ).toPromise().then(
+ ok =>this.refreshTree(),
+ err => console.error(err)
+ );
}
}
--- /dev/null
+<div class="row ml-2 mt-4 p-2 border border-secondary" *ngIf="values.pointType">
+ <div class="col-lg-12 common-form striped-odd form-validated">
+ <ng-container *ngIf="values.pointType=='attr'">
+ <div class="row mb-1">
+ <div class="col-lg-3" i18n>Record Attribute:</div>
+ <div class="col-lg-4">
+ <eg-combobox [entries]="bibAttrDefEntries"
+ [required]="true"
+ (onChange)="values.recordAttr=$event ? $event.id : ''"
+ placeholder="Record Attribute..." i18n-placeholder>
+ </eg-combobox>
+ </div>
+ </div>
+ </ng-container>
+ <ng-container *ngIf="values.pointType=='marc'">
+ <div class="row mb-1">
+ <div class="col-lg-3" i18n>Tag:</div>
+ <div class="col-lg-2">
+ <input required type="text" class="form-control" [(ngModel)]="values.marcTag"/>
+ </div>
+ </div>
+ <div class="row mb-1">
+ <div class="col-lg-3" i18n>Subfield ‡:</div>
+ <div class="col-lg-2">
+ <input required type="text" class="form-control" [(ngModel)]="values.marcSf"/>
+ </div>
+ </div>
+ </ng-container>
+ <ng-container *ngIf="values.pointType=='heading'">
+ <div class="row mb-1">
+ <div class="col-lg-3" i18n>Normalized Heading:</div>
+ <div class="col-lg-2">
+ <input type="checkbox" class="form-check-input" checked disabled/>
+ </div>
+ </div>
+ </ng-container>
+ <ng-container *ngIf="values.pointType!='bool'">
+ <div class="row mb-1">
+ <div class="col-lg-3">Match Score:</div>
+ <div class="col-lg-2">
+ <input required type="number" class="form-control"
+ [(ngModel)]="values.matchScore" step="0.1"/>
+ </div>
+ </div>
+ <div class="row mb-1">
+ <div class="col-lg-3">Negate:</div>
+ <div class="col-lg-2">
+ <input type="checkbox"
+ class="form-check-input" [(ngModel)]="values.negate"/>
+ </div>
+ </div>
+ </ng-container>
+ <ng-container *ngIf="values.pointType=='bool'">
+ <div class="row mb-1">
+ <div class="col-lg-3">Operator:</div>
+ <div class="col-lg-2">
+ <select class="form-control" [(ngModel)]="values.boolOp">
+ <option value='AND' i18n>AND</option>
+ <option value='OR' i18n>OR</option>
+ </select>
+ </div>
+ </div>
+ </ng-container>
+ </div>
+</div>
+
--- /dev/null
+import {Component, OnInit, ViewChild, Output, Input} from '@angular/core';
+import {IdlObject, IdlService} from '@eg/core/idl.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
+
+// Can be used to create match_set_point's and match_set_quality's
+export class MatchSetPointValues {
+ pointType: string;
+ recordAttr: string;
+ matchScore: number;
+ negate: boolean;
+ marcTag: string;
+ marcSf: string;
+ heading: string;
+ boolOp: string;
+}
+
+@Component({
+ selector: 'eg-match-set-new-point',
+ templateUrl: 'match-set-new-point.component.html'
+})
+export class MatchSetNewPointComponent implements OnInit {
+
+ public values: MatchSetPointValues;
+
+ bibAttrDefs: IdlObject[];
+ bibAttrDefEntries: ComboboxEntry[];
+
+ // biblio, authority, quality
+ @Input() set pointType(type_: string) {
+ this.values.pointType = type_;
+ this.values.recordAttr = '';
+ this.values.matchScore = 1;
+ this.values.negate = false;
+ this.values.marcTag = '';
+ this.values.marcSf = '';
+ this.values.boolOp = 'AND';
+ }
+
+ constructor(
+ private idl: IdlService,
+ private pcrud: PcrudService
+ ) {
+ this.values = new MatchSetPointValues();
+ this.bibAttrDefs = [];
+ this.bibAttrDefEntries = [];
+ }
+
+ ngOnInit() {
+ this.pcrud.retrieveAll('crad', {order_by: {crad: 'label'}})
+ .subscribe(attr => {
+ this.bibAttrDefs.push(attr);
+ this.bibAttrDefEntries.push({id: attr.name(), label: attr.label()});
+ });
+ }
+
+ setNewPointType(type_: string) {
+ }
+}
+
import {StaffCommonModule} from '@eg/staff/common.module';
import {CatalogCommonModule} from '@eg/share/catalog/catalog-common.module';
import {HttpClientModule} from '@angular/common/http';
+import {TreeModule} from '@eg/share/tree/tree.module';
import {VandelayRoutingModule} from './routing.module';
import {VandelayService} from './vandelay.service';
import {VandelayComponent} from './vandelay.component';
import {MatchSetListComponent} from './match-set-list.component';
import {MatchSetComponent} from './match-set.component';
import {MatchSetExpressionComponent} from './match-set-expression.component';
-import {TreeModule} from '@eg/share/tree/tree.module';
+import {MatchSetNewPointComponent} from './match-set-new-point.component';
@NgModule({
declarations: [
RecordItemsComponent,
MatchSetListComponent,
MatchSetComponent,
- MatchSetExpressionComponent
+ MatchSetExpressionComponent,
+ MatchSetNewPointComponent
],
imports: [
TreeModule,