33 * Happy about anyone who's able to make this work with imports (i.e. run the tests in this project), but I couldn't figure it out and gave up.
44 */
55
6- export type SupportedApplication = "github" | "gitlab" | "bitbucket-server" | "bitbucket" ;
6+ export type SupportedApplication = "github" | "gitlab" | "bitbucket-server" | "bitbucket" | "azure-devops" ;
77
88const resolveMetaAppName = ( head : HTMLHeadElement ) : string | undefined => {
99 const metaApplication = head . querySelector ( "meta[name=application-name]" ) ;
@@ -18,16 +18,24 @@ const resolveMetaAppName = (head: HTMLHeadElement): string | undefined => {
1818 return undefined ;
1919} ;
2020
21+ export const DEFAULT_HOSTS = [ "github.com" , "gitlab.com" , "bitbucket.org" , "dev.azure.com" ] ;
22+
2123/**
2224 * Provides a fast check to see if the current URL is on a supported site.
2325 */
2426export const isSiteSuitable = ( ) : boolean => {
27+ const isWhitelistedHost = DEFAULT_HOSTS . some ( ( host ) => location . host === host ) ;
28+ if ( isWhitelistedHost ) {
29+ return true ;
30+ }
31+
2532 const appName = resolveMetaAppName ( document . head ) ;
2633 if ( ! appName ) {
2734 return false ;
2835 }
2936 const allowedApps = [ "GitHub" , "GitLab" , "Bitbucket" ] ;
30- return allowedApps . includes ( appName ) ;
37+
38+ return allowedApps . some ( ( allowedApp ) => appName . includes ( allowedApp ) ) ;
3139} ;
3240
3341export interface ButtonContributionParams {
@@ -51,7 +59,7 @@ export interface ButtonContributionParams {
5159 /**
5260 * The element in which the button should be inserted.
5361 *
54- * This element will be inserted into teh main document and allows for styling within the original page.
62+ * This element will be inserted into the main document and allows for styling within the original page.
5563 *
5664 * The structure looks like this:
5765 *
@@ -98,6 +106,12 @@ export interface ButtonContributionParams {
98106 * the classnames to remove and add.
99107 */
100108 manipulations ?: { element : string ; remove ?: string ; add ?: string ; style ?: Partial < CSSStyleDeclaration > } [ ] ;
109+
110+ /**
111+ * A function that can be used to transform the URL that should be opened when the Gitpod button is clicked.
112+ * @returns The transformed URL.
113+ */
114+ urlTransformer ?: ( originalURL : string ) => string ;
101115}
102116
103117function createElement (
@@ -113,6 +127,61 @@ function createElement(
113127}
114128
115129export const buttonContributions : ButtonContributionParams [ ] = [
130+ // Azure DevOps
131+ {
132+ id : "ado-repo" ,
133+ exampleUrls : [
134+ // "https://dev.azure.com/services-azure/_git/project2"
135+ ] ,
136+ selector : "div.repos-files-header-commandbar:nth-child(1)" ,
137+ containerElement : createElement ( "div" , { } ) ,
138+ application : "azure-devops" ,
139+ insertBefore : `div.bolt-header-command-item-button:has(button[id^="__bolt-header-command-bar-menu-button"])` ,
140+ manipulations : [
141+ {
142+ element : "div.repos-files-header-commandbar.scroll-hidden" ,
143+ remove : "scroll-hidden" ,
144+ } ,
145+ ] ,
146+ urlTransformer ( originalUrl ) {
147+ const url = new URL ( originalUrl ) ;
148+ if ( url . pathname . includes ( "version=GB" ) ) {
149+ return originalUrl ;
150+ }
151+ // version=GBdevelop
152+ const branchElement = document . evaluate (
153+ "//div[contains(@class, 'version-dropdown')]//span[contains(@class, 'text-ellipsis')]" ,
154+ document ,
155+ null ,
156+ XPathResult . FIRST_ORDERED_NODE_TYPE ,
157+ null ,
158+ ) . singleNodeValue ;
159+ if ( branchElement ) {
160+ const branch = branchElement . textContent ?. trim ( ) ;
161+ url . searchParams . set ( "version" , `GB${ branch } ` ) ;
162+ }
163+
164+ return url . toString ( ) ;
165+ } ,
166+ } ,
167+ {
168+ id : "ado-pr" ,
169+ exampleUrls : [
170+ // "https://dev.azure.com/services-azure/test-project/_git/repo2/pullrequest/1"
171+ ] ,
172+ selector : ".repos-pr-header > div:nth-child(2) > div:nth-child(1)" ,
173+ containerElement : createElement ( "div" , { } ) ,
174+ application : "azure-devops" ,
175+ insertBefore : `div.bolt-header-command-item-button:has(button[id^="__bolt-menu-button-"])` ,
176+ } ,
177+ {
178+ id : "ado-repo-empty" ,
179+ exampleUrls : [ ] ,
180+ selector : "div.clone-with-application" ,
181+ application : "azure-devops" ,
182+ containerElement : createElement ( "div" , { marginLeft : "4px" , marginRight : "4px" } ) ,
183+ } ,
184+
116185 // GitLab
117186 {
118187 id : "gl-repo" , // also taking care of branches
0 commit comments