From: Jane Sandberg Date: Sat, 6 May 2023 15:08:20 +0000 (-0700) Subject: lp1754364: example solution X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=refs%2Fheads%2Fuser%2Fsandbergja%2Flp1754364-example-solution;p=working%2FEvergreen.git lp1754364: example solution Signed-off-by: Jane Sandberg --- diff --git a/Open-ILS/src/eg2/src/app/share/dialog/dialog.component.ts b/Open-ILS/src/eg2/src/app/share/dialog/dialog.component.ts index 6f73bd5f24..f8be6611ba 100644 --- a/Open-ILS/src/eg2/src/app/share/dialog/dialog.component.ts +++ b/Open-ILS/src/eg2/src/app/share/dialog/dialog.component.ts @@ -44,8 +44,7 @@ export class DialogComponent implements OnInit { @Input() public dialogTitle: string; // Pointer to the dialog content template. - @ViewChild('dialogContent', {static: false}) - private dialogContent: TemplateRef; + @ViewChild('dialogContent', {static: false}) dialogContent: TemplateRef; identifier: number = DialogComponent.counter++; diff --git a/Open-ILS/src/eg2/src/app/share/util/timezone.service.spec.ts b/Open-ILS/src/eg2/src/app/share/util/timezone.service.spec.ts new file mode 100644 index 0000000000..4b08dbcb3f --- /dev/null +++ b/Open-ILS/src/eg2/src/app/share/util/timezone.service.spec.ts @@ -0,0 +1,13 @@ +import { TimezoneService } from "./timezone.service"; + +describe('TimezoneService', () => { + describe('#validTimezones', () => { + it('includes valid timezones', () => { + expect(new TimezoneService().validTimezones()).toContain('America/Vancouver') + }); + it('does not include duplicate timezones', () => { + const timezones = new TimezoneService().validTimezones(); + expect(timezones.length).toEqual(new Set(timezones).size) + }); + }); +}); diff --git a/Open-ILS/src/eg2/src/app/share/util/timezone.service.ts b/Open-ILS/src/eg2/src/app/share/util/timezone.service.ts new file mode 100644 index 0000000000..a947ce1bd8 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/share/util/timezone.service.ts @@ -0,0 +1,7 @@ +import * as moment from 'moment-timezone'; + +export class TimezoneService { + validTimezones() { + return moment.tz.names(); + } +} diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.html b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.html index b929ac80b0..5dda1b4a3a 100644 --- a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.html +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.html @@ -115,6 +115,13 @@ + +
+ + +
+
@@ -127,7 +134,6 @@ (click)="delete()" i18n>Delete Setting - {{r.label}} diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.spec.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.spec.ts new file mode 100644 index 0000000000..e959cb309b --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.spec.ts @@ -0,0 +1,76 @@ +import { NgbModal } from "@ng-bootstrap/ng-bootstrap"; +import { EditOuSettingDialogComponent } from "./edit-org-unit-setting-dialog.component"; +import { TestBed, waitForAsync } from "@angular/core/testing"; +import { AfterViewInit, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectorRef, Component, TemplateRef, ViewChild } from "@angular/core"; + +const modal = jasmine.createSpyObj(['open']); +let component = new EditOuSettingDialogComponent(modal); + +@Component({ + template: ` +
+ +
+ + `, + }) + class MockModalComponent implements AfterViewInit { + @ViewChild('dialog') componentRef: EditOuSettingDialogComponent; + modal: TemplateRef; + constructor(private cdr: ChangeDetectorRef) {} + ngAfterViewInit() { + this.modal = this.componentRef.dialogContent; + this.cdr.detectChanges(); + } + } + +describe('EditOuSettingDialogComponent', () => { + describe('inputType()', () => { + describe('when setting name is lib.timezone', () => { + it('returns timezone', () => { + const entry = { + name: 'lib.timezone', + dataType: 'string' + }; + component.entry = entry; + expect(component.inputType()).toEqual('timezone'); + }); + }); + describe('when setting dataType is integer', () => { + it('returns integer', () => { + const entry = { + dataType: 'integer' + }; + component.entry = entry; + expect(component.inputType()).toEqual('integer'); + }); + }); + }); + describe('template', () => { + it(('displays a timezone select if the entry is lib.timezone'), waitForAsync(() => { + TestBed.configureTestingModule({ + providers: [ + { provide: NgbModal, useValue: modal} + ], declarations: [ + MockModalComponent, + EditOuSettingDialogComponent + ], schemas: [ + CUSTOM_ELEMENTS_SCHEMA + ] + }).compileComponents(); + const fixture = TestBed.createComponent(MockModalComponent); + const mockModal = fixture.debugElement.componentInstance; + fixture.detectChanges(); + mockModal.ngAfterViewInit(); + let component = mockModal.componentRef; + const entry = { + name: 'lib.timezone', + dataType: 'string' + }; + component.entry = entry; + const editElement: HTMLElement = fixture.nativeElement; + fixture.detectChanges(); + expect(editElement.querySelectorAll('eg-timezone-select').length).toEqual(1); + })) + }); +}); diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.ts index 13ef1799a8..0dd43bb1d3 100644 --- a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.ts @@ -28,6 +28,9 @@ export class EditOuSettingDialogComponent extends DialogComponent { } inputType() { + if (this.entry.name === 'lib.timezone') { + return 'timezone'; + } return this.entry.dataType; } diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.module.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.module.ts index 35a4a0dfa6..bdb0ab3339 100644 --- a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/org-unit-settings.module.ts @@ -7,13 +7,16 @@ import {OuSettingHistoryDialogComponent} from './org-unit-setting-history-dialog import {OrgUnitSettingsRoutingModule} from './org-unit-settings-routing.module'; import {OuSettingJsonDialogComponent} from './org-unit-setting-json-dialog.component'; import {ItemLocationSelectModule} from '@eg/share/item-location-select/item-location-select.module'; +import { TimezoneSelectComponent } from './timezone-select/timezone-select.component'; +import { TimezoneService } from '@eg/share/util/timezone.service'; @NgModule({ declarations: [ OrgUnitSettingsComponent, EditOuSettingDialogComponent, OuSettingHistoryDialogComponent, - OuSettingJsonDialogComponent + OuSettingJsonDialogComponent, + TimezoneSelectComponent ], imports: [ AdminCommonModule, @@ -24,6 +27,7 @@ import {ItemLocationSelectModule} from '@eg/share/item-location-select/item-loca exports: [ ], providers: [ + TimezoneService ] }) diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/timezone-select/timezone-select.component.html b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/timezone-select/timezone-select.component.html new file mode 100644 index 0000000000..251f5de0dd --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/timezone-select/timezone-select.component.html @@ -0,0 +1,7 @@ + + + diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/timezone-select/timezone-select.component.spec.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/timezone-select/timezone-select.component.spec.ts new file mode 100644 index 0000000000..39cef0c39c --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/timezone-select/timezone-select.component.spec.ts @@ -0,0 +1,11 @@ +import { TimezoneService } from '@eg/share/util/timezone.service'; +import { TimezoneSelectComponent } from './timezone-select.component'; + +describe('TimezoneSelectComponent', () => { + it('should have an entry for each valid timezone', () => { + const service = jasmine.createSpyObj(['validTimezones']); + service.validTimezones.and.returnValue(['America/Vancouver']); + const component = new TimezoneSelectComponent(service); + expect(component.entries).toContain({id: 'America/Vancouver', label: 'America/Vancouver'}); + }) +}); diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/timezone-select/timezone-select.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/timezone-select/timezone-select.component.ts new file mode 100644 index 0000000000..1b4ad702c9 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/timezone-select/timezone-select.component.ts @@ -0,0 +1,51 @@ +import { Component, ViewChild, forwardRef } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ComboboxComponent, ComboboxEntry } from '@eg/share/combobox/combobox.component'; +import { TimezoneService } from '@eg/share/util/timezone.service'; + +@Component({ + selector: 'eg-timezone-select', + templateUrl: './timezone-select.component.html', + providers: [{ + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => TimezoneSelectComponent), + multi: true + }] +}) +export class TimezoneSelectComponent implements ControlValueAccessor { + entries: ComboboxEntry[]; + startId: string; + + constructor( + private timezone: TimezoneService + ) { + this.entries = this.timezone.validTimezones().map((timezone) => { + return {id: timezone, label: timezone} + }); + } + + @ViewChild('combobox') combobox: ComboboxComponent; + + writeValue(id: string): void { + if (this.combobox) { + this.combobox.selectedId = id; + } else { + // Too early in the lifecycle + this.startId = id; + } + } + + cboxChanged(entry: ComboboxEntry) { + this.propagateChange(entry?.id); +} + + // Stub functions required by ControlValueAccessor + propagateChange = (_: any) => {}; + propagateTouch = () => {}; + registerOnChange(fn) { + this.propagateChange = fn; + } + registerOnTouched(fn) { + this.propagateTouch = fn; + } +}