11import * as React from 'react' ;
2- import CodeMirror from 'codemirror' ;
2+ import CodeMirror , { Editor } from 'codemirror' ;
33import 'codemirror/lib/codemirror.css' ;
44import './yaml' ;
55import * as condaHint from './CondaHint' ;
6+ import { IEnvironmentManager } from '../tokens' ;
7+ import { INotification } from 'jupyterlab_toastify' ;
68
79/**
810 * Conda solve properties
@@ -11,59 +13,145 @@ export interface ICondaEnvSolveProps {
1113 quetzUrl : string ;
1214 quetzSolverUrl : string ;
1315 subdir : string ;
14- create ( name : string , explicitList : string ) : void ;
16+ content ?: string ;
17+ expandChannelUrl ?: boolean ;
18+ onContentChange ?( content : string ) : void ;
1519}
1620
1721export const CondaEnvSolve = ( props : ICondaEnvSolveProps ) : JSX . Element => {
18- condaHint . register ( props . quetzUrl ) ;
19-
20- const codemirrorElem = React . useRef ( ) ;
22+ condaHint . register ( props . quetzUrl , props . expandChannelUrl ) ;
23+ const codemirrorElem = React . useRef ( null ) ;
2124
2225 const [ editor , setEditor ] = React . useState ( null ) ;
23- const [ solveState , setSolveState ] = React . useState ( null ) ;
24-
25- async function solve ( ) {
26- const environment_yml = editor . getValue ( ) ;
27- setSolveState ( 'Solving...' ) ;
28- const name = condaHint . getName ( environment_yml ) ;
29- try {
30- const solveResult = await condaHint . fetchSolve (
31- props . quetzUrl ,
32- props . quetzSolverUrl ,
33- props . subdir ,
34- environment_yml
35- ) ;
36- setSolveState ( `Creating environment ${ name } ...` ) ;
37- await props . create ( name , solveResult ) ;
38- setSolveState ( 'Ok' ) ;
39- } catch ( e ) {
40- setSolveState ( `Error: ${ e } ` ) ;
41- }
42- }
4326
4427 React . useEffect ( ( ) => {
4528 if ( editor ) {
29+ if ( props . content !== undefined && props . content !== editor . getValue ( ) ) {
30+ editor . setValue ( props . content ) ;
31+ editor . refresh ( ) ;
32+ }
4633 return ;
4734 }
48- setEditor (
49- CodeMirror ( codemirrorElem . current , {
50- lineNumbers : true ,
51- extraKeys : {
52- 'Ctrl-Space' : 'autocomplete' ,
53- 'Ctrl-Tab' : 'autocomplete'
54- } ,
55- tabSize : 2 ,
56- mode : 'yaml' ,
57- autofocus : true
58- } )
59- ) ;
35+ const newEditor = CodeMirror ( codemirrorElem . current , {
36+ value : props . content || '' ,
37+ lineNumbers : true ,
38+ extraKeys : {
39+ 'Ctrl-Space' : 'autocomplete' ,
40+ 'Ctrl-Tab' : 'autocomplete'
41+ } ,
42+ tabSize : 2 ,
43+ mode : 'yaml' ,
44+ autofocus : true
45+ } ) ;
46+ if ( props . onContentChange ) {
47+ newEditor . on ( 'change' , ( instance : Editor ) =>
48+ props . onContentChange ( instance . getValue ( ) )
49+ ) ;
50+ }
51+ setEditor ( newEditor ) ;
52+
53+ /* Apply lab styles to this codemirror instance */
54+ codemirrorElem . current . childNodes [ 0 ] . classList . add ( 'cm-s-jupyter' ) ;
6055 } ) ;
6156 return (
62- < div style = { { width : '80vw' , maxWidth : '900px' } } >
63- < div ref = { codemirrorElem } > </ div >
64- < div style = { { paddingTop : '8px' } } >
65- < button onClick = { solve } > Create</ button >
66- < span style = { { marginLeft : '16px' } } > { solveState } </ span >
57+ < div
58+ ref = { codemirrorElem }
59+ className = "conda-complete-panel"
60+ onMouseEnter = { ( ) => editor && editor . refresh ( ) }
61+ />
62+ ) ;
63+ } ;
64+
65+ export async function solveAndCreateEnvironment (
66+ environment_yml : string ,
67+ environmentManager : IEnvironmentManager ,
68+ expandChannelUrl : boolean ,
69+ onMessage ?: ( msg : string ) => void
70+ ) : Promise < void > {
71+ const name = condaHint . getName ( environment_yml ) ;
72+ const { quetzUrl, quetzSolverUrl, subdir } = environmentManager ;
73+
74+ let message = 'Solving environment...' ;
75+ onMessage && onMessage ( message ) ;
76+ let toastId = await INotification . inProgress ( message ) ;
77+ try {
78+ const explicitList = await condaHint . fetchSolve (
79+ quetzUrl ,
80+ quetzSolverUrl ,
81+ ( await subdir ( ) ) . subdir ,
82+ environment_yml ,
83+ expandChannelUrl
84+ ) ;
85+ await INotification . update ( {
86+ toastId,
87+ message : 'Environment has been solved.' ,
88+ type : 'success' ,
89+ autoClose : 5000
90+ } ) ;
91+
92+ message = `creating environment ${ name } ...` ;
93+ onMessage && onMessage ( message ) ;
94+ toastId = await INotification . inProgress ( message ) ;
95+ await environmentManager . import ( name , explicitList ) ;
96+
97+ message = `Environment ${ name } created.` ;
98+ onMessage && onMessage ( message ) ;
99+ await INotification . update ( {
100+ toastId,
101+ message,
102+ type : 'success' ,
103+ autoClose : 5000
104+ } ) ;
105+ } catch ( error ) {
106+ onMessage && onMessage ( error . message ) ;
107+ if ( toastId ) {
108+ await INotification . update ( {
109+ toastId,
110+ message : error . message ,
111+ type : 'error' ,
112+ autoClose : 0
113+ } ) ;
114+ }
115+ }
116+ }
117+
118+ export interface ICondaEnvSolveDialogProps {
119+ subdir : string ;
120+ environmentManager : IEnvironmentManager ;
121+ }
122+
123+ export const CondaEnvSolveDialog = (
124+ props : ICondaEnvSolveDialogProps
125+ ) : JSX . Element => {
126+ const [ environment_yml , setEnvironment_yml ] = React . useState ( '' ) ;
127+ const [ solveState , setSolveState ] = React . useState ( null ) ;
128+
129+ return (
130+ < div className = "condaCompleteDialog__panel" >
131+ < div style = { { flexGrow : 1 } } >
132+ < CondaEnvSolve
133+ expandChannelUrl = { false }
134+ subdir = { props . subdir }
135+ quetzUrl = { props . environmentManager . quetzUrl }
136+ quetzSolverUrl = { props . environmentManager . quetzSolverUrl }
137+ onContentChange = { setEnvironment_yml }
138+ />
139+ </ div >
140+ < div style = { { padding : '12px' } } >
141+ < button
142+ onClick = { ( ) =>
143+ solveAndCreateEnvironment (
144+ environment_yml ,
145+ props . environmentManager ,
146+ true ,
147+ setSolveState
148+ )
149+ }
150+ className = "jp-Dialog-button jp-mod-accept jp-mod-styled"
151+ >
152+ Create
153+ </ button >
154+ < span style = { { marginLeft : '12px' } } > { solveState } </ span >
67155 </ div >
68156 </ div >
69157 ) ;
0 commit comments