Skip to content
Snippets Groups Projects
Commit 9f4e6679 authored by Stefano Alberto Russo's avatar Stefano Alberto Russo
Browse files

UI/UX improvements for new tasks and navigation. Fixes.

parent 90cee362
No related branches found
No related tags found
No related merge requests found
...@@ -48,9 +48,9 @@ class Command(BaseCommand): ...@@ -48,9 +48,9 @@ class Command(BaseCommand):
To change it, head to the <a href="/admin">admin</a> page and edit the <code>Text</code> model. To change it, head to the <a href="/admin">admin</a> page and edit the <code>Text</code> model.
<br/><br/> <br/><br/>
The default installation provides a test user register with email <code>testuser@rosetta.platform</code> The default installation provides a test user register with email <code>testuser@rosetta.platform</code>
and password <code>testpass</code>, which you can use to login on the menu on the right or using the link and password <code>testpass</code>, which you can use to login on the menu on the rightand give Rosetta
below and give Rosetta a try immediately. If you run with the default docker-compose file (i.e. you just a try immediately. If you run with the default docker-compose file (i.e. you just run
run <code>rosetta/setup</code>), then you will also have a few demo computing resources you can play with <code>rosetta/setup</code>), then you will also have a few demo computing resources you can play with
out-of-the-box, including a small Slurm cluster. Otherwise, you will need to setup your own computing out-of-the-box, including a small Slurm cluster. Otherwise, you will need to setup your own computing
resources either platform-wide or as user. resources either platform-wide or as user.
</div> </div>
......
...@@ -112,7 +112,7 @@ ...@@ -112,7 +112,7 @@
</div> </div>
<div style="margin-bottom:13px; margin-top: 3px; text-align:center"> <div style="margin-bottom:13px; margin-top: 3px; text-align:center">
<a href="/create_task?task_container_uuid={{ container.uuid }}" class="btn btn-light" style="border: #c0c0c0 1px solid">&nbsp;<i class="fa fa-play" style="color:green"></i></a> <a href="/create_task?task_container_uuid={{ container.uuid }}&step=two" class="btn btn-light" style="border: #c0c0c0 1px solid">&nbsp;<i class="fa fa-play" style="color:green"></i></a>
</div> </div>
......
...@@ -12,15 +12,24 @@ ...@@ -12,15 +12,24 @@
{% if data.container %} {% if data.container %}
<h1><a href="/containers">Containers</a> <span style="font-size:18px"> / {{ data.container.name }}</span></h1> <h1><a href="/containers">Containers</a> <span style="font-size:18px"> / {{ data.container.name }}</span></h1>
{% else %} {% else %}
{% if data.mode == 'new_task' %}
<h1>New task</h1>
<hr/>
<h3>Step 1: choose software container.</h3>
<br/>
{% else %}
<h1>Containers</h1> <h1>Containers</h1>
<hr/> <hr/>
{% endif %}
<div class="form-filter" style="margin-bottom:20px"> <div class="form-filter" style="margin-bottom:20px">
<form action="" method="POST"> <form action="" method="POST">
<input type="hidden" name="mode" value="{{data.mode}}">
<input type="text" class="form-control" id="search_text" name="search_text" placeholder="Search..." style="width:200px; margin:0; display:inline" value="{{data.search_text}}" autofocus> <input type="text" class="form-control" id="search_text" name="search_text" placeholder="Search..." style="width:200px; margin:0; display:inline" value="{{data.search_text}}" autofocus>
<select class="form-control" id="search_type" name="search_type" style="width:120px; margin:0; display:inline"> <select class="form-control" id="search_type" name="search_type" style="width:120px; margin:0; display:inline">
......
...@@ -11,45 +11,49 @@ ...@@ -11,45 +11,49 @@
<h1>New Task</h1> <h1>New Task</h1>
<hr> <hr>
{% if data.step == 'one' %}
<h3>Step 1: name, container and computing.</h3> {% if data.step == 'two' %}
<h3>Step 2: set task name and computing.</h3>
{% elif data.step == 'three' %}
<h3>Step 3: add authentication and computing details.</h3>
{% endif %}
<br/> <br/>
<div style="width:300px; float:left; border: #e0e0e0 solid 1px; margin:10px; background:#f8f8f8; margin-bottom:15px">
<div style="padding:10px; margin-top:5px; text-align:center; border-bottom: {{data.task_container.color}} solid 10px; ">
<a href="?uuid={{ container.uuid }}">{{ data.task_container.name }}</a>&nbsp;
{% if data.task_container.type == 'docker' %}<img src="/static/img/docker-logo.svg" style="height:18px; width:18px; margin-bottom:4px" />{% endif %}
{% if data.task_container.type == 'singularity' %}<img src="/static/img/singularity-logo.svg" style="height:18px; width:18px; margin-bottom:4px" />{% endif %}
</div>
<div style="padding:10px; height: 64px; vertical-align: middle;">
<b>Image:</b> {{ data.task_container.image_name }}<br/>
<b>Version:</b> {{ data.task_container.image_tag }}
</div>
</div>
{% if data.step == 'two' %}
<form action="/create_task/" method="POST"> <form action="/create_task/" method="POST">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="step" value="one" /> <input type="hidden" name="step" value="{{ data.next_step }}" />
<input type="hidden" name="task_container_uuid" value="{{data.task_container.uuid}}">
<div style="width:300px; float:left; border: #e0e0e0 solid 0px; margin:10px; background:#f8f8f8; margin-bottom:15px">
<table class="dashboard" style="max-width:700px"> <table style="max-width:100%; border: #e0e0e0 solid 1px; margin:0">
<tr><td colspan="2"></td></tr> <tr><td colspan="2"></td></tr>
<tr> <tr>
<td><b>Task name </b></td> <td><b>Task name </b></td>
<td> <td>
<input type="text" name="task_name" value="" placeholder="" size="23" required /> <input type="text" name="task_name" value="" placeholder="" size="" required />
</td> </td>
</tr> </tr>
<tr> <tr>
<td><b>Task container</b></td><td> <td><b>Computing</b></td><td>
{% if data.task_container %}
<select name="task_container_uuid">
<option value="{{data.task_container.uuid}}" selected>{{data.task_container.name}} ({{data.task_container.type.title}})</option>
</select>
{% else %}
<select name="task_container_uuid" >
{% for container in data.containers %}
<option value="{{container.uuid}}">{{container.name}} ({{container.type.title}})</option>
{% endfor %}
</select>
{% endif %}
</td>
</tr>
<tr>
<td><b>Computing resource</b></td><td>
<select name="task_computing_uuid" > <select name="task_computing_uuid" >
{% for computing in data.computings %}} {% for computing in data.computings %}}
<option value="{{ computing.uuid }}">{{ computing.name}}</option> <option value="{{ computing.uuid }}">{{ computing.name}}</option>
...@@ -59,38 +63,30 @@ ...@@ -59,38 +63,30 @@
</tr> </tr>
<tr> <tr>
<td colspan=2 align=center style="padding:20px"> <td colspan=2 align=center style="padding:9px">
<input type="submit" value="Next"> <input type="submit" value="Next">
</td> </td>
</tr> </tr>
</table> </table>
</div>
</form> </form>
{% elif data.step == 'two' %} {% elif data.step == 'three' %}
<h3>Step 2: add authentication and computing details</h3>
<br/> <div style="width:300px; float:left; border: #e0e0e0 solid 0px; margin:10px; background:#f8f8f8; margin-bottom:15px">
<table class="dashboard" style="max-width:700px"> <table style="width:100%; height:126px; border: #e0e0e0 solid 1px; margin:0">
<tr><td colspan="2"></td></tr>
<tr> <tr valign="bottom">
<td><b>Task name </b></td> <td><b>Task name </b></td>
<td> <td>
<input type="text" name="task_name_RECAP" value="{{ data.task_name }}" placeholder="" size="23" disabled /> <input type="text" name="task_name_RECAP" value="{{ data.task_name }}" placeholder="" size="" disabled />
</td> </td>
</tr> </tr>
<tr>
<td><b>Task container</b></td><td>
<select name="task_container_uuid_RECAP">
<option value="" selected>{{data.task_container.name}} ({{data.task_container.type.title}})</option>
</select>
</td>
</tr>
<tr> <tr valign="top">
<td><b>Computing resource</b></td><td> <td><b>Computing</b></td><td>
<select name="task_computing_uuid_RECAP" > <select name="task_computing_uuid_RECAP" >
<option value="">{{ data.task_computing.name}}</option> <option value="">{{ data.task_computing.name}}</option>
</select> </select>
...@@ -98,8 +94,10 @@ ...@@ -98,8 +94,10 @@
</tr> </tr>
</table> </table>
</div>
<div style="width:640px; float:left; border: #e0e0e0 solid 0px; margin:10px; background:#f8f8f8; margin-bottom:15px">
<br>
{% if data.task_container.type == 'singularity' and not data.task_container.supports_dynamic_ports %} {% if data.task_container.type == 'singularity' and not data.task_container.supports_dynamic_ports %}
<div> <p style="font-size:15px; max-width:700px; margin-bottom:20px; margin-left:5px"> <div> <p style="font-size:15px; max-width:700px; margin-bottom:20px; margin-left:5px">
<i class="fa fa-exclamation-triangle" style="color:orange"></i> This container does not support dynamic ports and you are running it with Singularity, without network insulation. This means that if the container port is already occupied, it will not be able to start. <i class="fa fa-exclamation-triangle" style="color:orange"></i> This container does not support dynamic ports and you are running it with Singularity, without network insulation. This means that if the container port is already occupied, it will not be able to start.
...@@ -114,7 +112,8 @@ ...@@ -114,7 +112,8 @@
<form action="/create_task/" method="POST"> <form action="/create_task/" method="POST">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="step" value="two" /> <input type="hidden" name="task_container_uuid" value="{{data.task_container.uuid}}">
<input type="hidden" name="step" value="{{ data.next_step }}" />
<input type="hidden" name="task_name" value="{{ data.task_name }}" /> <input type="hidden" name="task_name" value="{{ data.task_name }}" />
<input type="hidden" name="task_container_uuid" value="{{ data.task_container.uuid }}" /> <input type="hidden" name="task_container_uuid" value="{{ data.task_container.uuid }}" />
<input type="hidden" name="task_computing_uuid" value="{{ data.task_computing.uuid }}" /> <input type="hidden" name="task_computing_uuid" value="{{ data.task_computing.uuid }}" />
...@@ -180,7 +179,7 @@ ...@@ -180,7 +179,7 @@
</td> </td>
</tr> --> </tr> -->
{% if data.task_computing.type == 'slurm' %} {% if data.task_computing.access_method == 'slurm+ssh' %}
<tr> <tr>
<td><b>Computing options</b></td> <td><b>Computing options</b></td>
<td> <td>
...@@ -207,6 +206,7 @@ ...@@ -207,6 +206,7 @@
</tr> </tr>
</table> </table>
</form> </form>
</div>
{% else %} {% else %}
......
...@@ -25,17 +25,6 @@ ...@@ -25,17 +25,6 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
<div style="display:table-row">
<div class="text-vertical-bottom">
{% if user.is_authenticated %}
<a href="/tasks" class="btn btn-dark btn-lg">Tasks</a>
<a href="/containers" class="btn btn-dark btn-lg">Containers</a>
{% else %}
<a href="/login" class="btn btn-dark btn-lg">Log In</a>
{% endif %}
</div>
</div>
</header> </header>
{% include "footer.html" %} {% include "footer.html" %}
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
{% if not data.task and not data.tasks %} {% if not data.task and not data.tasks %}
<div class="row" style="padding:10px; padding-left:15px"> <div class="row" style="padding:10px; padding-left:15px">
<i>Nothing here. To create a new task, choose a container from the "containers" menu entry and run it by hitting the play button.</i> <a href="/create_task">New task...</a>
</div> </div>
{% endif %} {% endif %}
......
...@@ -402,35 +402,12 @@ def create_task(request): ...@@ -402,35 +402,12 @@ def create_task(request):
data['profile'] = Profile.objects.get(user=request.user) data['profile'] = Profile.objects.get(user=request.user)
data['title'] = 'New Task' data['title'] = 'New Task'
# Step if any # Get task container helper function
step = request.POST.get('step', None) def get_task_container(request):
# Container uuid if any
container_uuid = request.GET.get('task_container_uuid', None)
if container_uuid:
try:
data['task_container'] = Container.objects.get(uuid=container_uuid, user=request.user)
except Container.DoesNotExist:
data['task_container'] = Container.objects.get(uuid=container_uuid, user=None)
else:
# Get containers
data['containers'] = list(Container.objects.filter(user=None)) + list(Container.objects.filter(user=request.user))
# Get computings
data['computings'] = list(Computing.objects.filter(user=None)) + list(Computing.objects.filter(user=request.user))
# Handle step
if step:
# Task name
task_name = request.POST.get('task_name', None)
if not task_name:
raise ErrorMessage('Missing task name')
data['task_name'] = task_name
# Task container
task_container_uuid = request.POST.get('task_container_uuid', None) task_container_uuid = request.POST.get('task_container_uuid', None)
if not task_container_uuid:
# At the second step the task uuid is set via a GET request
task_container_uuid = request.GET.get('task_container_uuid', None)
try: try:
task_container = Container.objects.get(uuid=task_container_uuid, user=None) task_container = Container.objects.get(uuid=task_container_uuid, user=None)
except Container.DoesNotExist: except Container.DoesNotExist:
...@@ -438,9 +415,10 @@ def create_task(request): ...@@ -438,9 +415,10 @@ def create_task(request):
task_container = Container.objects.get(uuid=task_container_uuid, user=request.user) task_container = Container.objects.get(uuid=task_container_uuid, user=request.user)
except Container.DoesNotExist: except Container.DoesNotExist:
raise Exception('Consistency error, container with uuid "{}" does not exists or user "{}" does not have access rights'.format(task_container_uuid, request.user.email)) raise Exception('Consistency error, container with uuid "{}" does not exists or user "{}" does not have access rights'.format(task_container_uuid, request.user.email))
data['task_container'] = task_container return task_container
# Task computing # Get task computing helper function
def get_task_computing(request):
task_computing_uuid = request.POST.get('task_computing_uuid', None) task_computing_uuid = request.POST.get('task_computing_uuid', None)
try: try:
task_computing = Computing.objects.get(uuid=task_computing_uuid, user=None) task_computing = Computing.objects.get(uuid=task_computing_uuid, user=None)
...@@ -450,26 +428,75 @@ def create_task(request): ...@@ -450,26 +428,75 @@ def create_task(request):
except Computing.DoesNotExist: except Computing.DoesNotExist:
raise Exception('Consistency error, computing with uuid "{}" does not exists or user "{}" does not have access rights'.format(task_computing_uuid, request.user.email)) raise Exception('Consistency error, computing with uuid "{}" does not exists or user "{}" does not have access rights'.format(task_computing_uuid, request.user.email))
task_computing.attach_user_conf(request.user) task_computing.attach_user_conf(request.user)
data['task_computing'] = task_computing return task_computing
# Get task name helper function
def get_task_name(request):
task_name = request.POST.get('task_name', None)
if not task_name:
raise ErrorMessage('Missing task name')
return task_name
# Handle step one/two # Get step if any, check both POST and GET
if step == 'one': step = request.POST.get('step', None)
if not step:
step = request.GET.get('step', None)
# Set step and task uuid
data['step'] = 'two' # Handle the various steps
if not step:
# Step one is assumed: chose software container
return HttpResponseRedirect('/containers/?mode=new_task')
elif step == 'two': elif step == 'two':
# Get software container
data['task_container'] = get_task_container(request)
# List all computing resources
data['computings'] = list(Computing.objects.filter(user=None)) + list(Computing.objects.filter(user=request.user))
data['step'] = 'two'
data['next_step'] = 'three'
elif step == 'three':
# Get software container
data['task_container'] = get_task_container(request)
# Get computing resource
data['task_computing'] = get_task_computing(request)
# Get task name
data['task_name'] = get_task_name(request)
# Set current and next step
data['step'] = 'three'
data['next_step'] = 'last'
elif step == 'last':
# Get software container
data['task_container'] = get_task_container(request)
# Get computing resource
data['task_computing'] = get_task_computing(request)
# Get task name
data['task_name'] = get_task_name(request)
# Generate the task uuid # Generate the task uuid
task_uuid = str(uuid.uuid4()) task_uuid = str(uuid.uuid4())
# Create the task object # Create the task object
task = Task(uuid = task_uuid, task = Task(uuid = task_uuid,
user = request.user, user = request.user,
name = task_name, name = data['task_name'],
status = TaskStatuses.created, status = TaskStatuses.created,
container = task_container, container = data['task_container'],
computing = task_computing) computing = data['task_computing'])
# Add auth # Add auth
task.auth_user = request.POST.get('auth_user', None) task.auth_user = request.POST.get('auth_user', None)
...@@ -534,10 +561,6 @@ def create_task(request): ...@@ -534,10 +561,6 @@ def create_task(request):
# Set step # Set step
data['step'] = 'created' data['step'] = 'created'
else:
# Set step
data['step'] = 'one'
return render(request, 'create_task.html', {'data': data}) return render(request, 'create_task.html', {'data': data})
...@@ -608,10 +631,15 @@ def containers(request): ...@@ -608,10 +631,15 @@ def containers(request):
search_text = request.POST.get('search_text', '') search_text = request.POST.get('search_text', '')
search_type = request.POST.get('search_type', 'All') search_type = request.POST.get('search_type', 'All')
# Set bak to page data # Set back to page data
data['search_type'] = search_type data['search_type'] = search_type
data['search_text'] = search_text data['search_text'] = search_text
# Are we using this page as first step of a new task?
data['mode'] = request.GET.get('mode', None)
if not data['mode']:
data['mode'] = request.POST.get('mode', None)
# Do we have to operate on a specific container? # Do we have to operate on a specific container?
if uuid: if uuid:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment