diff --git a/app/grandchallenge/cases/widgets.py b/app/grandchallenge/cases/widgets.py
index c2097df44..e679e5242 100644
--- a/app/grandchallenge/cases/widgets.py
+++ b/app/grandchallenge/cases/widgets.py
@@ -45,6 +45,8 @@ def __init__(
help_text=None,
user=None,
current_value=None,
+ submitted_value=None,
+ submitted_widget_choice=None,
disabled=False,
**kwargs,
):
@@ -58,6 +60,8 @@ def __init__(
"disabled": disabled,
"user": user,
"current_value": current_value,
+ "submitted_value": submitted_value,
+ "submitted_widget_choice": submitted_widget_choice,
"widget_choices": {
choice.name: choice.value for choice in WidgetChoices
},
diff --git a/app/grandchallenge/components/form_fields.py b/app/grandchallenge/components/form_fields.py
index 96081250a..ca72865b1 100644
--- a/app/grandchallenge/components/form_fields.py
+++ b/app/grandchallenge/components/form_fields.py
@@ -2,9 +2,11 @@
from django.forms import ModelChoiceField
from django.utils.functional import cached_property
+from grandchallenge.cases.models import Image
from grandchallenge.cases.widgets import (
FlexibleImageField,
FlexibleImageWidget,
+ WidgetChoices,
)
from grandchallenge.components.models import ComponentInterfaceValue
from grandchallenge.components.schemas import INTERFACE_VALUE_SCHEMA
@@ -102,10 +104,43 @@ def get_initial_value(self):
return self.initial
def get_image_field(self):
+
+ current_value = None
+ submitted_value = None
+ submitted_widget_choice = None
+
+ if self.initial is not None and not isinstance(
+ self.initial, ComponentInterfaceValue
+ ):
+
+ widget_choice_key = f"WidgetChoice-{INTERFACE_FORM_FIELD_PREFIX}{self.instance.slug}"
+
+ if (
+ widget_choice_key in self.form_data
+ and self.form_data[widget_choice_key]
+ not in WidgetChoices.names
+ ):
+ widget_choice_key = f"SubmittedWidgetChoice-{INTERFACE_FORM_FIELD_PREFIX}{self.instance.slug}"
+
+ if widget_choice_key in self.form_data:
+ submitted_widget_choice = self.form_data[widget_choice_key]
+ if self.form_data[widget_choice_key] == "IMAGE_SEARCH":
+ submitted_value = Image.objects.filter(
+ pk=self.initial
+ ).first()
+ elif self.form_data[widget_choice_key] == "IMAGE_UPLOAD":
+ submitted_value = UserUpload.objects.filter(
+ pk=self.initial
+ ).first()
+ else:
+ current_value = self.initial
+
self.kwargs["widget"] = FlexibleImageWidget(
help_text=self.help_text,
user=self.user,
- current_value=self.initial,
+ current_value=current_value,
+ submitted_value=submitted_value,
+ submitted_widget_choice=submitted_widget_choice,
# also passing the CIV as current value here so that we can
# show the image name to the user rather than its pk
)
From 44c478db6455aeba4ba68e2a6fd119a9475d70d0 Mon Sep 17 00:00:00 2001
From: Ammar Ammar <43293485+ammar257ammar@users.noreply.github.com>
Date: Thu, 31 Oct 2024 16:12:45 +0000
Subject: [PATCH 03/21] Rename variables
---
app/grandchallenge/cases/widgets.py | 8 ++++----
app/grandchallenge/components/form_fields.py | 16 ++++++++--------
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/app/grandchallenge/cases/widgets.py b/app/grandchallenge/cases/widgets.py
index e679e5242..d453712fd 100644
--- a/app/grandchallenge/cases/widgets.py
+++ b/app/grandchallenge/cases/widgets.py
@@ -45,8 +45,8 @@ def __init__(
help_text=None,
user=None,
current_value=None,
- submitted_value=None,
- submitted_widget_choice=None,
+ submit_value=None,
+ submit_widget_choice=None,
disabled=False,
**kwargs,
):
@@ -60,8 +60,8 @@ def __init__(
"disabled": disabled,
"user": user,
"current_value": current_value,
- "submitted_value": submitted_value,
- "submitted_widget_choice": submitted_widget_choice,
+ "submit_value": submit_value,
+ "submit_widget_choice": submit_widget_choice,
"widget_choices": {
choice.name: choice.value for choice in WidgetChoices
},
diff --git a/app/grandchallenge/components/form_fields.py b/app/grandchallenge/components/form_fields.py
index ca72865b1..ad9e87896 100644
--- a/app/grandchallenge/components/form_fields.py
+++ b/app/grandchallenge/components/form_fields.py
@@ -106,8 +106,8 @@ def get_initial_value(self):
def get_image_field(self):
current_value = None
- submitted_value = None
- submitted_widget_choice = None
+ submit_value = None
+ submit_widget_choice = None
if self.initial is not None and not isinstance(
self.initial, ComponentInterfaceValue
@@ -120,16 +120,16 @@ def get_image_field(self):
and self.form_data[widget_choice_key]
not in WidgetChoices.names
):
- widget_choice_key = f"SubmittedWidgetChoice-{INTERFACE_FORM_FIELD_PREFIX}{self.instance.slug}"
+ widget_choice_key = f"SubmitWidgetChoice-{INTERFACE_FORM_FIELD_PREFIX}{self.instance.slug}"
if widget_choice_key in self.form_data:
- submitted_widget_choice = self.form_data[widget_choice_key]
+ submit_widget_choice = self.form_data[widget_choice_key]
if self.form_data[widget_choice_key] == "IMAGE_SEARCH":
- submitted_value = Image.objects.filter(
+ submit_value = Image.objects.filter(
pk=self.initial
).first()
elif self.form_data[widget_choice_key] == "IMAGE_UPLOAD":
- submitted_value = UserUpload.objects.filter(
+ submit_value = UserUpload.objects.filter(
pk=self.initial
).first()
else:
@@ -139,8 +139,8 @@ def get_image_field(self):
help_text=self.help_text,
user=self.user,
current_value=current_value,
- submitted_value=submitted_value,
- submitted_widget_choice=submitted_widget_choice,
+ submit_value=submit_value,
+ submit_widget_choice=submit_widget_choice,
# also passing the CIV as current value here so that we can
# show the image name to the user rather than its pk
)
From 8c4c69e2a0e41fcce36f65c2ffdeac5b3b81196e Mon Sep 17 00:00:00 2001
From: Ammar Ammar <43293485+ammar257ammar@users.noreply.github.com>
Date: Thu, 31 Oct 2024 16:15:08 +0000
Subject: [PATCH 04/21] Rename variables in image widget template
---
.../cases/templates/cases/flexible_image_widget.html | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/app/grandchallenge/cases/templates/cases/flexible_image_widget.html b/app/grandchallenge/cases/templates/cases/flexible_image_widget.html
index dfb9856de..b2efbe1c0 100644
--- a/app/grandchallenge/cases/templates/cases/flexible_image_widget.html
+++ b/app/grandchallenge/cases/templates/cases/flexible_image_widget.html
@@ -8,8 +8,8 @@
hx-trigger="widgetSelected, change"
hx-include="[id='values-{{ widget.name }}']"
>
- {% if widget.attrs.submitted_value %}
-
+ {% if widget.attrs.submit_value %}
+
{% elif widget.attrs.current_value %}
{% else %}
@@ -26,9 +26,9 @@
- {% if widget.attrs.submitted_value %}
-
-
+ {% if widget.attrs.submit_value %}
+
+
{% endif %}
From c5db5e519182a5cae2afdc99d04b63617c6d0717 Mon Sep 17 00:00:00 2001
From: Ammar Ammar <43293485+ammar257ammar@users.noreply.github.com>
Date: Thu, 31 Oct 2024 16:42:03 +0000
Subject: [PATCH 05/21] clean condition
---
app/grandchallenge/components/form_fields.py | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/app/grandchallenge/components/form_fields.py b/app/grandchallenge/components/form_fields.py
index ad9e87896..32015c797 100644
--- a/app/grandchallenge/components/form_fields.py
+++ b/app/grandchallenge/components/form_fields.py
@@ -109,9 +109,7 @@ def get_image_field(self):
submit_value = None
submit_widget_choice = None
- if self.initial is not None and not isinstance(
- self.initial, ComponentInterfaceValue
- ):
+ if not isinstance(self.initial, ComponentInterfaceValue):
widget_choice_key = f"WidgetChoice-{INTERFACE_FORM_FIELD_PREFIX}{self.instance.slug}"
From 3de2e16ab39e7b189659d33160404bc51b46495e Mon Sep 17 00:00:00 2001
From: Ammar Ammar <43293485+ammar257ammar@users.noreply.github.com>
Date: Sat, 2 Nov 2024 11:14:40 +0000
Subject: [PATCH 06/21] Add title to Image and UserUpload to unify access
object name
---
app/grandchallenge/cases/models.py | 4 ++++
app/grandchallenge/uploads/models.py | 4 ++++
2 files changed, 8 insertions(+)
diff --git a/app/grandchallenge/cases/models.py b/app/grandchallenge/cases/models.py
index d391108b5..37ca8a7a7 100644
--- a/app/grandchallenge/cases/models.py
+++ b/app/grandchallenge/cases/models.py
@@ -390,6 +390,10 @@ class Image(UUIDModel):
def __str__(self):
return f"Image {self.name} {self.shape_without_color}"
+ @property
+ def title(self):
+ return self.name
+
@property
def shape_without_color(self) -> list[int]:
"""
diff --git a/app/grandchallenge/uploads/models.py b/app/grandchallenge/uploads/models.py
index 04e88e808..2066f6d78 100644
--- a/app/grandchallenge/uploads/models.py
+++ b/app/grandchallenge/uploads/models.py
@@ -93,6 +93,10 @@ def handle_file_validation_failure(self, *, error_message, linked_object):
status=linked_object.CANCELLED, error_message=error_message
)
+ @property
+ def title(self):
+ return self.filename
+
@property
def _client(self):
return _UPLOADS_CLIENT
From a501081f56c146fafd11771bd5fa47271a4e3876 Mon Sep 17 00:00:00 2001
From: Ammar Ammar <43293485+ammar257ammar@users.noreply.github.com>
Date: Sat, 2 Nov 2024 11:41:17 +0000
Subject: [PATCH 07/21] Add hidden input field with current value on form
redisplay submission
---
app/grandchallenge/cases/views.py | 33 ++++++++++++++++++++++++++-----
1 file changed, 28 insertions(+), 5 deletions(-)
diff --git a/app/grandchallenge/cases/views.py b/app/grandchallenge/cases/views.py
index 26878d30b..7fb8ae2f1 100644
--- a/app/grandchallenge/cases/views.py
+++ b/app/grandchallenge/cases/views.py
@@ -3,6 +3,7 @@
from django.conf import settings
from django.db.models import Q
+from django.forms import HiddenInput
from django.http import HttpResponse
from django.template.loader import render_to_string
from django.template.response import TemplateResponse
@@ -37,6 +38,7 @@
from grandchallenge.core.renderers import PaginatedCSVRenderer
from grandchallenge.datatables.views import Column, PaginatedTableListView
from grandchallenge.subdomains.utils import reverse_lazy
+from grandchallenge.uploads.models import UserUpload
from grandchallenge.uploads.widgets import UserUploadMultipleWidget
from grandchallenge.workstations.models import Workstation
@@ -142,11 +144,32 @@ def get(self, request, *args, **kwargs):
},
)
return HttpResponse(html_content)
- elif current_value and Image.objects.filter(pk=current_value).exists():
- # this can happen on the display set update view, where one of the options
- # is the current image, this enables switching back from one of the
- # above widgets to the chosen image
- return HttpResponse()
+ elif current_value and (
+ Image.objects.filter(pk=current_value).exists()
+ or UserUpload.objects.filter(pk=current_value).exists()
+ ):
+ # this can happen on the display set update view or redisplay of
+ # form upon validation, where one of the options is the current
+ # image, this enables switching back from one of the above widgets
+ # to the chosen image. In the case of form redisplay on validation
+ # error, current_value will be set in the flexible image widget
+ # select dropdown element with name starting with "WidgetChoice-"
+ # which will not be captured on resubmission, because the
+ # current_value is looked up from the form data element with
+ # interface name (in JobCreateForm and MultipleCIVForm). This make
+ # sure the form element with the right name is available on
+ # resubmission.
+ html_content = render_to_string(
+ HiddenInput.template_name,
+ {
+ "widget": {
+ "name": interface,
+ "value": current_value,
+ "type": "hidden",
+ },
+ },
+ )
+ return HttpResponse(html_content)
elif widget_name == WidgetChoices.UNDEFINED.name:
# this happens when switching back from one of the
# above widgets to the "Choose data source" option
From 745564fe0e9a89e65d2b0e5d1b5996cc42c2486b Mon Sep 17 00:00:00 2001
From: Ammar Ammar <43293485+ammar257ammar@users.noreply.github.com>
Date: Sat, 2 Nov 2024 11:42:41 +0000
Subject: [PATCH 08/21] Clean the implementation
---
.../cases/flexible_image_widget.html | 17 +++------
app/grandchallenge/cases/widgets.py | 4 --
app/grandchallenge/components/form_fields.py | 37 ++++---------------
3 files changed, 12 insertions(+), 46 deletions(-)
diff --git a/app/grandchallenge/cases/templates/cases/flexible_image_widget.html b/app/grandchallenge/cases/templates/cases/flexible_image_widget.html
index b2efbe1c0..b3dc640f5 100644
--- a/app/grandchallenge/cases/templates/cases/flexible_image_widget.html
+++ b/app/grandchallenge/cases/templates/cases/flexible_image_widget.html
@@ -5,13 +5,11 @@
id="widgetSelect-{{ widget.name }}"
hx-get="{% url 'cases:select-image-widget' %}"
hx-target="#area-{{ widget.name }}"
- hx-trigger="widgetSelected, change"
+ hx-trigger="widgetSelected, change, load"
hx-include="[id='values-{{ widget.name }}']"
>
- {% if widget.attrs.submit_value %}
-
- {% elif widget.attrs.current_value %}
-
+ {% if widget.attrs.current_value %}
+
{% else %}
{% endif %}
@@ -22,14 +20,9 @@