@Input() public dialogTitle: string;
// Pointer to the dialog content template.
- @ViewChild('dialogContent', {static: false})
- private dialogContent: TemplateRef<any>;
+ @ViewChild('dialogContent', {static: false}) dialogContent: TemplateRef<any>;
identifier: number = DialogComponent.counter++;
--- /dev/null
+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)
+ });
+ });
+});
--- /dev/null
+import * as moment from 'moment-timezone';
+
+export class TimezoneService {
+ validTimezones() {
+ return moment.tz.names();
+ }
+}
</ng-container><!-- fmClass ngSwitch -->
</div>
</ng-container>
+ <ng-container *ngSwitchCase="'timezone'">
+ <div class="input-group">
+ <eg-timezone-select
+ [(ngModel)]="entryValue">
+ </eg-timezone-select>
+ </div>
+ </ng-container>
</ng-container> <!-- input type ngSwitch -->
</div>
(click)="delete()" i18n>Delete Setting</button>
</div>
</ng-template>
-
<ng-template #fmClassLabel let-r="result" i18n>
{{r.label}}
</ng-template>
--- /dev/null
+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<NgbModal>(['open']);
+let component = new EditOuSettingDialogComponent(modal);
+
+@Component({
+ template: `
+ <div>
+ <ng-container *ngTemplateOutlet="modal"> </ng-container>
+ </div>
+ <eg-admin-edit-org-unit-setting-dialog #dialog></eg-admin-edit-org-unit-setting-dialog>
+ `,
+ })
+ class MockModalComponent implements AfterViewInit {
+ @ViewChild('dialog') componentRef: EditOuSettingDialogComponent;
+ modal: TemplateRef<any>;
+ 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);
+ }))
+ });
+});
}
inputType() {
+ if (this.entry.name === 'lib.timezone') {
+ return 'timezone';
+ }
return this.entry.dataType;
}
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,
exports: [
],
providers: [
+ TimezoneService
]
})
--- /dev/null
+<label for="timezone-select" i18n>Timezone</label>
+<eg-combobox domId="timezone-select"
+ [startId]="startId"
+ [entries]="entries"
+ (onChange)="cboxChanged($event)"
+ #combobox>
+</eg-combobox>
--- /dev/null
+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<TimezoneService>(['validTimezones']);
+ service.validTimezones.and.returnValue(['America/Vancouver']);
+ const component = new TimezoneSelectComponent(service);
+ expect(component.entries).toContain({id: 'America/Vancouver', label: 'America/Vancouver'});
+ })
+});
--- /dev/null
+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;
+ }
+}