import {IdlService, IdlObject} from '@eg/core/idl.service';
import {Observable} from 'rxjs';
import {map} from 'rxjs/operators';
-import {AuthService} from '@eg/core/auth.service';
import {PcrudService} from '@eg/core/pcrud.service';
import {OrgService} from '@eg/core/org.service';
import {DialogComponent} from '@eg/share/dialog/dialog.component';
constructor(
private modal: NgbModal, // required for passing to parent
private idl: IdlService,
- private auth: AuthService,
private toast: ToastService,
private format: FormatService,
private org: OrgService,
--- /dev/null
+import { IdlService } from "@eg/core/idl.service";
+import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
+import { ToastService } from "@eg/share/toast/toast.service";
+import { FmRecordEditorComponent } from "./fm-editor.component"
+import { FormatService } from "@eg/core/format.service";
+import { OrgService } from "@eg/core/org.service";
+import { PcrudService } from "@eg/core/pcrud.service";
+import { waitForAsync } from "@angular/core/testing";
+import { of } from "rxjs";
+
+describe('FmRecordEditorComponent', () => {
+ let component: FmRecordEditorComponent;
+ const mockPcrud = jasmine.createSpyObj<PcrudService>(['retrieve']);
+ beforeEach(() => {
+ const mockModal = jasmine.createSpyObj<NgbModal>(['open']);
+ const mockIdl = jasmine.createSpyObj<IdlService>(['pkeyMatches', 'getClassSelector', 'sortIdlFields'], {classes: {
+ 'mock': {
+ label: 'Mock Class',
+ fields: [
+ {datatype: 'link', name: 'linked_field', class: 'linked'}
+ ]
+ },
+ 'linked': {pkey: 'id'}
+ }});
+ mockIdl.pkeyMatches.and.returnValue(true);
+ mockIdl.getClassSelector.and.returnValue('label');
+ const mockToast = jasmine.createSpyObj<ToastService>(['success']);
+ const mockFormat = jasmine.createSpyObj<FormatService>([], {wsOrgTimezone: 'America/Los_Angeles'});
+ const mockOrg = jasmine.createSpyObj<OrgService>(['get']);
+ mockPcrud.retrieve.and.callFake((fmClass, pkey) => {
+ if (fmClass === 'mock') {
+ return of({
+ a: [],
+ classname: 'mock',
+ _isfieldmapper: true,
+ 'linked_field': () => 456
+ });
+ } else {
+ return of({
+ id: () => 456,
+ label: () => 'My Config Value'
+ });
+ }
+ });
+
+ component = new FmRecordEditorComponent(
+ mockModal, mockIdl, mockToast, mockFormat, mockOrg, mockPcrud
+ );
+
+ })
+ describe('hidden fields', () => {
+ it('fetches only one row of linked values', waitForAsync(() => {
+ component.idlClass = 'mock';
+ component.readonlyFields = 'linked_field';
+ component.mode = 'update';
+ component.displayMode = 'inline';
+ component.recordId = 123;
+ component.ngOnInit();
+ // wait for ngOnInit to do its work
+ setTimeout(() => {
+ expect(mockPcrud.retrieve).toHaveBeenCalledWith('mock', 123);
+ expect(mockPcrud.retrieve).toHaveBeenCalledWith('linked', 456);
+ }, 100)
+ }));
+ });
+});
<button type="button" class="btn-close btn-close-white"
i18n-aria-label aria-label="Close" (click)="close()"></button>
</div>
- <div class="modal-body p-4 form-validated">
-
- <ng-container *ngIf="mode === 'manage' && copy.notes().length">
- <h4 i18n>Existing Notes</h4>
- <div class="row mt-2 p-2" *ngFor="let note of copy.notes()">
- <div class="col-lg-4">{{note.title()}}</div>
- <div class="col-lg-5">{{note.value()}}</div>
- <div class="col-lg-3">
- <button class="btn btn-outline-danger"
- (click)="removeNote(note)" i18n>Remove</button>
- </div>
- </div>
- <hr/>
+ <div class="modal-body">
+ <ng-container #editDialogContent *ngIf="mode === 'edit' && idToEdit; else manageDialogContent">
+ <eg-copy-notes-edit [recordId]="idToEdit" (doneWithEdits)="returnToManage()">
+ </eg-copy-notes-edit>
</ng-container>
-
- <h4 i18n>New Notes</h4>
- <div class="row mt-2 p-2" *ngFor="let note of newNotes">
- <div class="col-lg-4">{{note.title()}}</div>
- <div class="col-lg-5">{{note.value()}}</div>
- <div class="col-lg-3">
- <button class="btn btn-outline-danger" (click)="removeNote(note)" i18n>
- Remove
- </button>
- </div>
- </div>
-
- <div class="row mt-2 p-2 rounded border border-success">
- <div class="col-lg-12">
- <div class="row">
- <div class="col-lg-6">
- <input type="text" class="form-control" [(ngModel)]="curNoteTitle"
- i18n-placeholder placeholder="Note title..."/>
- </div>
- <div class="col-lg-6">
- <div class="form-check">
- <input class="form-check-input" type="checkbox"
- [(ngModel)]="curNotePublic" id="pub-check">
- <label class="form-label form-check-label" for="pub-check">Public Note</label>
+ <ng-template #manageDialogContent>
+ <div class="p-4 form-validated">
+ <ng-container *ngIf="mode === 'manage' && copy.notes().length">
+ <h4 i18n>Existing Notes</h4>
+ <div class="row mt-2 p-2" *ngFor="let note of copy.notes()">
+ <div class="col-lg-3">{{note.title()}}</div>
+ <div class="col-lg-5">{{note.value()}}</div>
+ <div class="col-lg-2">
+ <button class="btn btn-outline-info" (click)="editNote(note)" i18n>
+ Edit
+ </button>
+ </div>
+ <div class="col-lg-2">
+ <button class="btn btn-outline-danger"
+ (click)="removeNote(note)" i18n>Remove</button>
</div>
</div>
- </div>
- <div class="row mt-3">
- <div class="col-lg-9">
- <textarea class="form-control" [(ngModel)]="curNote"
- i18n-placeholder placeholder="Enter note value..."></textarea>
+ <hr/>
+ </ng-container>
+
+ <h4 i18n>New Notes</h4>
+ <div class="row mt-2 p-2" *ngFor="let note of newNotes">
+ <div class="col-lg-3">{{note.title()}}</div>
+ <div class="col-lg-7">{{note.value()}}</div>
+ <div class="col-lg-2">
+ <button class="btn btn-outline-danger" (click)="removeNote(note)" i18n>
+ Remove
+ </button>
</div>
- <div class="col-lg-3">
- <button class="btn btn-success" (click)="addNew()" i18n>Add Note</button>
+ </div>
+
+ <div class="row mt-2 p-2 rounded border border-success">
+ <div class="col-lg-12">
+ <div class="row">
+ <div class="col-lg-6">
+ <input type="text" class="form-control" [(ngModel)]="curNoteTitle"
+ i18n-placeholder placeholder="Note title..."/>
+ </div>
+ <div class="col-lg-6">
+ <div class="form-check">
+ <input class="form-check-input" type="checkbox"
+ [(ngModel)]="curNotePublic" id="pub-check">
+ <label class="form-label form-check-label" for="pub-check">Public Note</label>
+ </div>
+ </div>
+ </div>
+ <div class="row mt-3">
+ <div class="col-lg-9">
+ <textarea class="form-control" [(ngModel)]="curNote"
+ i18n-placeholder placeholder="Enter note value..."></textarea>
+ </div>
+ <div class="col-lg-3">
+ <button class="btn btn-success" (click)="addNew()" i18n>Add Note</button>
+ </div>
+ </div>
</div>
</div>
</div>
- </div>
+ </ng-template>
</div>
- <div class="modal-footer">
+
+ <div class="modal-footer" *ngIf="mode !== 'edit'">
<button type="button" class="btn btn-secondary" (click)="close()" i18n>Cancel</button>
<button class="btn btn-success me-2" (click)="applyChanges()" i18n>Apply Changes</button>
</div>
// If there is only one copyId, then notes may be applied or removed.
@Input() copyIds: number[] = [];
- mode: string; // create | manage
+ mode: string; // create | manage | edit
// If true, no attempt is made to save the new notes to the
// database. It's assumed this takes place in the calling code.
autoId = -1;
+ idToEdit: number;
+
@ViewChild('successMsg', { static: true }) private successMsg: StringComponent;
@ViewChild('errorMsg', { static: true }) private errorMsg: StringComponent;
});
}
+ editNote(note: IdlObject) {
+ this.idToEdit = note.id();
+ this.mode = 'edit';
+ }
+
+ returnToManage() {
+ this.getCopies().then(() => {
+ this.idToEdit = null;
+ this.mode = 'manage';
+ })
+ }
+
removeNote(note: IdlObject) {
this.newNotes = this.newNotes.filter(t => t.id() !== note.id());
--- /dev/null
+<button class="btn btn-info label-with-material-icon" (click)="doneWithEdits.emit()">
+ <span class="material-icons" aria-hidden="true">arrow_back</span>
+ <span i18n>Back</span>
+</button>
+<eg-fm-record-editor #fmRecordEditor
+ (recordSaved)="doneWithEdits.emit()"
+ idlClass="acpn" mode="update"
+ hiddenFields="create_date,owning_copy,id,creator"
+ [hideBanner]="true"
+ displayMode="inline" fieldOrder="title,value,pub" [recordId]="recordId">
+</eg-fm-record-editor>
+
--- /dev/null
+import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CopyNotesEditComponent } from './copy-notes-edit.component';
+
+describe('CopyNotesEditComponent', () => {
+ let component: CopyNotesEditComponent;
+ let fixture: ComponentFixture<CopyNotesEditComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ CopyNotesEditComponent ],
+ schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CopyNotesEditComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+ describe('back button', () => {
+ it('emits an event on click', () => {
+ spyOn(component.doneWithEdits, 'emit');
+ const generatedElement: HTMLElement = fixture.nativeElement;
+ const buttonElement: HTMLButtonElement = generatedElement.querySelector('button');
+ buttonElement.dispatchEvent(new Event('click'));
+ fixture.detectChanges();
+ expect(component.doneWithEdits.emit).toHaveBeenCalled();
+ })
+ })
+});
--- /dev/null
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+
+@Component({
+ selector: 'eg-copy-notes-edit',
+ templateUrl: './copy-notes-edit.component.html',
+})
+export class CopyNotesEditComponent {
+
+ constructor() { }
+
+ @Input() recordId: number;
+ @Output() doneWithEdits: EventEmitter<any> = new EventEmitter();
+}
import {TransferHoldingsComponent} from './transfer-holdings.component';
import {BatchItemAttrComponent} from './batch-item-attr.component';
import {CopyAlertManagerDialogComponent} from './copy-alert-manager.component';
+import {CopyNotesEditComponent} from './copy-notes-edit/copy-notes-edit.component';
+import { FmRecordEditorModule } from '@eg/share/fm-editor/fm-editor.module';
@NgModule({
declarations: [
CopyAlertsDialogComponent,
CopyTagsDialogComponent,
CopyNotesDialogComponent,
+ CopyNotesEditComponent,
ReplaceBarcodeDialogComponent,
DeleteHoldingDialogComponent,
ConjoinedItemsDialogComponent,
],
imports: [
StaffCommonModule,
- BillingModule
+ BillingModule,
+ FmRecordEditorModule
],
exports: [
MarkDamagedDialogComponent,