Split jinja template in views

This commit is contained in:
Benoît Seignovert 2024-02-14 18:45:57 +01:00
parent b0f8e336bc
commit b26425d4cf
Signed by: Benoît Seignovert
GPG key ID: F5D8895227D18A0B
9 changed files with 163 additions and 61 deletions

View file

@ -6,22 +6,24 @@ Usage: `python -m render`
from traceback import format_exc from traceback import format_exc
from flask import Flask, render_template, request from flask import Flask, render_template, request
from glicid_spawner.form import TEMPLATE_FORM, options_from_form from glicid_spawner.form import TEMPLATES, options_from_form
from glicid_spawner.micromamba import MicromambaEnv from glicid_spawner.micromamba import MicromambaEnv
from glicid_spawner.resources import CPU, GPU, RAM from glicid_spawner.resources import CPU, GPU, RAM
from livereload import Server from livereload import Server
# Monkeypatch # Dummy username and python environments
USERNAME = 'john-doe'
ENVS = [
MicromambaEnv('USER', 'foo', f'/{USERNAME}/envs/foo'),
MicromambaEnv('USER', 'bar', f'/{USERNAME}/envs/bar'),
MicromambaEnv('GLOBAL', 'baz', '/global/envs/baz'),
]
OPTIONS = { OPTIONS = {
'username': 'john-doe', 'username': USERNAME,
'python_envs': [ 'envs': ENVS,
MicromambaEnv('USER', 'foo', '/john-doe/envs/foo'), 'cpus': CPU,
MicromambaEnv('USER', 'bar', '/john-doe/envs/bar'), 'rams': RAM,
MicromambaEnv('GLOBAL', 'baz', '/global/envs/baz'), 'gpus': GPU,
],
'cpu_available': CPU,
'ram_available': RAM,
'gpu_available': GPU,
} }
@ -34,7 +36,9 @@ app.debug = True
def home(): def home():
"""Form spawner home page.""" """Form spawner home page."""
return render_template( return render_template(
'form.html', spawner_options_form=TEMPLATE_FORM.render(**OPTIONS), options=OPTIONS 'form.html',
spawner_options_form=TEMPLATES.get_template('spawner_form.jinja').render(**OPTIONS),
options=OPTIONS,
) )

View file

@ -9,23 +9,23 @@ TEMPLATES = Environment(
loader=PackageLoader('glicid_spawner'), loader=PackageLoader('glicid_spawner'),
autoescape=select_autoescape(), autoescape=select_autoescape(),
) )
TEMPLATE_FORM = TEMPLATES.get_template('spawner_form.html')
def options_attrs(username: str) -> dict: def options_attrs(username: str) -> dict:
"""Form options attributes.""" """Form options attributes."""
return { return {
'username': username, 'username': username,
'python_envs': get_envs(username), 'envs': get_envs(username),
'cpu_available': CPU, 'cpus': CPU,
'ram_available': RAM, 'rams': RAM,
'gpu_available': GPU, 'gpus': GPU,
} }
def options_form(username: str) -> str: def options_form(username: str) -> str:
"""Render default spawner form.""" """Render default spawner form."""
return TEMPLATE_FORM.render(**options_attrs(username)) template = TEMPLATES.get_template('spawner_form.jinja')
return template.render(**options_attrs(username))
def options_from_form(formdata) -> dict: def options_from_form(formdata) -> dict:

View file

@ -0,0 +1,12 @@
<style type="text/css">
{% include "static/style.css" %}
</style>
<div class="form-horizontal">
{% include "views/username.jinja" %}
{% include "views/envs.jinja" %}
{% include "views/resources.jinja" %}
{% include "views/slurm.jinja" %}
</div>

View file

@ -0,0 +1,24 @@
/* Spawner form addition style */
input[type=radio] {
display: none;
}
input[type=radio]:checked+label {
background-color: #f37524;
border-color: #e34f21;
color: #fff;
}
.panel-heading .panel-title-toggle {
text-decoration: none;
}
.panel-heading .panel-title-toggle:before {
font-family: 'FontAwesome';
content: "\\f078";
color: lightgrey;
}
.panel-heading .panel-title-toggle.collapsed:before {
content: "\\f054";
}

View file

@ -0,0 +1,10 @@
<div class="form-group">
<label for="python-env" class="col-sm-3 control-label">Python environment:</label>
<div class="col-sm-9">
<select class="form-control" name="python-env">
{%- for pyenv in envs -%}
<option value="{{ pyenv.path }}">{{ pyenv.name }} ({{ pyenv.scope | upper }})</option>
{% endfor -%}
</select>
</div>
</div>

View file

@ -1,24 +1,9 @@
<div class="form-horizontal"> <div class="resources">
<div class="form-group">
<label class="col-sm-3 control-label">Username:</label>
<div class="col-sm-9">
<div class="form-control-static">{{ username }}</div>
</div>
</div>
<div class="form-group">
<label for="python-env" class="col-sm-3 control-label">Python environment:</label>
<div class="col-sm-9">
<select class="form-control" name="python-env">
{%- for pyenv in python_envs -%}
<option value="{{ pyenv.path }}">{{ pyenv.name }} ({{ pyenv.scope | upper }})</option>
{% endfor -%}
</select>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="cpu" class="col-sm-3 control-label">CPU:</label> <label for="cpu" class="col-sm-3 control-label">CPU:</label>
<div class="col-sm-9"> <div class="col-sm-9">
{%- for cpu in cpu_available -%} {%- for cpu in cpus -%}
<div class="col-sm-2"> <div class="col-sm-2">
<input type="radio" name="cpu" id="cpu_{{loop.index0}}" value="{{loop.index0}}" <input type="radio" name="cpu" id="cpu_{{loop.index0}}" value="{{loop.index0}}"
data-max-duration="{{cpu.max_duration}}"{% if loop.first %} checked{% endif %}> data-max-duration="{{cpu.max_duration}}"{% if loop.first %} checked{% endif %}>
@ -29,10 +14,11 @@
{% endfor -%} {% endfor -%}
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="ram" class="col-sm-3 control-label">Memory:</label> <label for="ram" class="col-sm-3 control-label">Memory:</label>
<div class="col-sm-9"> <div class="col-sm-9">
{%- for ram in ram_available -%} {%- for ram in rams -%}
<div class="col-sm-2"> <div class="col-sm-2">
<input type="radio" name="ram" id="ram_{{loop.index0}}" value="{{loop.index0}}" <input type="radio" name="ram" id="ram_{{loop.index0}}" value="{{loop.index0}}"
data-max-duration="{{ram.max_duration}}"{% if loop.first %} checked{% endif %}> data-max-duration="{{ram.max_duration}}"{% if loop.first %} checked{% endif %}>
@ -43,10 +29,11 @@
{% endfor -%} {% endfor -%}
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="gpu" class="col-sm-3 control-label">GPU:</label> <label for="gpu" class="col-sm-3 control-label">GPU:</label>
<div class="col-sm-9"> <div class="col-sm-9">
{%- for gpu in gpu_available -%} {%- for gpu in gpus -%}
<div class="col-sm-2"> <div class="col-sm-2">
<input type="radio" name="gpu" id="gpu_{{loop.index0}}" value="{{loop.index0}}" <input type="radio" name="gpu" id="gpu_{{loop.index0}}" value="{{loop.index0}}"
data-max-duration="{{gpu.max_duration}}"{% if loop.first %} checked{% endif %}> data-max-duration="{{gpu.max_duration}}"{% if loop.first %} checked{% endif %}>
@ -57,32 +44,20 @@
{% endfor -%} {% endfor -%}
</div> </div>
</div> </div>
<div class="form-group"> </div>
<label class="col-sm-3 control-label">Session duration:</label>
<div class="col-sm-9"> <div class="form-group">
<div class="form-control-static"><span id="time-max-duration">24</span> h</div> <label class="col-sm-3 control-label">Session duration:</label>
</div> <div class="col-sm-9">
<div class="form-control-static"><span id="time-max-duration">24</span> h</div>
</div> </div>
</div> </div>
<script> <script>
// Append button style
var $style = $(`<style>
input[type=radio] {
display: none;
}
input[type=radio]:checked + label {
background-color: #f37524;
border-color: #e34f21;
color: #fff;
}
</style>`)
$('html > head').append($style);
// Adjust time duration // Adjust time duration
var $reservations_dropdown = $("#time-max-duration"); var $reservations_dropdown = $("#time-max-duration");
$('input[type=radio]').change(function () { $('.resources input[type=radio]').change(function () {
var cpu = $('input[name=cpu]:checked').data('max-duration'); var cpu = $('input[name=cpu]:checked').data('max-duration');
var ram = $('input[name=ram]:checked').data('max-duration'); var ram = $('input[name=ram]:checked').data('max-duration');
var gpu = $('input[name=gpu]:checked').data('max-duration'); var gpu = $('input[name=gpu]:checked').data('max-duration');

View file

@ -0,0 +1,70 @@
<div class="panel-group" id="advanced-config" role="tablist" aria-multiselectable="true">
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="heading">
<h4 class="panel-title">
<a class="panel-title-toggle collapsed" role="button" data-toggle="collapse"
data-parent="#advanced-config" href="#advanced-config-collapse" aria-expanded="true" aria-controls="advanced-config-collapse">
Advanced configuration
</a>
</h4>
</div>
<div id="advanced-config-collapse" class="panel-collapse {# collapse #}" role="tabpanel" aria-labelledby="heading">
<div class="panel-body">
<p>You can specify on which cluster/partion/node you want to start your Jupyter server:</p>
{# {% if slurm is not 'None' %} #}
<div class="form-group">
<label for="cluster" class="col-sm-3 control-label">Clusters:</label>
<div class="col-sm-9">
{%- for cluster in slurm -%}
<div class="col-sm-6">
<input type="radio" name="cluster" id="cluster_{{cluster}}" class="slurm_cluster"
value="{{cluster}}">
<label for="cluster_{{cluster}}" class="btn btn-default btn-block">
{{ cluster | capitalize }}
</label>
</div>
{% endfor -%}
</div>
</div>
{# {% endif %} #}
<div class="form-group">
<label for="partition" class="col-sm-3 control-label">Partitions:</label>
<div class="col-sm-9" id="partitions-list"></div>
</div>
<div class="form-group">
<label for="node" class="col-sm-3 control-label">Nodes:</label>
<div class="col-sm-9">
<div class="col-sm-3">
<input type="radio" name="node" id="node_0" value="0" checked>
<label for="node_0" class="btn btn-default btn-block">
cribbar033
</label>
</div>
<div class="col-sm-3">
<input type="radio" name="node" id="node_1" value="1">
<label for="node_1" class="btn btn-default btn-block">
cribbar034
</label>
</div>
<div class="col-sm-3">
<input type="radio" name="node" id="node_2" value="2">
<label for="node_2" class="btn btn-default btn-block">
cribbar035
</label>
</div>
<div class="col-sm-3">
<input type="radio" name="node" id="node_3" value="3">
<label for="node_3" class="btn btn-default btn-block">
cribbar036
</label>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,6 @@
<div class="form-group">
<label class="col-sm-3 control-label">Username:</label>
<div class="col-sm-9">
<div class="form-control-static">{{ username }}</div>
</div>
</div>

View file

@ -2,8 +2,9 @@
import re import re
from glicid_spawner import form, micromamba from glicid_spawner import form
from glicid_spawner.form import options_form, options_from_form from glicid_spawner.form import options_form, options_from_form
from glicid_spawner.micromamba import MicromambaEnv
def test_options_form(monkeypatch): def test_options_form(monkeypatch):
@ -12,9 +13,9 @@ def test_options_form(monkeypatch):
form, form,
'get_envs', 'get_envs',
lambda username: [ lambda username: [
micromamba.MicromambaEnv('USER', 'foo', f'/{username}/envs/foo'), MicromambaEnv('USER', 'foo', f'/{username}/envs/foo'),
micromamba.MicromambaEnv('USER', 'bar', f'/{username}/envs/bar'), MicromambaEnv('USER', 'bar', f'/{username}/envs/bar'),
micromamba.MicromambaEnv('GLOBAL', 'baz', '/global/envs/baz'), MicromambaEnv('GLOBAL', 'baz', '/global/envs/baz'),
], ],
) )