1
1
// Copyright (c) Jupyter Development Team.
2
2
// Distributed under the terms of the Modified BSD License.
3
3
4
+ import {
5
+ find
6
+ } from '@phosphor/algorithm' ;
7
+
4
8
import {
5
9
PanelLayout , Widget
6
10
} from '@phosphor/widgets' ;
@@ -21,9 +25,22 @@ import {
21
25
GitHubDrive
22
26
} from './contents' ;
23
27
28
+
29
+ /**
30
+ * The base url for a mybinder deployment.
31
+ */
24
32
const MY_BINDER_BASE_URL = 'https://mybinder.org/v2/gh' ;
33
+
34
+ /**
35
+ * The GitHub base url.
36
+ */
25
37
const GITHUB_BASE_URL = 'https://github.com' ;
26
38
39
+ /**
40
+ * The className for disabling the mybinder button.
41
+ */
42
+ const MY_BINDER_DISABLED = 'jp-MyBinderButton-disabled' ;
43
+
27
44
/**
28
45
* Widget for hosting the GitHub filebrowser.
29
46
*/
@@ -37,18 +54,27 @@ class GitHubFileBrowser extends Widget {
37
54
this . _browser = browser ;
38
55
this . _drive = drive ;
39
56
57
+ // Create an editable name for the user/org name.
40
58
this . userName = new GitHubEditableName ( drive . user , '<Edit User>' ) ;
41
59
this . userName . addClass ( 'jp-GitHubEditableUserName' ) ;
42
60
this . userName . node . title = 'Click to edit user/organization' ;
43
61
this . _browser . toolbar . addItem ( 'user' , this . userName ) ;
44
62
this . userName . name . changed . connect ( this . _onUserChanged , this ) ;
45
63
46
- const openGitHubButton = new ToolbarButton ( {
64
+ // Create a button that opens GitHub at the appropriate
65
+ // repo+directory.
66
+ this . _openGitHubButton = new ToolbarButton ( {
47
67
onClick : ( ) => {
68
+ let url = GITHUB_BASE_URL ;
69
+ // If there is no valid user, do nothing.
70
+ if ( ! this . _drive . validUserState . get ( ) ) {
71
+ window . open ( url ) ;
72
+ return ;
73
+ }
48
74
const user = this . _drive . user ;
49
75
const path = this . _browser . model . path ;
50
76
const repo = path . split ( '/' ) [ 0 ] . split ( ':' ) [ 1 ] ;
51
- let url = URLExt . join ( GITHUB_BASE_URL , user ) ;
77
+ url = URLExt . join ( url , user ) ;
52
78
if ( repo ) {
53
79
const dirPath = URLExt . join ( repo , ...path . split ( '/' ) . slice ( 1 ) ) ;
54
80
url = URLExt . join ( url , repo , 'tree' , 'master' , dirPath ) ;
@@ -58,10 +84,15 @@ class GitHubFileBrowser extends Widget {
58
84
className : 'jp-GitHubIcon' ,
59
85
tooltip : 'Open this repository on GitHub'
60
86
} ) ;
61
- this . _browser . toolbar . addItem ( 'GitHub' , openGitHubButton ) ;
87
+ this . _browser . toolbar . addItem ( 'GitHub' , this . _openGitHubButton ) ;
62
88
63
- const launchBinderButton = new ToolbarButton ( {
89
+ // Create a button the opens MyBinder to the appropriate repo.
90
+ this . _launchBinderButton = new ToolbarButton ( {
64
91
onClick : ( ) => {
92
+ // If binder is not active for this directory, do nothing.
93
+ if ( ! this . _binderActive ) {
94
+ return ;
95
+ }
65
96
const user = this . _drive . user ;
66
97
const repo = this . _browser . model . path . split ( '/' ) [ 0 ] . split ( ':' ) [ 1 ] ;
67
98
const url = URLExt . join ( MY_BINDER_BASE_URL , user , repo , 'master' ) ;
@@ -70,7 +101,12 @@ class GitHubFileBrowser extends Widget {
70
101
tooltip : 'Launch this repository on mybinder.org' ,
71
102
className : 'jp-MyBinderButton'
72
103
} ) ;
73
- this . _browser . toolbar . addItem ( 'binder' , launchBinderButton ) ;
104
+ this . _browser . toolbar . addItem ( 'binder' , this . _launchBinderButton ) ;
105
+
106
+ // Set up a listener to check if we can launch mybinder.
107
+ this . _browser . model . pathChanged . connect ( this . _onPathChanged , this ) ;
108
+ // Trigger an initial pathChanged to check for binder state.
109
+ this . _onPathChanged ( ) ;
74
110
75
111
this . _drive . rateLimitedState . changed . connect ( this . _updateErrorPanel , this ) ;
76
112
this . _drive . validUserState . changed . connect ( this . _updateErrorPanel , this ) ;
@@ -101,6 +137,40 @@ class GitHubFileBrowser extends Widget {
101
137
} ) ;
102
138
}
103
139
140
+ /**
141
+ * React to the path changing for the browser.
142
+ */
143
+ private _onPathChanged ( ) : void {
144
+ const path = this . _browser . model . path ;
145
+ // Check for a valid user.
146
+ if ( ! this . _drive . validUserState . get ( ) ) {
147
+ this . _launchBinderButton . addClass ( MY_BINDER_DISABLED ) ;
148
+ this . _binderActive = false ;
149
+ return ;
150
+ }
151
+ // Check for a valid repo.
152
+ const repo = path . split ( '/' ) [ 0 ] . split ( ':' ) [ 1 ] ;
153
+ if ( ! repo ) {
154
+ this . _launchBinderButton . addClass ( MY_BINDER_DISABLED ) ;
155
+ this . _binderActive = false ;
156
+ return ;
157
+ }
158
+ // Check for one of the special values indicating we can
159
+ // launch the repository.
160
+ const item = find ( this . _browser . model . items ( ) , i => {
161
+ return i . name === 'requirements.txt' || i . name === 'environment.yml' ||
162
+ i . name === 'apt.txt' || i . name === 'REQUIRE' ||
163
+ i . name === 'Dockerfile' ;
164
+ } ) ;
165
+ if ( item ) {
166
+ this . _launchBinderButton . removeClass ( MY_BINDER_DISABLED ) ;
167
+ this . _binderActive = true ;
168
+ return ;
169
+ }
170
+ this . _launchBinderButton . addClass ( MY_BINDER_DISABLED ) ;
171
+ this . _binderActive = false ;
172
+ }
173
+
104
174
/**
105
175
* React to a change in the validity of the drive.
106
176
*/
@@ -139,6 +209,9 @@ class GitHubFileBrowser extends Widget {
139
209
private _browser : FileBrowser ;
140
210
private _drive : GitHubDrive ;
141
211
private _errorPanel : GitHubErrorPanel | null ;
212
+ private _openGitHubButton : ToolbarButton ;
213
+ private _launchBinderButton : ToolbarButton ;
214
+ private _binderActive = false ;
142
215
}
143
216
144
217
/**
0 commit comments