-
Notifications
You must be signed in to change notification settings - Fork 582
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WiP on finder-browser component WiP on finder-browser component WiP on finder-browser component
- Loading branch information
Showing
15 changed files
with
340 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import {build} from 'esbuild'; | ||
import svgr from 'esbuild-plugin-svgr'; | ||
import parser from 'yargs-parser'; | ||
const buildOptions = parser(process.argv.slice(2), { | ||
boolean: ['debug', 'minify'], | ||
}); | ||
|
||
await build({ | ||
entryPoints: [ | ||
'client/finder-browser.ts', | ||
], | ||
bundle: true, | ||
minify: buildOptions.minify, | ||
sourcemap: buildOptions.debug, | ||
outfile: 'finder/static/finder/js/browser.js', | ||
format: 'esm', | ||
jsx: 'automatic', | ||
plugins: [svgr()], | ||
loader: {'.svg': 'text', '.jsx': 'jsx' }, | ||
target: ['es2020', 'chrome84', 'firefox84', 'safari14', 'edge84'] | ||
}).catch(() => process.exit(1)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
finder-file-select { | ||
display: flex; | ||
|
||
.folder-structure { | ||
flex-shrink: 0; | ||
padding-right: 1rem; | ||
|
||
ul ul { | ||
padding-left: 1.5rem; | ||
} | ||
|
||
&, ul { | ||
padding-left: 0; | ||
list-style: none; | ||
} | ||
|
||
li { | ||
i { | ||
display: inline-block; | ||
cursor: pointer; | ||
width: 1.5rem; | ||
color: #808080; | ||
&:hover { | ||
color: inherit; | ||
} | ||
} | ||
|
||
svg { | ||
height: 20px; | ||
vertical-align: text-bottom; | ||
margin-right: 0.5em; | ||
} | ||
|
||
span { | ||
cursor: pointer; | ||
&:hover { | ||
text-decoration: underline; | ||
text-decoration-style: dashed; | ||
text-decoration-color: #808080; | ||
} | ||
} | ||
} | ||
} | ||
|
||
.files-list { | ||
&, ul { | ||
list-style: none; | ||
display: flex; | ||
padding: 10px; | ||
flex-wrap: wrap; | ||
flex-direction: row; | ||
align-content: flex-start; | ||
justify-content: flex-start; | ||
gap: 10px; | ||
} | ||
|
||
li { | ||
min-height: 150px; | ||
width: 125px; | ||
|
||
&.status { | ||
font-size: 18px; | ||
font-weight: bold; | ||
line-height: 50px; | ||
color: #808080; | ||
padding-left: 2em; | ||
width: auto; | ||
} | ||
|
||
.figure { | ||
width: 100%; | ||
height: 100%; | ||
margin: 0; | ||
cursor: pointer; | ||
|
||
div:has(> .figure-labels) { | ||
position: relative; | ||
} | ||
|
||
.figure-labels { | ||
position: absolute; | ||
line-height: 0; | ||
text-align: right; | ||
overflow: hidden; | ||
inset: 4px; | ||
|
||
span { | ||
width: 10px; | ||
height: 10px; | ||
display: inline-block; | ||
border-radius: 50%; | ||
margin-left: -4px; | ||
} | ||
|
||
} | ||
|
||
img, video { | ||
width: 100%; | ||
border-radius: 0.25rem; | ||
} | ||
|
||
img:not([src$=".svg"]), video { | ||
box-shadow: 0 0 0.5rem #808080; | ||
} | ||
|
||
figcaption { | ||
text-align: center; | ||
line-height: 1.5rem; | ||
font-size: 0.8em; | ||
white-space: nowrap; | ||
overflow: hidden; | ||
text-overflow: ellipsis; | ||
} | ||
} | ||
} | ||
} | ||
|
||
.file-uploader { | ||
width: 100%; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
from django.urls import path | ||
from django.views.i18n import JavaScriptCatalog | ||
|
||
from finder.api.views import BrowserView | ||
|
||
|
||
app_name = 'finder-api' | ||
urlpatterns = [ | ||
path( | ||
'structure/<slug:realm>', | ||
BrowserView.as_view(action='structure'), | ||
), | ||
path( | ||
'fetch/<uuid:folder_id>', | ||
BrowserView.as_view(action='fetch'), | ||
), | ||
path( | ||
'open/<uuid:folder_id>', | ||
BrowserView.as_view(action='open'), | ||
), | ||
path( | ||
'close/<uuid:folder_id>', | ||
BrowserView.as_view(action='close'), | ||
), | ||
path( | ||
'list/<uuid:folder_id>', | ||
BrowserView.as_view(action='list'), | ||
), | ||
path( | ||
'jsi18n/', | ||
JavaScriptCatalog.as_view(packages=['finder']), | ||
name="javascript-catalog", | ||
), | ||
path( | ||
'', | ||
BrowserView.as_view(), | ||
name="base-url", | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
from django.contrib.sites.shortcuts import get_current_site | ||
from django.core.exceptions import ObjectDoesNotExist | ||
from django.http import JsonResponse, HttpResponseBadRequest, HttpResponseNotFound | ||
from django.views import View | ||
|
||
from finder.models.folder import FolderModel, RealmModel | ||
|
||
|
||
class BrowserView(View): | ||
""" | ||
The view for web component <finder-browser>. | ||
""" | ||
action = None | ||
|
||
def get(self, request, *args, **kwargs): | ||
action = getattr(self, self.action, None) | ||
if not callable(action): | ||
return HttpResponseBadRequest(f"Action {self.action} not allowed.") | ||
try: | ||
return JsonResponse(action(request, *args, **kwargs)) | ||
except Exception as e: | ||
return HttpResponseBadRequest(str(e)) | ||
|
||
def _get_children(cls, open_folders, parent): | ||
children = [] | ||
for child in parent.subfolders: | ||
child_id = str(child.id) | ||
if child_id in open_folders: | ||
grandchildren = cls._get_children(open_folders, child) | ||
else: | ||
grandchildren = None | ||
children.append({ | ||
'id': child_id, | ||
'name': child.name, | ||
'children': grandchildren, | ||
'is_open': grandchildren is not None, | ||
'has_subfolders': child.subfolders.exists(), | ||
}) | ||
return children | ||
|
||
def structure(self, request, realm): | ||
site = get_current_site(request) | ||
try: | ||
realm = RealmModel.objects.get(site=site, slug=realm) | ||
except RealmModel.DoesNotExist: | ||
raise ObjectDoesNotExist(f"Realm {realm} not found for {site.domain}.") | ||
root_folder = FolderModel.objects.get_root_folder(realm) | ||
root_folder_id = str(root_folder.id) | ||
request.session.setdefault('finder.open_folders', []) | ||
request.session.setdefault('finder.last_folder', root_folder_id) | ||
if is_open := root_folder.subfolders.exists(): | ||
# direct children of the root folder are open regardless of the `open_folders` session | ||
children = self._get_children(request.session['finder.open_folders'], root_folder) | ||
else: | ||
children = None | ||
return { | ||
'root_folder': { | ||
'id': root_folder_id, | ||
'name': None, # the root folder has no readable name | ||
'is_root': True, | ||
'is_open': is_open, | ||
'children': children, | ||
'has_subfolders': is_open, | ||
}, | ||
'last_folder': request.session['finder.last_folder'], | ||
**self.list(request, request.session['finder.last_folder']), | ||
} | ||
|
||
def fetch(self, request, folder_id): | ||
""" | ||
Open the given folder and fetch children data for the folder. | ||
""" | ||
folder = FolderModel.objects.get(id=folder_id) | ||
folder_id = str(folder_id) | ||
request.session.setdefault('finder.open_folders', []) | ||
if folder_id not in request.session['finder.open_folders']: | ||
request.session['finder.open_folders'].append(folder_id) | ||
request.session.modified = True | ||
|
||
return { | ||
'id': folder_id, | ||
'name': folder.name, | ||
'children': self._get_children(request.session['finder.open_folders'], folder), | ||
'is_open': True, | ||
'has_subfolders': folder.subfolders.exists(), | ||
} | ||
|
||
def open(self, request, folder_id): | ||
""" | ||
Just open the folder. | ||
""" | ||
folder_id = str(folder_id) | ||
request.session.setdefault('finder.open_folders', []) | ||
if folder_id not in request.session['finder.open_folders']: | ||
request.session['finder.open_folders'].append(folder_id) | ||
request.session.modified = True | ||
|
||
def close(self, request, folder_id): | ||
""" | ||
Just close the folder. | ||
""" | ||
folder_id = str(folder_id) | ||
try: | ||
request.session['finder.open_folders'].remove(folder_id) | ||
except (KeyError, ValueError): | ||
pass | ||
else: | ||
request.session.modified = True | ||
|
||
def list(self, request, folder_id): | ||
""" | ||
List all the files of the given folder. | ||
""" | ||
folder = FolderModel.objects.get(id=folder_id) | ||
request.session['finder.last_folder'] = str(folder_id) | ||
|
||
folder.listdir(is_folder=False) | ||
|
||
return { | ||
'files': [{ | ||
'id': str(file.id), | ||
'name': file.name, | ||
'mime_type': file.mime_type, | ||
'browser_component': file.casted.browser_component, | ||
'thumbnail_url': file.casted.get_thumbnail_url(), | ||
'sample_url': getattr(file.casted, 'get_sample_url', lambda: None)(), | ||
'labels': file.serializable_value('labels'), | ||
} for file in folder.listdir(is_folder=False)] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.