diff --git a/app/client/models/ColumnToMap.ts b/app/client/models/ColumnToMap.ts index 48638e53..d7432cf9 100644 --- a/app/client/models/ColumnToMap.ts +++ b/app/client/models/ColumnToMap.ts @@ -13,7 +13,7 @@ export class ColumnToMapImpl implements Required { public description: string; // If column is optional (used only on the UI). public optional: boolean; - // Type of the column that widget expects. + // Type of the column that widget expects. Might be a single or a comma separated list of types. public type: string; // Description of the type (used to show a placeholder). public typeDesc: string; @@ -33,7 +33,7 @@ export class ColumnToMapImpl implements Required { * Does the column type matches this definition. */ public canByMapped(pureType: string) { - return pureType === this.type + return this.type.split(',').includes(pureType) || pureType === "Any" || this.type === "Any"; } diff --git a/test/nbrowser/CustomWidgetsConfig.ts b/test/nbrowser/CustomWidgetsConfig.ts index e480b243..63941ee8 100644 --- a/test/nbrowser/CustomWidgetsConfig.ts +++ b/test/nbrowser/CustomWidgetsConfig.ts @@ -244,6 +244,10 @@ describe('CustomWidgetsConfig', function () { const text = await this._read('#onRecords'); return JSON.parse(text || 'null'); } + public async onRecord() { + const text = await this._read('#onRecord'); + return JSON.parse(text || 'null'); + } public async onRecordsMappings() { const text = await this._read('#onRecordsMappings'); return JSON.parse(text || 'null'); @@ -572,6 +576,66 @@ describe('CustomWidgetsConfig', function () { await revert(); }); + it('should support multiple types in mappings', async () => { + const revert = await gu.begin(); + await toggleWidgetMenu(); + await clickOption(CUSTOM_URL); + await gu.setWidgetUrl( + createConfigUrl({ + columns: [ + {name: 'M1', type: 'Date,DateTime'}, + {name: 'M2', type: 'Date,DateTime', allowMultiple: true}, + ], + requiredAccess: 'read table', + }) + ); + await accept(); + await widget.waitForFrame(); + // Add B=Date, C=DateTime, D=Numeric + await gu.sendActions([ + ['AddVisibleColumn', 'Table1', 'B', {type: 'Any'}], + ['AddVisibleColumn', 'Table1', 'C', {type: 'Date'}], + ['AddVisibleColumn', 'Table1', 'D', {type: 'DateTime'}], + ['AddVisibleColumn', 'Table1', 'E', {type: 'Numeric'}], + // Add sample record. + ['UpdateRecord', 'Table1', 1, {C: '2019-01-01', D: '2019-01-01 12:00', E: 1}] + ]); + + await gu.selectSectionByTitle('Widget'); + // Make sure we have no mappings + assert.deepEqual(await widget.onRecordsMappings(), null); + // Now see what we are offered for M1. + await toggleDrop(pickerDrop('M1')); + assert.deepEqual(await getOptions(), ['B', 'C', 'D']); + // Make sure they work. First select C. + await clickOption('B'); + // Make sure onRecord and onRecordMappings looks legit. + assert.deepEqual(await widget.onRecord(), {id:1, B: null}); + assert.deepEqual(await widget.onRecordMappings(), {M1: 'B', M2: []}); + // Now select C. + await toggleDrop(pickerDrop('M1')); + await clickOption('C'); + assert.deepEqual(await widget.onRecord(), {id:1, C: '2019-01-01T00:00:00.000Z'}); + assert.deepEqual(await widget.onRecordMappings(), {M1: 'C', M2: []}); + // Now select D. + await toggleDrop(pickerDrop('M1')); + await clickOption('D'); + assert.deepEqual(await widget.onRecord(), {id:1, D: '2019-01-01T17:00:00.000Z'}); + assert.deepEqual(await widget.onRecordMappings(), {M1: 'D', M2: []}); + + // Make sure we can select multiple columns for M2 with Date and DateTime. + await click(pickerAdd('M2')); + assert.deepEqual(await getMenuOptions(), ['B', 'C', 'D']); + await clickMenuItem('B'); + + assert.deepEqual(await widget.onRecordMappings(), {M1: 'D', M2: ['B']}); + await click(pickerAdd('M2')); + await clickMenuItem('C'); + assert.deepEqual(await widget.onRecordMappings(), {M1: 'D', M2: ['B', 'C']}); + + await revert(); + }); + it('should remove mapping when column is deleted', async () => { const revert = await gu.begin(); await toggleWidgetMenu();