| @@ -1,3 +1,5 @@ | |||||
| __pycache__ | __pycache__ | ||||
| *.pyc | *.pyc | ||||
| node_modules | |||||
| package-lock.json | |||||
| /frontend/dist/ | |||||
| @@ -0,0 +1,19 @@ | |||||
| { | |||||
| "dependencies": { | |||||
| "linkstate": "^1.1.1", | |||||
| "preact": "^8.2.9", | |||||
| "preact-router": "^2.6.1", | |||||
| "rollup": "^0.62.0", | |||||
| "rollup-plugin-buble": "^0.19.2", | |||||
| "rollup-plugin-copy": "^0.2.3", | |||||
| "rollup-plugin-includepaths": "^0.2.3", | |||||
| "rollup-plugin-license": "^0.7.0", | |||||
| "rollup-plugin-minify": "^1.0.3", | |||||
| "rollup-plugin-node-resolve": "^3.3.0", | |||||
| "watch": "^1.0.2" | |||||
| }, | |||||
| "scripts": { | |||||
| "rollup": "rollup -c", | |||||
| "watch": "watch \"rollup -c\" src" | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,35 @@ | |||||
| import resolve from 'rollup-plugin-node-resolve' | |||||
| import buble from 'rollup-plugin-buble'; | |||||
| import minify from 'rollup-plugin-minify'; | |||||
| import copy from 'rollup-plugin-copy'; | |||||
| import includePaths from 'rollup-plugin-includepaths'; | |||||
| import license from 'rollup-plugin-license'; | |||||
| export default { | |||||
| //dest: 'dist/app.min.js', | |||||
| input: 'src/js/index.js', | |||||
| output: { | |||||
| file: 'dist/js/app.min.js', | |||||
| name: 'CHEMTOP', | |||||
| format: 'umd', | |||||
| sourceMap: true | |||||
| }, | |||||
| plugins: [ | |||||
| includePaths({ | |||||
| paths: ['src/js', 'src/js/widget', 'src/js/misc'] | |||||
| }), | |||||
| copy({ | |||||
| 'src/html/index.html': 'dist/index.html', | |||||
| 'src/css/index.css': 'dist/css/index.css', | |||||
| verbose: true | |||||
| }), | |||||
| buble({jsx: 'h'}), | |||||
| resolve({}), | |||||
| license({ | |||||
| banner: 'Copyright (C) F. Hoffmann-La Roche AG, 2020.\nAuthor: stanislaw.adaszewski@roche.com\nAll Rights Reserved.', | |||||
| }) /* , | |||||
| minify({ | |||||
| iife: 'dist/app.min.js' | |||||
| }) */ | |||||
| ] | |||||
| } | |||||
| @@ -1,11 +1,18 @@ | |||||
| import dash | import dash | ||||
| import dash_bootstrap_components as dbc | import dash_bootstrap_components as dbc | ||||
| import dash_html_components as html | import dash_html_components as html | ||||
| import dash_core_components as dcc | |||||
| import socket | import socket | ||||
| import arvados | import arvados | ||||
| import functools | import functools | ||||
| from .projects import list_projects_html | from .projects import list_projects_html | ||||
| from .collections import list_collections_html | from .collections import list_collections_html | ||||
| from .processes import list_processes_html | |||||
| # list_projects_html = functools.lru_cache(maxsize=128)(list_projects_html) | |||||
| # list_collections_html = functools.lru_cache(maxsize=128)(list_collections_html) | |||||
| # list_processes_html = functools.lru_cache(maxsize=128)(list_processes_html) | |||||
| def main(): | def main(): | ||||
| @@ -13,19 +20,36 @@ def main(): | |||||
| arv = arvados.api('v1') | arv = arvados.api('v1') | ||||
| user = arv.users().current().execute() | user = arv.users().current().execute() | ||||
| # nav_btns = [ dbc.Button(a['name']) for a in projects ] | # nav_btns = [ dbc.Button(a['name']) for a in projects ] | ||||
| projects_table = list_projects_html(arv, user['uuid']) | |||||
| collections_table = list_collections_html(arv, user['uuid']) | |||||
| app.layout = html.Div([ | app.layout = html.Div([ | ||||
| html.H5('Projects'), | |||||
| projects_table, | |||||
| html.H5('Collections'), | |||||
| collections_table | |||||
| dcc.Location(id='url', refresh=False), | |||||
| html.Div(id='page-content') | |||||
| ], style={ 'margin': '10px' }) | ], style={ 'margin': '10px' }) | ||||
| app.run_server(host=socket.getfqdn(), debug=True) | |||||
| projects_table = list_projects_html(arv, user['uuid']) | |||||
| collections_table = list_collections_html(arv, user['uuid']) | |||||
| processes_table = list_processes_html(arv, user['uuid']) | |||||
| @app.callback(dash.dependencies.Output('page-content', 'children'), | |||||
| [ dash.dependencies.Input('url', 'pathname') ]) | |||||
| def display_page(pathname): | |||||
| print('display_page(), pathname:', pathname) | |||||
| return html.Div([ | |||||
| dbc.Tabs([ | |||||
| dbc.Tab(projects_table, label="Projects", | |||||
| label_style={ 'cursor': 'pointer' }) | |||||
| ], style={ 'borderBottom': 'none' }), | |||||
| dbc.Tabs([ | |||||
| dbc.Tab(collections_table, label="Collections", | |||||
| label_style={ 'cursor': 'pointer' }), | |||||
| dbc.Tab(processes_table, label="Processes", | |||||
| label_style={ 'cursor': 'pointer' }) | |||||
| ], style={ 'borderBottom': 'none' }) | |||||
| ]) | |||||
| app.run_server(host=socket.getfqdn(), debug=False) | |||||
| main() | main() | ||||
| @@ -4,18 +4,18 @@ import humanize | |||||
| from .users import get_user | from .users import get_user | ||||
| def list_collections(arv, owner_uuid): | |||||
| def list_collections(arv, owner_uuid, limit=100): | |||||
| res = arv.collections().list(where = { | res = arv.collections().list(where = { | ||||
| 'owner_uuid': owner_uuid | 'owner_uuid': owner_uuid | ||||
| }).execute() | |||||
| }, limit=limit).execute() | |||||
| res = res['items'] | res = res['items'] | ||||
| #while res['items_available'] > len(res['items']): | #while res['items_available'] > len(res['items']): | ||||
| #res = arv.collections().list(where = {}) | #res = arv.collections().list(where = {}) | ||||
| return res | return res | ||||
| def list_collections_html(arv, parent): | |||||
| projects = list_collections(arv, parent) | |||||
| def list_collections_html(arv, parent, limit=100): | |||||
| projects = list_collections(arv, parent, limit=limit) | |||||
| header = html.Tr([ | header = html.Tr([ | ||||
| html.Th('Name'), | html.Th('Name'), | ||||
| @@ -0,0 +1,49 @@ | |||||
| import dash_bootstrap_components as dbc | |||||
| import dash_html_components as html | |||||
| from .users import get_user | |||||
| def list_processes(arv, parent, limit=100): | |||||
| res = arv.container_requests().list(where={ | |||||
| 'owner_uuid': parent | |||||
| }, limit=100).execute()['items'] | |||||
| return res | |||||
| def list_processes_html(arv, parent, limit=100): | |||||
| processes = list_processes(arv, parent, limit=limit) | |||||
| header = html.Tr([ | |||||
| html.Th('Name'), | |||||
| html.Th('Description'), | |||||
| html.Th('Owner') | |||||
| ]) | |||||
| header = [ html.Thead(header) ] | |||||
| rows = [] | |||||
| for a in processes: | |||||
| owner = get_user(arv, a['owner_uuid']) | |||||
| rows.append( | |||||
| html.Tr([ | |||||
| html.Td([ | |||||
| html.Div(html.A(href='/processes/' + a['uuid'], | |||||
| children=a['name'])), | |||||
| html.Div(a['uuid']) | |||||
| ]), | |||||
| html.Td(a['description'] or 'Process'), | |||||
| html.Td([ | |||||
| html.Div(html.A(href='mailto:' + owner['email'], | |||||
| children=owner['first_name'] + ' ' + owner['last_name'])), | |||||
| html.Div(a['owner_uuid']) | |||||
| ]) | |||||
| ])) | |||||
| rows = [ html.Tbody(rows) ] | |||||
| res = dbc.Table(header + rows, | |||||
| striped=True, | |||||
| hover=True, | |||||
| responsive=True) | |||||
| return res | |||||
| @@ -1,5 +1,6 @@ | |||||
| import dash_bootstrap_components as dbc | import dash_bootstrap_components as dbc | ||||
| import dash_html_components as html | import dash_html_components as html | ||||
| import dash_core_components as dcc | |||||
| from .users import get_user | from .users import get_user | ||||
| @@ -27,7 +28,7 @@ def list_projects_html(arv, parent): | |||||
| rows.append( | rows.append( | ||||
| html.Tr([ | html.Tr([ | ||||
| html.Td([ | html.Td([ | ||||
| html.Div(html.A(href='/projects/' + a['uuid'], | |||||
| html.Div(dcc.Link(href='/projects/' + a['uuid'], | |||||
| children=a['name'])), | children=a['name'])), | ||||
| html.Div(a['uuid']) | html.Div(a['uuid']) | ||||
| ]), | ]), | ||||