From 90f270c82390e368b6676b1b70b62ff1cb6d603b Mon Sep 17 00:00:00 2001 From: Julien FumeyY <julien.fumey@pasteur.fr> Date: Thu, 24 Apr 2025 12:01:27 +0200 Subject: [PATCH] add listview for simulatorjob --- src/InSillyCloWeb/assemblies/models.py | 32 ++++++----- .../assemblies/simulatorjob_card.html | 53 +++++++++++++++++++ .../assemblies/simulatorjob_list.html | 20 +++++++ src/InSillyCloWeb/assemblies/urls.py | 1 + src/InSillyCloWeb/assemblies/views.py | 17 ++++++ 5 files changed, 109 insertions(+), 14 deletions(-) create mode 100644 src/InSillyCloWeb/assemblies/templates/assemblies/simulatorjob_card.html create mode 100644 src/InSillyCloWeb/assemblies/templates/assemblies/simulatorjob_list.html diff --git a/src/InSillyCloWeb/assemblies/models.py b/src/InSillyCloWeb/assemblies/models.py index b9a8003..785a029 100644 --- a/src/InSillyCloWeb/assemblies/models.py +++ b/src/InSillyCloWeb/assemblies/models.py @@ -288,6 +288,20 @@ class SimulatorJob(models.Model): null=True, blank=True, ) + owner = models.ForeignKey( + User, + on_delete=models.CASCADE, + related_name='jobs', + null=True, + blank=True, + ) + owning_session = models.ForeignKey( + Session, + on_delete=models.CASCADE, + related_name='jobs', + null=True, + blank=True, + ) status = models.IntegerField(choices=JobStatus.choices, default=JobStatus.NEW) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) @@ -321,20 +335,6 @@ class SimulatorJob(models.Model): verbose_name="Restriction enzyme", help_text="Enzyme used to produce digestion gel", ) - owner = models.ForeignKey( - User, - on_delete=models.CASCADE, - related_name='jobs', - null=True, - blank=True, - ) - owning_session = models.ForeignKey( - Session, - on_delete=models.CASCADE, - related_name='jobs', - null=True, - blank=True, - ) ######################################################################### # Function and methods @@ -442,6 +442,10 @@ class SimulatorJob(models.Model): messages.error(request, utils.clear_sensitive_info(str(e), self)) return output + @property + def output_name(self): + pass + @property def db_ip_files(self): return [self.dbip_dir / file for file in os.listdir(self.dbip_dir)] diff --git a/src/InSillyCloWeb/assemblies/templates/assemblies/simulatorjob_card.html b/src/InSillyCloWeb/assemblies/templates/assemblies/simulatorjob_card.html new file mode 100644 index 0000000..3a10920 --- /dev/null +++ b/src/InSillyCloWeb/assemblies/templates/assemblies/simulatorjob_card.html @@ -0,0 +1,53 @@ +{% load assemblies_tags %} +{% load i18n %} + +<div class="card context-simulator"> + <div class="card-body row"> + <a class="col-12 col-xl-2 col-lg-3 col-md-3 me-md-4 text-decoration-none" href="{% url 'assemblies:simulator-detail' uuid=object.uuid %}"> + <div class="fw-bolder"> + Job #{{object.uuid_short}} + </div> + <small class="text-secondary"> + {{object|field_verbose_name:'updated_at'}}{%trans ':'%}<br/> + {{object.updated_at}} + </small> + </a> + <div class="col border-10 border-start border-primary ps-md-4"> + + <div class="d-block"> + <span class="fw-bolder"> + {{object|field_verbose_name_and_help_text:'restriction_enzyme_gel'}} + {%trans ':'%} + </span> + {{object.restriction_enzyme_gel}} + </div> + + + <div class="d-block"> + <span class="fw-bolder"> + {{object|field_verbose_name_and_help_text:'pcr_pairs_str'}} + {%trans ':'%} + </span> + {{object.pcr_pairs_str}} + </div> + + <div class="d-block mt-1"> + <span class="fw-bolder"> + {% trans "Plasmids"%} + {%for ip in object.input_parts.all %} + <div class="d-inline-flex px-3 py-0 mb-1 border border-{{ip.is_mandatory|yesno:'3,1'}} + rounded-5 border-designer" + >{{ip}}</div> + {%endfor%} + </div> + </div> + + <div class="col-auto"> + <a href="" + class="btn btn-designer btn-md"> + <i class="bi bi-cloud-arrow-down fs-3"></i> + </a> + </div> + + </div> +</div> diff --git a/src/InSillyCloWeb/assemblies/templates/assemblies/simulatorjob_list.html b/src/InSillyCloWeb/assemblies/templates/assemblies/simulatorjob_list.html new file mode 100644 index 0000000..eef42dc --- /dev/null +++ b/src/InSillyCloWeb/assemblies/templates/assemblies/simulatorjob_list.html @@ -0,0 +1,20 @@ +{% extends "assemblies/base.html" %} +{% load crispy_forms_tags %} +{% load i18n %} +{% load djangoscss %} +{% load assemblies_tags %} +{% load include_markdown %} +{% load sstatic %} + +{% block title %}{{object_list|class_verbose_name_plural}}{% endblock %} +{% block page_title %}{{object_list|class_verbose_name_plural}}{% endblock %} + +{% block content %} +{% for object in object_list %} + <div class="col-12 mb-4"> + {% include 'assemblies/simulatorjob_card.html' with object=object%} + </div> +{% empty %} +<div class="alert alert-warning">{% trans "No simulator job found" %}</div> +{%endfor%} +{%endblock content %} \ No newline at end of file diff --git a/src/InSillyCloWeb/assemblies/urls.py b/src/InSillyCloWeb/assemblies/urls.py index 8ef6778..ba9d99e 100644 --- a/src/InSillyCloWeb/assemblies/urls.py +++ b/src/InSillyCloWeb/assemblies/urls.py @@ -65,6 +65,7 @@ urlpatterns = [ path('', views.index, name='assembly-simulator'), path('assembly/', views.AssemblyListView.as_view(), name='assembly-list'), path('assembly/<int:pk>/', views.AssemblyDetailView.as_view(), name='assembly-detail'), + path('assembly-simulator/', views.JobSimulatorListView.as_view(), name='simulator-list'), path('assembly-simulator/create/<str:step>/', simulator_wizard, name='simulator-create-step'), path('assembly-simulator/create/', simulator_wizard, name='simulator-create'), path('assembly-simulator/<slug:uuid>/', views.JobSimulatorResult.as_view(), name='simulator-detail'), diff --git a/src/InSillyCloWeb/assemblies/views.py b/src/InSillyCloWeb/assemblies/views.py index 0793b9f..32602e1 100644 --- a/src/InSillyCloWeb/assemblies/views.py +++ b/src/InSillyCloWeb/assemblies/views.py @@ -11,6 +11,7 @@ from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ from django.views.generic import ListView, DetailView, View, DeleteView, UpdateView from django.views.generic.detail import SingleObjectMixin +from django.contrib.sessions.models import Session from . import mixins from assemblies import forms, models, utils @@ -112,6 +113,22 @@ class AssemblyDeleteView( return super().form_valid(form) +class JobSimulatorListView(ListView): + model = models.SimulatorJob + + def get_queryset(self): + qs = super().get_queryset() + + if not any([self.request.user.is_authenticated, self.request.session.session_key]): + return qs.none() + + if self.request.user.is_authenticated: + qs = qs.filter(owner=self.request.user) + elif self.request.session.session_key: + qs = qs.filter(owning_session=Session.objects.get(session_key=self.request.session.session_key)) + return qs + + class JobSimulatorResult(DetailView): model = models.SimulatorJob slug_field = 'uuid' -- GitLab