@@ -14,6 +14,8 @@ import NotificationUtils from '../Utils/NotificationUtils';
1414import { ExtensionSetting } from "../Settings/ExtensionSetting" ;
1515import UiUtils = require( '../Utils/UiUtils' ) ;
1616
17+ declare const TomSelect : any ;
18+
1719export class Configuration {
1820 private projectSettings : ProjectSettings = null ;
1921 private organizationSettings : Settings = null ;
@@ -22,18 +24,19 @@ export class Configuration {
2224
2325 private teamscaleClient : TeamscaleClient = null ;
2426 private tgaTeamscaleClient : TeamscaleClient = null ;
25- private teamscaleTgaProjectSelect = document . getElementById ( 'teamscale-tga-project-select' ) as HTMLSelectElement ;
2627
2728 private notificationUtils : NotificationUtils = null ;
2829 private emailContact : string = '' ;
2930
30- private teamscaleProjectSelect = document . getElementById ( 'teamscale-project-select' ) as HTMLSelectElement ;
31- private teamscaleBaselineSelect = document . getElementById ( 'ts-baseline-select' ) as HTMLSelectElement ;
3231 private baselineDaysInput = document . getElementById ( 'baseline-days-input' ) as HTMLInputElement ;
3332 private datepicker = $ ( '#datepicker' ) ;
3433 private testGapCheckbox = $ ( '#show-test-gap' ) ;
3534 private separateTgaServerCheckbox = $ ( '#separate-tga-server' ) ;
3635
36+ private tsProjectSelect : any ;
37+ private tsTgaProjectSelect : any ;
38+ private tsBaselineSelect : any ;
39+
3740 private widgetHelpers : any ;
3841 private readonly notificationService : any ;
3942 private readonly controlService : any ;
@@ -63,10 +66,15 @@ export class Configuration {
6366 this . separateTgaServerCheckbox . prop ( 'checked' , this . widgetSettings . useSeparateTgaServer ) ;
6467 }
6568 this . zipTgaConfiguration ( ) ;
66- $ ( '#teamscale-project-select' ) . chosen ( { width : '100%' } ) . on ( 'change' ,
67- ( ) => this . fillDropdownWithTeamscaleBaselines ( notifyWidgetChange ) ) ;
68- $ ( '#teamscale-tga-project-select' ) . chosen ( { width : '100%' } ) . on ( 'change' , notifyWidgetChange ) ;
69- $ ( '#ts-baseline-select' ) . chosen ( { width : '95%' } ) . on ( 'change' , notifyWidgetChange ) ;
69+
70+ this . tsProjectSelect = new TomSelect ( '#teamscale-project-select' , { } ) ;
71+ this . tsProjectSelect . on ( 'change' , ( ) => this . fillDropdownWithTeamscaleBaselines ( notifyWidgetChange ) ) ;
72+
73+ this . tsTgaProjectSelect = new TomSelect ( '#teamscale-tga-project-select' , { } ) ;
74+ this . tsTgaProjectSelect . on ( 'change' , notifyWidgetChange ) ;
75+
76+ this . tsBaselineSelect = new TomSelect ( '#ts-baseline-select' , { } ) ;
77+ this . tsBaselineSelect . on ( 'change' , notifyWidgetChange ) ;
7078
7179 this . loadAndCheckConfiguration ( ) . then ( ( ) => this . fillDropdownsWithProjects ( ) )
7280 . then ( ( ) => this . fillDropdownWithTeamscaleBaselines ( notifyWidgetChange ) )
@@ -118,7 +126,7 @@ export class Configuration {
118126 if ( this . separateTgaServerCheckbox . is ( ':checked' ) ) {
119127 displayAttribute = 'block' ;
120128
121- if ( ! this . teamscaleTgaProjectSelect . firstChild ) {
129+ if ( Object . keys ( this . tsTgaProjectSelect . options ) . length === 0 ) {
122130 this . fillTgaDropdownWithProjects ( ) ;
123131 }
124132 }
@@ -129,12 +137,12 @@ export class Configuration {
129137 }
130138
131139 private handleMissingTgaServerConfig ( ) {
132- const element = document . createElement ( ' option' ) ;
133- element . textContent = 'Error: No TGA server configured. Deactivate separate Server option or' +
134- ' configure TGA Server.' ;
135- this . teamscaleTgaProjectSelect . appendChild ( element ) ;
136- $ ( '#' + this . teamscaleTgaProjectSelect . id ) . prop ( 'disabled' , true ) ;
137- $ ( '#' + this . teamscaleTgaProjectSelect . id ) . trigger ( 'chosen:updated' ) ;
140+ const message = 'Error: No TGA server configured. Deactivate separate Server option or configure TGA Server.' ;
141+ this . tsTgaProjectSelect . clear ( true ) ;
142+ this . tsTgaProjectSelect . clearOptions ( ) ;
143+ this . tsTgaProjectSelect . addOption ( { value : message , text : message } ) ;
144+ this . tsTgaProjectSelect . setValue ( message , true ) ;
145+ this . tsTgaProjectSelect . disable ( ) ;
138146 return Promise . resolve ( ) ;
139147 }
140148
@@ -149,7 +157,7 @@ export class Configuration {
149157 * Loads a list of accessible projects from the Teamscale server and appends them to the TQE dropdown menu.
150158 */
151159 private async fillTqeDropdownWithProjects ( ) {
152- return this . fillDropdownWithProjects ( this . teamscaleClient , this . teamscaleProjectSelect , '#teamscale-project-select ' ) ;
160+ return this . fillDropdownWithProjects ( this . teamscaleClient , this . tsProjectSelect , 'teamscaleProject ' ) ;
153161 }
154162
155163 /**
@@ -164,13 +172,13 @@ export class Configuration {
164172 }
165173 this . tgaTeamscaleClient = new TeamscaleClient ( tgaUrl ) ;
166174 }
167- return this . fillDropdownWithProjects ( this . tgaTeamscaleClient , this . teamscaleTgaProjectSelect , '#teamscale-tga-project-select ' ) ;
175+ return this . fillDropdownWithProjects ( this . tgaTeamscaleClient , this . tsTgaProjectSelect , 'tgaTeamscaleProject ' ) ;
168176 }
169177
170178 /**
171179 * Loads a list of accessible projects from the Teamscale server and appends them to the dropdown menu.
172180 */
173- private async fillDropdownWithProjects ( teamscaleClient : TeamscaleClient , selectElement : HTMLSelectElement , selectElementId : string ) {
181+ private async fillDropdownWithProjects ( teamscaleClient : TeamscaleClient , projectSelect : any , settingsKey : string ) {
174182 let projects : string [ ] ;
175183 try {
176184 projects = await teamscaleClient . retrieveTeamscaleProjects ( ) ;
@@ -179,26 +187,31 @@ export class Configuration {
179187 return Promise . reject ( error ) ;
180188 }
181189
190+ projectSelect . clear ( true ) ;
191+ projectSelect . clearOptions ( ) ;
192+ projectSelect . enable ( ) ;
182193 for ( const project of projects ) {
183- const element = document . createElement ( 'option' ) ;
184- element . textContent = project ;
185- element . value = project ;
186- if ( this . widgetSettings ) {
187- element . selected = this . widgetSettings . teamscaleProject === project ;
188- }
189- selectElement . appendChild ( element ) ;
194+ projectSelect . addOption ( { value : project , text : project } ) ;
190195 }
191196
192- $ ( selectElementId ) . trigger ( 'chosen:updated' ) ;
197+ const savedValue = this . widgetSettings && this . widgetSettings [ settingsKey ] ;
198+ if ( savedValue && projects . indexOf ( savedValue ) !== - 1 ) {
199+ projectSelect . setValue ( savedValue , true ) ;
200+ } else if ( projects . length > 0 ) {
201+ projectSelect . setValue ( projects [ 0 ] , true ) ;
202+ }
193203 }
194204
195205 /**
196206 * Loads the list configured baselines for a project from the Teamscale server and appends them to the dropdown menu.
197207 */
198208 private async fillDropdownWithTeamscaleBaselines ( notifyWidgetChange ) {
199209 // use input value and not widgetSetting Object which might hold an outdated project name
200- // since the chosen change event of the project selector is fired before the settings object update
201- const teamscaleProject : string = this . teamscaleProjectSelect . value ;
210+ // since the change event of the project selector is fired before the settings object update
211+ const teamscaleProject : string = this . tsProjectSelect . getValue ( ) ;
212+ if ( ! teamscaleProject ) {
213+ return ;
214+ }
202215
203216 let baselines : ITeamscaleBaseline [ ] ;
204217 try {
@@ -209,43 +222,31 @@ export class Configuration {
209222 return Promise . reject ( error ) ;
210223 }
211224
212- while ( this . teamscaleBaselineSelect . firstChild ) {
213- this . teamscaleBaselineSelect . removeChild ( this . teamscaleBaselineSelect . firstChild ) ;
214- }
215-
216- this . disableBaselineDropdownForProjectsWithoutBaselines ( baselines , teamscaleProject ) ;
225+ this . tsBaselineSelect . clear ( true ) ;
226+ this . tsBaselineSelect . clearOptions ( ) ;
217227
218- for ( const baseline of baselines ) {
219- const element = document . createElement ( 'option' ) ;
220- const date = new Date ( baseline . timestamp ) ;
221- element . textContent = baseline . name + ' (' + date . toLocaleDateString ( ) + ')' ;
222- element . value = baseline . name ;
223- if ( this . widgetSettings ) {
224- element . selected = this . widgetSettings . tsBaseline === baseline . name ;
228+ if ( baselines . length === 0 ) {
229+ const message = 'No baseline configured for project »' + teamscaleProject + '«' ;
230+ this . tsBaselineSelect . addOption ( { value : message , text : message } ) ;
231+ this . tsBaselineSelect . setValue ( message , true ) ;
232+ this . tsBaselineSelect . disable ( ) ;
233+ } else {
234+ this . tsBaselineSelect . enable ( ) ;
235+ for ( const baseline of baselines ) {
236+ const date = new Date ( baseline . timestamp ) ;
237+ const text = baseline . name + ' (' + date . toLocaleDateString ( ) + ')' ;
238+ this . tsBaselineSelect . addOption ( { value : baseline . name , text : text } ) ;
239+ }
240+ if ( this . widgetSettings && this . widgetSettings . tsBaseline ) {
241+ this . tsBaselineSelect . setValue ( this . widgetSettings . tsBaseline , true ) ;
225242 }
226- this . teamscaleBaselineSelect . appendChild ( element ) ;
227243 }
228244
229- // update widget settings to get rid of a baseline which belongs to the formally chosen project
245+ // update widget settings to get rid of a baseline which belongs to the formerly chosen project
230246 this . getAndUpdateCustomSettings ( ) ;
231- $ ( '#ts-baseline-select' ) . trigger ( 'chosen:updated' ) ;
232247 notifyWidgetChange ( ) ;
233248 }
234249
235- /**
236- * Disables the baseline chooser for projects without configured Teamscale baselines.
237- */
238- private disableBaselineDropdownForProjectsWithoutBaselines ( baselines : ITeamscaleBaseline [ ] , teamscaleProject : string ) {
239- if ( baselines . length === 0 ) {
240- const element = document . createElement ( 'option' ) ;
241- element . textContent = 'No baseline configured for project »' + teamscaleProject + '«' ;
242- this . teamscaleBaselineSelect . appendChild ( element ) ;
243- $ ( '#ts-baseline-select' ) . prop ( 'disabled' , true ) ;
244- } else {
245- $ ( '#ts-baseline-select' ) . prop ( 'disabled' , false ) ;
246- }
247- }
248-
249250 /**
250251 * Loads the Teamscale email contact from the organization settings and assures that a Teamscale server url and project
251252 * name is set in the Azure DevOps project settings.
@@ -304,14 +305,14 @@ export class Configuration {
304305 * Read the current configuration as specified in the configuration form. Stores it as class member and returns it.
305306 */
306307 private getAndUpdateCustomSettings ( ) : ITeamscaleWidgetSettings {
307- const teamscaleProject : string = this . teamscaleProjectSelect . value ;
308- const tgaTeamscaleProject : string = this . teamscaleTgaProjectSelect . value ;
308+ const teamscaleProject : string = this . tsProjectSelect ? this . tsProjectSelect . getValue ( ) : '' ;
309+ const tgaTeamscaleProject : string = this . tsTgaProjectSelect ? this . tsTgaProjectSelect . getValue ( ) : '' ;
309310 const baselineDays : number = Number ( this . baselineDaysInput . value ) ;
310311 let startFixedDate : number ;
311312 if ( this . datepicker . datepicker ( 'getDate' ) ) {
312313 startFixedDate = this . datepicker . datepicker ( 'getDate' ) . getTime ( ) ;
313314 }
314- const tsBaseline : string = this . teamscaleBaselineSelect . value ;
315+ const tsBaseline : string = this . tsBaselineSelect ? this . tsBaselineSelect . getValue ( ) : '' ;
315316 const showTestGapBadge : boolean = document . getElementById ( 'show-test-gap' ) . checked ;
316317 const useSeparateTgaServer : boolean = document . getElementById ( 'separate-tga-server' ) . checked ;
317318
0 commit comments