@@ -13,7 +13,7 @@ import Message from 'kit/Message';
13
13
import Spinner from 'kit/Spinner' ;
14
14
import { useTheme } from 'kit/Theme' ;
15
15
import { ErrorHandler } from 'kit/utils/error' ;
16
- import { Loadable , Loaded , NotLoaded } from 'kit/utils/loadable' ;
16
+ import { Loadable } from 'kit/utils/loadable' ;
17
17
import { TreeNode , ValueOf } from 'kit/utils/types' ;
18
18
19
19
const JupyterRenderer = lazy ( ( ) => import ( './CodeEditor/IpynbRenderer' ) ) ;
@@ -100,6 +100,10 @@ const langs = {
100
100
yaml : ( ) => StreamLanguage . define ( yaml ) ,
101
101
} ;
102
102
103
+ const emptyIpynbFile = JSON . stringify ( {
104
+ cells : [ ] ,
105
+ } ) ;
106
+
103
107
/**
104
108
* A component responsible to enable the user to view the code for a experiment.
105
109
*
@@ -126,7 +130,7 @@ const CodeEditor: React.FC<Props> = ({
126
130
readonly,
127
131
selectedFilePath = String ( files [ 0 ] ?. key ) ,
128
132
} ) => {
129
- const loadableFile = useMemo ( ( ) => ( typeof file === 'string' ? Loaded ( file ) : file ) , [ file ] ) ;
133
+ const loadableFile = useMemo ( ( ) => Loadable . ensureLoadable ( file ) , [ file ] ) ;
130
134
const sortedFiles = useMemo ( ( ) => [ ...files ] . sort ( sortTree ) , [ files ] ) ;
131
135
const {
132
136
themeSettings : { themeIsDark, className : themeClass } ,
@@ -193,8 +197,7 @@ const CodeEditor: React.FC<Props> = ({
193
197
) ;
194
198
195
199
const handleDownloadClick = useCallback ( ( ) => {
196
- if ( ! Loadable . isLoadable ( loadableFile ) || ! Loadable . isLoaded ( loadableFile ) || ! activeFile )
197
- return ;
200
+ if ( ! loadableFile . isLoaded || ! activeFile ) return ;
198
201
199
202
const link = document . createElement ( 'a' ) ;
200
203
@@ -215,7 +218,7 @@ const CodeEditor: React.FC<Props> = ({
215
218
themeClass ,
216
219
] ;
217
220
218
- const sectionClasses = [ loadableFile . isFailed ? css . pageError : css . editor ] ;
221
+ const sectionClass = loadableFile . isFailed ? css . pageError : css . editor ;
219
222
220
223
const treeClasses = [ css . fileTree , viewMode === 'editor' ? css . hideElement : '' ] ;
221
224
@@ -237,7 +240,10 @@ const CodeEditor: React.FC<Props> = ({
237
240
/>
238
241
) : (
239
242
< Suspense fallback = { < Spinner spinning tip = "Loading ipynb viewer..." /> } >
240
- < JupyterRenderer file = { Loadable . getOrElse ( '' , loadableFile ) } onError = { onError } />
243
+ < JupyterRenderer
244
+ file = { Loadable . getOrElse ( emptyIpynbFile , loadableFile ) }
245
+ onError = { onError }
246
+ />
241
247
</ Suspense >
242
248
) ;
243
249
}
@@ -253,39 +259,36 @@ const CodeEditor: React.FC<Props> = ({
253
259
onSelect = { handleSelectFile }
254
260
/>
255
261
{ ! ! activeFile ?. title && (
256
- < div className = { css . fileDir } >
257
- < div className = { css . fileInfo } >
258
- < div className = { css . buttonContainer } >
259
- < >
260
- { activeFile . icon ?? < Icon decorative name = "document" /> }
261
- < span className = { css . filePath } >
262
- < > { activeFile . title } </ >
263
- </ span >
264
- { activeFile ?. subtitle && (
265
- < span className = { css . fileDesc } > { activeFile ?. subtitle } </ span >
266
- ) }
267
- { readonly && < span className = { css . readOnly } > read-only</ span > }
268
- </ >
269
- </ div >
270
- < div className = { css . buttonsContainer } >
271
- { /*
272
- * TODO: Add notebook integration
273
- * <Button type="text">Open in Notebook</Button>
274
- */ }
275
- { readonly && file !== NotLoaded && (
276
- < Button
277
- icon = { < Icon name = "download" showTooltip size = "small" title = "Download File" /> }
278
- type = "text"
279
- onClick = { handleDownloadClick }
280
- />
262
+ < div className = { css . fileInfo } >
263
+ < div className = { css . buttonContainer } >
264
+ < >
265
+ { activeFile . icon ?? < Icon decorative name = "document" /> }
266
+ < span className = { css . filePath } >
267
+ < > { activeFile . title } </ >
268
+ </ span >
269
+ { activeFile ?. subtitle && (
270
+ < span className = { css . fileDesc } > { activeFile ?. subtitle } </ span >
281
271
) }
282
- </ div >
272
+ { readonly && < span className = { css . readOnly } > read-only</ span > }
273
+ </ >
274
+ </ div >
275
+ < div className = { css . buttonsContainer } >
276
+ { /*
277
+ * TODO: Add notebook integration
278
+ * <Button type="text">Open in Notebook</Button>
279
+ */ }
280
+ { readonly && ! loadableFile . isNotLoaded && (
281
+ < Button
282
+ icon = { < Icon name = "download" showTooltip size = "small" title = "Download File" /> }
283
+ type = "text"
284
+ onClick = { handleDownloadClick }
285
+ />
286
+ ) }
283
287
</ div >
284
288
</ div >
285
289
) }
286
- < div className = { sectionClasses . join ( ' ' ) } >
287
- { /* directly checking tag because loadable.isLoaded only takes loadables */ }
288
- < Spinner spinning = { file === NotLoaded } > { fileContent } </ Spinner >
290
+ < div className = { sectionClass } >
291
+ < Spinner spinning = { loadableFile . isNotLoaded } > { fileContent } </ Spinner >
289
292
</ div >
290
293
</ div >
291
294
) ;
0 commit comments