@@ -501,7 +501,6 @@ def url(path: str) -> str:
501
501
return f"{ settings .urlbase } /{ path } "
502
502
503
503
504
- app .mount ("/static" , StaticFiles (directory = BASE_DIR / "static" ), name = "static" )
505
504
templates = Jinja2Templates (directory = BASE_DIR / "templates" )
506
505
templates .env .filters ["filesizeformat" ] = custom_filesizeformat
507
506
templates .env .globals ["url" ] = url
@@ -1426,6 +1425,21 @@ async def htmx_root_list(
1426
1425
return templates .TemplateResponse (request , "root_list.html" , context )
1427
1426
1428
1427
1428
+ def _get_rootdir (user , root ):
1429
+ if user and root == "@personal" :
1430
+ return settings .personal / str (user .id )
1431
+ elif user and root == "@shared" :
1432
+ return settings .shared
1433
+ elif root == "@public" :
1434
+ return settings .public
1435
+ else :
1436
+ if not get_root (root ).subscribed :
1437
+ follow (root )
1438
+ return settings .cache / root
1439
+
1440
+ return None
1441
+
1442
+
1429
1443
@app .get ("/htmx/path-list/" , response_class = HTMLResponse )
1430
1444
async def htmx_path_list (
1431
1445
request : Request ,
@@ -1450,20 +1464,6 @@ def get_names():
1450
1464
1451
1465
names = get_names ()
1452
1466
1453
- def get_rootdir (root ):
1454
- if user and root == "@personal" :
1455
- rootdir = settings .personal / str (user .id )
1456
- elif user and root == "@shared" :
1457
- rootdir = settings .shared
1458
- elif root == "@public" :
1459
- rootdir = settings .public
1460
- else :
1461
- if not get_root (root ).subscribed :
1462
- follow (root )
1463
- rootdir = settings .cache / root
1464
-
1465
- return rootdir
1466
-
1467
1467
datasets = []
1468
1468
query = {"roots" : roots , "search" : search }
1469
1469
@@ -1479,7 +1479,7 @@ def add_dataset(path, abspath):
1479
1479
)
1480
1480
1481
1481
for root in roots :
1482
- rootdir = get_rootdir ( root )
1482
+ rootdir = _get_rootdir ( user , root )
1483
1483
for abspath , relpath in utils .walk_files (rootdir ):
1484
1484
if relpath .suffix == ".b2" :
1485
1485
relpath = relpath .with_suffix ("" )
@@ -1497,7 +1497,7 @@ def add_dataset(path, abspath):
1497
1497
break
1498
1498
else :
1499
1499
root = segments [1 ]
1500
- rootdir = get_rootdir ( root )
1500
+ rootdir = _get_rootdir ( user , root )
1501
1501
relpath = pathlib .Path (* segments [2 :])
1502
1502
abspath = rootdir / relpath
1503
1503
if abspath .suffix not in {".b2" , ".b2nd" , ".b2frame" }:
@@ -2112,7 +2112,10 @@ async def html_display(
2112
2112
return f'<object data="{ data } " type="application/pdf" class="w-100" style="height: 768px"></object>'
2113
2113
elif mimetype == "application/vnd.jupyter" :
2114
2114
src = f"{ url ('api/preview/' )} { path } "
2115
- return f'<iframe src="{ src } " class="w-100" height="768px"></iframe>'
2115
+ return (
2116
+ f'<a href="/static/jupyterlite/notebooks/index.html?path={ path } " target="_blank">Run</a><br>'
2117
+ f'<iframe src="{ src } " class="w-100" height="768px"></iframe>'
2118
+ )
2116
2119
elif mimetype == "text/markdown" :
2117
2120
content = await get_file_content (path , user )
2118
2121
return markdown .markdown (content .decode ("utf-8" ))
@@ -2138,6 +2141,97 @@ async def html_display(
2138
2141
return "Format not supported"
2139
2142
2140
2143
2144
+ #
2145
+ # For Jupyterlite
2146
+ #
2147
+
2148
+
2149
+ @app .get ("/static/jupyterlite/api/contents/{path:path}" )
2150
+ def jupyterlite_contents (
2151
+ request : Request ,
2152
+ # Path parameters
2153
+ path : pathlib .Path ,
2154
+ user : db .User = Depends (optional_user ),
2155
+ ):
2156
+ parts = path .parts
2157
+ if parts [- 1 ] != "all.json" :
2158
+ raise fastapi .HTTPException (status_code = 404 ) # NotFound
2159
+
2160
+ content = []
2161
+
2162
+ def directory (path ):
2163
+ return {
2164
+ "name" : pathlib .Path (path ).name ,
2165
+ "path" : path ,
2166
+ "size" : None ,
2167
+ "type" : "directory" ,
2168
+ }
2169
+
2170
+ parts = parts [:- 1 ]
2171
+ if len (parts ) == 0 :
2172
+ # TODO pub/sub roots: settings.database.roots.values()
2173
+ if user :
2174
+ content .append (directory ("@personal" ))
2175
+ content .append (directory ("@shared" ))
2176
+
2177
+ content .append (directory ("@public" ))
2178
+ else :
2179
+ root = parts [0 ]
2180
+ rootdir = _get_rootdir (user , root )
2181
+ if rootdir is None :
2182
+ raise fastapi .HTTPException (status_code = 404 ) # NotFound
2183
+
2184
+ for abspath , relpath in utils .iterdir (rootdir ):
2185
+ if abspath .is_file ():
2186
+ if relpath .suffix == ".b2" :
2187
+ relpath = relpath .with_suffix ("" )
2188
+
2189
+ if relpath .suffix == ".ipynb" :
2190
+ type = "notebook"
2191
+ else :
2192
+ type = "file" # XXX Is this the correct type?
2193
+
2194
+ stat = abspath .stat ()
2195
+ content .append (
2196
+ {
2197
+ "created" : utils .epoch_to_iso (stat .st_ctime ),
2198
+ "last_modified" : utils .epoch_to_iso (stat .st_mtime ),
2199
+ "name" : relpath .name ,
2200
+ "path" : relpath ,
2201
+ "size" : stat .st_size , # XXX Return the uncompressed size?
2202
+ "type" : type ,
2203
+ }
2204
+ )
2205
+ else :
2206
+ content .append (directory (relpath ))
2207
+
2208
+ return {
2209
+ "content" : content ,
2210
+ }
2211
+
2212
+
2213
+ @app .get ("/static/jupyterlite/files/{path:path}" )
2214
+ def jupyterlite_files (
2215
+ request : Request ,
2216
+ # Path parameters
2217
+ path : pathlib .Path ,
2218
+ user : db .User = Depends (optional_user ),
2219
+ ):
2220
+ async def downloader ():
2221
+ yield await get_file_content (path , user )
2222
+
2223
+ mimetype = guess_type (path )
2224
+ # mimetype = 'application/json'
2225
+ return responses .StreamingResponse (downloader (), media_type = mimetype )
2226
+
2227
+
2228
+ #
2229
+ # Static
2230
+ #
2231
+
2232
+ app .mount ("/static" , StaticFiles (directory = BASE_DIR / "static" ), name = "static" )
2233
+
2234
+
2141
2235
#
2142
2236
# Command line interface
2143
2237
#
0 commit comments