diff --git a/src/InSillyCloWeb/assemblies/models.py b/src/InSillyCloWeb/assemblies/models.py index b9a800390cac2ed56de138b31a5a8e5b1d664091..785a029d17637985e60125abd1c31203d219b5d8 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 0000000000000000000000000000000000000000..3a109201bc4d28e8ecd4507e64a800e0518d0086 --- /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 0000000000000000000000000000000000000000..eef42dca242f2c05e9036c8e52a32bba623beeba --- /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 8ef67788a5cfb4b3c12cdaab2b3de8a75d4908d1..ba9d99e20ff0e9105405ae1981495ffbc46c2b89 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 0793b9fd597da049e2cb5f2c248e009ac768bfdb..32602e1085aa2031bc71020ac142108019fcbf9a 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'