diff --git a/src/dialog-user/components/dialog-user/dialogUser.ts b/src/dialog-user/components/dialog-user/dialogUser.ts index 6926491445..4e56e288ac 100644 --- a/src/dialog-user/components/dialog-user/dialogUser.ts +++ b/src/dialog-user/components/dialog-user/dialogUser.ts @@ -27,10 +27,11 @@ export class DialogUserController extends DialogClass implements IDialogs { * @param {Object} DialogData factory. */ - /*@ngInject*/ - constructor(private DialogData: any,private $scope : ng.IScope) { + /* @ngInject */ + constructor(private DialogData, private $q) { super(); } + /** * Runs when component is initialized * @memberof DialogUserController @@ -82,6 +83,10 @@ export class DialogUserController extends DialogClass implements IDialogs { data: this.dialogValues }; this.onUpdate({ data: outputData }); + this.service.data = { + fields: this.dialogFields, + values: this.dialogValues, + }; } public validateFields() { @@ -184,13 +189,12 @@ export class DialogUserController extends DialogClass implements IDialogs { promiseList.push(this.refreshSingleField(field)); }); - Promise.all(promiseList).then((_data) => { + this.$q.all(promiseList).then((_data) => { this.refreshRequestCount -= promiseList.length; if (this.refreshRequestCount === 0) { this.areFieldsBeingRefreshed = false; } this.saveDialogData(); - this.$scope.$apply(); }); } @@ -224,7 +228,6 @@ export class DialogUserController extends DialogClass implements IDialogs { this.dialogFields[field].fieldBeingRefreshed = false; this.saveDialogData(); - this.$scope.$apply(); if (! _.isEmpty(this.fieldAssociations[field])) { this.updateTargetedFieldsFrom(field); diff --git a/src/dialog-user/services/dialogData.spec.ts b/src/dialog-user/services/dialogData.spec.ts index 824621854a..e4f86f432d 100644 --- a/src/dialog-user/services/dialogData.spec.ts +++ b/src/dialog-user/services/dialogData.spec.ts @@ -1,5 +1,6 @@ import DialogData from './dialogData'; import * as angular from 'angular'; + const dialogField = { 'href': 'http://localhost:3001/api/service_templates/10000000000015/service_dialogs/10000000007060', 'id': 10000000007060, @@ -465,41 +466,86 @@ describe('DialogDataService test', () => { }); }); - it('should allow a select list to be sorted', () => { - const testDropDown = { - values: [ - [1, 'Test'], - [5, 'Test2'], - [2, 'Test5'] - ], - options: { sort_by: 'value', sort_order: 'descending', data_type: 'integer' } - }; - const testSorted = dialogData.updateFieldSortOrder(testDropDown); - const expectedResult = [[5, 'Test2'], [2, 'Test5'], [1, 'Test']]; - expect(testSorted).toEqual(expectedResult); - const testDropDownDescription = { - values: [ - [1, 'B'], - [5, 'C'], - [2, 'A'] - ], - options: { sort_by: 'description', sort_order: 'descending' } - }; - const testSortedDescription = dialogData.updateFieldSortOrder(testDropDownDescription); - const expectedSortedResult = [[5, 'C'], [1, 'B'], [2, 'A']]; - expect(testSortedDescription).toEqual(expectedSortedResult); + describe('#outputConversion', () => { + beforeEach(() => { + const configuredField = dialogData.setupField({ + name: 'date_1', + type: 'DialogFieldDateControl', + default_value: '2019-10-15', + }); + + dialogData.data = { + fields: { + [configuredField.name]: configuredField, + }, + values: { + [configuredField.name]: configuredField.default_value, + }, + }; + }); + + it('converts Dates to string', () => { + let input = dialogData.data.values; + let output = dialogData.outputConversion(input); + + expect(input === output).toBe(false); // shallow copy + expect(typeof input.date_1).toEqual('object'); // Date + expect(typeof output.date_1).toEqual('string'); + expect(output.date_1).toMatch(/^\d+-\d+-\d+$/); // YYYY-MM-DD + }); + + // this test requires the "local timezone" to be UTC+1 or more + // timezone-mock is not compatible with current karma it seems: + // ERROR [karma]: { inspect: [Function: inspect] } + xit('preserves local timezone', () => { + let input = dialogData.data.values; + input.default_value = new Date('2019-10-15T00:11:22+01:00'); + + let output = dialogData.outputConversion(input); + + expect(input.date_1.getUTCDate()).toEqual(14); // UTC is off by one + expect(output.date_1).toEqual('2019-10-15'); // not 2019-10-14 + }); }); - it('should allow a numeric Description field to be sorted in a dropdown', () => { - const testDropDownDescription = { - values: [ - ['zero', '1'], - ['five', '5'], - ['two', '2'] - ], - options: { sort_by: 'description', sort_order: 'descending' } - }; - const testSortedDescription = dialogData.updateFieldSortOrder(testDropDownDescription); - const expectedSortedResult = [['five', '5'], ['two', '2'], ['zero', '1']]; - expect(testSortedDescription).toEqual(expectedSortedResult); + + describe('#updateFieldSortOrder', () => { + it('should allow a select list to be sorted', () => { + const testDropDown = { + values: [ + [1, 'Test'], + [5, 'Test2'], + [2, 'Test5'] + ], + options: { sort_by: 'value', sort_order: 'descending', data_type: 'integer' } + }; + const testSorted = dialogData.updateFieldSortOrder(testDropDown); + const expectedResult = [[5, 'Test2'], [2, 'Test5'], [1, 'Test']]; + expect(testSorted).toEqual(expectedResult); + const testDropDownDescription = { + values: [ + [1, 'B'], + [5, 'C'], + [2, 'A'] + ], + options: { sort_by: 'description', sort_order: 'descending' } + }; + const testSortedDescription = dialogData.updateFieldSortOrder(testDropDownDescription); + const expectedSortedResult = [[5, 'C'], [1, 'B'], [2, 'A']]; + expect(testSortedDescription).toEqual(expectedSortedResult); + }); + + it('should allow a numeric Description field to be sorted in a dropdown', () => { + const testDropDownDescription = { + values: [ + ['zero', '1'], + ['five', '5'], + ['two', '2'] + ], + options: { sort_by: 'description', sort_order: 'descending' } + }; + const testSortedDescription = dialogData.updateFieldSortOrder(testDropDownDescription); + const expectedSortedResult = [['five', '5'], ['two', '2'], ['zero', '1']]; + expect(testSortedDescription).toEqual(expectedSortedResult); + }); }); }); diff --git a/src/dialog-user/services/dialogData.ts b/src/dialog-user/services/dialogData.ts index b5a675b82e..257a31cbf3 100644 --- a/src/dialog-user/services/dialogData.ts +++ b/src/dialog-user/services/dialogData.ts @@ -1,8 +1,10 @@ import * as _ from 'lodash'; import * as angular from 'angular'; import {__} from '../../common/translateFunction'; +import {sprintf} from 'sprintf-js'; export default class DialogDataService { + public data: any; /** * Sets up and configures properties for a dialog field @@ -246,4 +248,35 @@ export default class DialogDataService { return invalid; } + + // converts the internal representation into the representation parsed by the API + // currently, this means we convert Date instances to strings + public outputConversion(dialogData) { + const dateString = (date) => { + let y = date.getFullYear(), + m = date.getMonth() + 1, + d = date.getDate(); + return sprintf('%04d-%02d-%02d', y, m, d); + }; + + let out = {...dialogData}; + + Object.values(this.data.fields || {}).forEach(({name, type}) => { + let value = out[name]; + + switch (type) { + case 'DialogFieldDateControl': + // server expects 2019-10-20, anything longer gets cut + // converting first to prevent timezone conversions + out[name] = _.isDate(value) ? dateString(value) : null; + break; + case 'DialogFieldDateTimeControl': + // explicit conversion to ISO datetime + out[name] = _.isDate(value) ? value.toISOString() : null; + break; + }; + }); + + return out; + } }