diff --git a/package-lock.json b/package-lock.json
index 0d0afae..e19501d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,10 +9,9 @@
"version": "1.5.3",
"license": "Apache-2.0",
"dependencies": {
- "@types/chosen-js": "^1.8.6",
- "chosen-js": "^1.8.7",
"jquery": "^4.0.0",
"jquery-ui-dist": "^1.13.3",
+ "tom-select": "^2.6.0",
"vss-web-extension-sdk": "^5.141.0"
},
"devDependencies": {
@@ -87,6 +86,21 @@
"node": ">= 8"
}
},
+ "node_modules/@orchidjs/sifter": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@orchidjs/sifter/-/sifter-1.1.0.tgz",
+ "integrity": "sha512-mYwHCfr736cIWWdhhSZvDbf90AKt2xyrJspKFC3qyIJG1LtrJeJunYEqCGG4Aq2ijENbc4WkOjszcvNaIAS/pQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@orchidjs/unicode-variants": "^1.1.2"
+ }
+ },
+ "node_modules/@orchidjs/unicode-variants": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@orchidjs/unicode-variants/-/unicode-variants-1.1.2.tgz",
+ "integrity": "sha512-5DobW1CHgnBROOEpFlEXytED5OosEWESFvg/VYmH0143oXcijYTprRYJTs+55HzGM4IqxiLFSuqEzu9mPNwVsA==",
+ "license": "Apache-2.0"
+ },
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@@ -98,15 +112,6 @@
"node": ">=14"
}
},
- "node_modules/@types/chosen-js": {
- "version": "1.8.6",
- "resolved": "https://registry.npmjs.org/@types/chosen-js/-/chosen-js-1.8.6.tgz",
- "integrity": "sha512-ql+NU3FvB7o4CbUwbDKwhTRsZ+9UATyuUl4DjYudT5q9JNlrGtHg9vyAGLjRs1BraoNhenTQTTIn1382CgssQA==",
- "license": "MIT",
- "dependencies": {
- "@types/jquery": "*"
- }
- },
"node_modules/@types/jquery": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-4.0.0.tgz",
@@ -634,12 +639,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/chosen-js": {
- "version": "1.8.7",
- "resolved": "https://registry.npmjs.org/chosen-js/-/chosen-js-1.8.7.tgz",
- "integrity": "sha512-eVdrZJ2U5ISdObkgsi0od5vIJdLwq1P1Xa/Vj/mgxkMZf14DlgobfB6nrlFi3kW4kkvKLsKk4NDqZj1MU1DCpw==",
- "license": "MIT"
- },
"node_modules/clipboardy": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-4.0.0.tgz",
@@ -3558,6 +3557,23 @@
"node": ">=8.0"
}
},
+ "node_modules/tom-select": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/tom-select/-/tom-select-2.6.0.tgz",
+ "integrity": "sha512-o2ToBjhUAnrrQvW/hrY9c//TpOpAKYSlfuFnf0DIwNy+ua+mmYnsF4PxN/PpzBfUIfEFkNYAngeGBfOAZWF3tw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@orchidjs/sifter": "^1.1.0",
+ "@orchidjs/unicode-variants": "^1.1.2"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/tom-select"
+ }
+ },
"node_modules/tracer": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/tracer/-/tracer-0.7.4.tgz",
diff --git a/package.json b/package.json
index a20b5af..cf62859 100644
--- a/package.json
+++ b/package.json
@@ -26,10 +26,9 @@
"typescript": "^5.9.3"
},
"dependencies": {
- "@types/chosen-js": "^1.8.6",
- "chosen-js": "^1.8.7",
"jquery": "^4.0.0",
"jquery-ui-dist": "^1.13.3",
+ "tom-select": "^2.6.0",
"vss-web-extension-sdk": "^5.141.0"
},
"overrides": {
diff --git a/sites/widget-configuration.html b/sites/widget-configuration.html
index fb9f8a2..d0884db 100644
--- a/sites/widget-configuration.html
+++ b/sites/widget-configuration.html
@@ -4,10 +4,10 @@
-
+
-
+
diff --git a/src/DashboardWidgetExtension/WidgetConfiguration.ts b/src/DashboardWidgetExtension/WidgetConfiguration.ts
index 65c667f..990a87a 100644
--- a/src/DashboardWidgetExtension/WidgetConfiguration.ts
+++ b/src/DashboardWidgetExtension/WidgetConfiguration.ts
@@ -14,6 +14,8 @@ import NotificationUtils from '../Utils/NotificationUtils';
import {ExtensionSetting} from "../Settings/ExtensionSetting";
import UiUtils = require('../Utils/UiUtils');
+declare var TomSelect: any;
+
export class Configuration {
private projectSettings: ProjectSettings = null;
private organizationSettings: Settings = null;
@@ -34,6 +36,10 @@ export class Configuration {
private testGapCheckbox = $('#show-test-gap');
private separateTgaServerCheckbox = $('#separate-tga-server');
+ private tsProjectSelect: any;
+ private tsTgaProjectSelect: any;
+ private tsBaselineSelect: any;
+
private widgetHelpers: any;
private readonly notificationService: any;
private readonly controlService: any;
@@ -63,10 +69,15 @@ export class Configuration {
this.separateTgaServerCheckbox.prop('checked', this.widgetSettings.useSeparateTgaServer);
}
this.zipTgaConfiguration();
- $('#teamscale-project-select').chosen({width: '100%'}).on('change',
- () => this.fillDropdownWithTeamscaleBaselines(notifyWidgetChange));
- $('#teamscale-tga-project-select').chosen({width: '100%'}).on('change', notifyWidgetChange);
- $('#ts-baseline-select').chosen({width: '95%'}).on('change', notifyWidgetChange);
+
+ this.tsProjectSelect = new TomSelect('#teamscale-project-select', {});
+ this.tsProjectSelect.on('change', () => this.fillDropdownWithTeamscaleBaselines(notifyWidgetChange));
+
+ this.tsTgaProjectSelect = new TomSelect('#teamscale-tga-project-select', {});
+ this.tsTgaProjectSelect.on('change', notifyWidgetChange);
+
+ this.tsBaselineSelect = new TomSelect('#ts-baseline-select', {});
+ this.tsBaselineSelect.on('change', notifyWidgetChange);
this.loadAndCheckConfiguration().then(() => this.fillDropdownsWithProjects())
.then(() => this.fillDropdownWithTeamscaleBaselines(notifyWidgetChange))
@@ -129,12 +140,8 @@ export class Configuration {
}
private handleMissingTgaServerConfig() {
- const element = document.createElement('option');
- element.textContent = 'Error: No TGA server configured. Deactivate separate Server option or' +
- ' configure TGA Server.';
- this.teamscaleTgaProjectSelect.appendChild(element);
- $('#' + this.teamscaleTgaProjectSelect.id).prop('disabled', true);
- $('#' + this.teamscaleTgaProjectSelect.id).trigger('chosen:updated');
+ this.tsTgaProjectSelect.addOption({value: '', text: 'Error: No TGA server configured. Deactivate separate Server option or configure TGA Server.'});
+ this.tsTgaProjectSelect.disable();
return Promise.resolve();
}
@@ -149,7 +156,7 @@ export class Configuration {
* Loads a list of accessible projects from the Teamscale server and appends them to the TQE dropdown menu.
*/
private async fillTqeDropdownWithProjects() {
- return this.fillDropdownWithProjects(this.teamscaleClient, this.teamscaleProjectSelect, '#teamscale-project-select');
+ return this.fillDropdownWithProjects(this.teamscaleClient, this.tsProjectSelect, 'teamscaleProject');
}
/**
@@ -164,13 +171,13 @@ export class Configuration {
}
this.tgaTeamscaleClient = new TeamscaleClient(tgaUrl);
}
- return this.fillDropdownWithProjects(this.tgaTeamscaleClient, this.teamscaleTgaProjectSelect, '#teamscale-tga-project-select');
+ return this.fillDropdownWithProjects(this.tgaTeamscaleClient, this.tsTgaProjectSelect, 'tgaTeamscaleProject');
}
/**
* Loads a list of accessible projects from the Teamscale server and appends them to the dropdown menu.
*/
- private async fillDropdownWithProjects(teamscaleClient: TeamscaleClient, selectElement: HTMLSelectElement, selectElementId: string) {
+ private async fillDropdownWithProjects(teamscaleClient: TeamscaleClient, tomSelect: any, settingsKey: string) {
let projects: string[];
try {
projects = await teamscaleClient.retrieveTeamscaleProjects();
@@ -179,17 +186,14 @@ export class Configuration {
return Promise.reject(error);
}
+ tomSelect.clearOptions();
for (const project of projects) {
- const element = document.createElement('option');
- element.textContent = project;
- element.value = project;
- if (this.widgetSettings) {
- element.selected = this.widgetSettings.teamscaleProject === project;
- }
- selectElement.appendChild(element);
+ tomSelect.addOption({value: project, text: project});
}
- $(selectElementId).trigger('chosen:updated');
+ if (this.widgetSettings && this.widgetSettings[settingsKey]) {
+ tomSelect.setValue(this.widgetSettings[settingsKey], true);
+ }
}
/**
@@ -197,7 +201,7 @@ export class Configuration {
*/
private async fillDropdownWithTeamscaleBaselines(notifyWidgetChange) {
// use input value and not widgetSetting Object which might hold an outdated project name
- // since the chosen change event of the project selector is fired before the settings object update
+ // since the change event of the project selector is fired before the settings object update
const teamscaleProject: string = this.teamscaleProjectSelect.value;
let baselines: ITeamscaleBaseline[];
@@ -209,26 +213,22 @@ export class Configuration {
return Promise.reject(error);
}
- while (this.teamscaleBaselineSelect.firstChild) {
- this.teamscaleBaselineSelect.removeChild(this.teamscaleBaselineSelect.firstChild);
- }
+ this.tsBaselineSelect.clearOptions();
this.disableBaselineDropdownForProjectsWithoutBaselines(baselines, teamscaleProject);
for (const baseline of baselines) {
- const element = document.createElement('option');
const date = new Date(baseline.timestamp);
- element.textContent = baseline.name + ' (' + date.toLocaleDateString() + ')';
- element.value = baseline.name;
- if (this.widgetSettings) {
- element.selected = this.widgetSettings.tsBaseline === baseline.name;
- }
- this.teamscaleBaselineSelect.appendChild(element);
+ const text = baseline.name + ' (' + date.toLocaleDateString() + ')';
+ this.tsBaselineSelect.addOption({value: baseline.name, text: text});
+ }
+
+ if (this.widgetSettings && this.widgetSettings.tsBaseline) {
+ this.tsBaselineSelect.setValue(this.widgetSettings.tsBaseline, true);
}
- // update widget settings to get rid of a baseline which belongs to the formally chosen project
+ // update widget settings to get rid of a baseline which belongs to the formerly chosen project
this.getAndUpdateCustomSettings();
- $('#ts-baseline-select').trigger('chosen:updated');
notifyWidgetChange();
}
@@ -237,12 +237,10 @@ export class Configuration {
*/
private disableBaselineDropdownForProjectsWithoutBaselines(baselines: ITeamscaleBaseline[], teamscaleProject: string) {
if (baselines.length === 0) {
- const element = document.createElement('option');
- element.textContent = 'No baseline configured for project »' + teamscaleProject + '«';
- this.teamscaleBaselineSelect.appendChild(element);
- $('#ts-baseline-select').prop('disabled', true);
+ this.tsBaselineSelect.addOption({value: '', text: 'No baseline configured for project »' + teamscaleProject + '«'});
+ this.tsBaselineSelect.disable();
} else {
- $('#ts-baseline-select').prop('disabled', false);
+ this.tsBaselineSelect.enable();
}
}
diff --git a/tsconfig.json b/tsconfig.json
index 1a07241..3b91fdd 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -9,8 +9,7 @@
"rootDir": "src/",
"outDir": "dist/",
"types": [
- "vss-web-extension-sdk",
- "chosen-js"
+ "vss-web-extension-sdk"
],
"lib": [ "es2015", "dom" ]
}
diff --git a/vss-extension.json b/vss-extension.json
index c4eb028..dfbe9a0 100644
--- a/vss-extension.json
+++ b/vss-extension.json
@@ -168,14 +168,14 @@
"packagePath": "lib/VSS.SDK.min.js"
},
{
- "path": "node_modules/chosen-js/chosen.jquery.min.js",
+ "path": "node_modules/tom-select/dist/js/tom-select.complete.min.js",
"addressable": true,
- "packagePath": "lib/chosen.jquery.min.js"
+ "packagePath": "lib/tom-select.complete.min.js"
},
{
- "path": "node_modules/chosen-js/chosen.min.css",
+ "path": "node_modules/tom-select/dist/css/tom-select.default.min.css",
"addressable": true,
- "packagePath": "styles/chosen.min.css"
+ "packagePath": "styles/tom-select.default.min.css"
},
{
"path": "node_modules/jquery/dist/jquery.min.js",
@@ -197,11 +197,6 @@
"addressable": true,
"packagePath": "styles/images/ui-icons_444444_256x240.png"
},
- {
- "path": "node_modules/chosen-js/chosen-sprite.png",
- "addressable": true,
- "packagePath": "styles/chosen-sprite.png"
- },
{
"path": "scripts/require.js",
"addressable": true