Enhance case inline editing and search functionality with improved UI and new subspecialty handling
This commit is contained in:
@@ -103,9 +103,9 @@
|
||||
{% endwith %}
|
||||
{% if can_edit %}
|
||||
<button class="btn btn-sm btn-link text-muted p-0 ms-2 quick-edit-button"
|
||||
hx-get="{% url 'atlas:case_inline_field' case.pk 'title' %}?edit=1&show_label=0"
|
||||
hx-target="#case-inline-title"
|
||||
hx-swap="innerHTML">quick edit</button>
|
||||
hx-get="{% url 'atlas:case_inline_field' case.pk 'title' %}?edit=1&show_label=0"
|
||||
hx-target="#case-inline-title"
|
||||
hx-swap="outerHTML">quick edit</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</h2>
|
||||
@@ -212,13 +212,23 @@
|
||||
|
||||
<div class="float-end text-end">
|
||||
{# Subspecialty badges (preserve any anchor returned by get_link) #}
|
||||
{% if case.subspecialty.all %}
|
||||
{% for sub in case.subspecialty.all %}
|
||||
<span class="badge bg-secondary ms-1">{{ sub.get_link|safe }}</span>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<span class="text-muted me-2">No subspecialty</span>
|
||||
{% endif %}
|
||||
<div class="quick-edit-wrap d-inline-block align-middle">
|
||||
<span id="case-inline-subspecialty">
|
||||
{% if case.subspecialty.all %}
|
||||
{% for sub in case.subspecialty.all %}
|
||||
<span class="badge bg-secondary ms-1">{{ sub.get_link|safe }}</span>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<span class="text-muted me-2">No subspecialty</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% if can_edit %}
|
||||
<button class="btn btn-sm btn-link text-muted p-0 ms-2 quick-edit-button"
|
||||
hx-get="{% url 'atlas:case_inline_field' case.pk 'subspecialty' %}?edit=1&show_label=0"
|
||||
hx-target="#case-inline-subspecialty"
|
||||
hx-swap="outerHTML">quick edit</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Pathological process badges #}
|
||||
{% if case.pathological_process.all %}
|
||||
@@ -232,9 +242,9 @@
|
||||
<span>Diagnostic certainty:</span>
|
||||
{% if can_edit %}
|
||||
<button class="btn btn-sm btn-link text-muted p-0 ms-2 quick-edit-button"
|
||||
hx-get="{% url 'atlas:case_inline_field' case.pk 'diagnostic_certainty' %}?edit=1&show_label=0"
|
||||
hx-target="#case-inline-diagnostic_certainty"
|
||||
hx-swap="innerHTML">quick edit</button>
|
||||
hx-get="{% url 'atlas:case_inline_field' case.pk 'diagnostic_certainty' %}?edit=1&show_label=0"
|
||||
hx-target="#case-inline-diagnostic_certainty"
|
||||
hx-swap="outerHTML">quick edit</button>
|
||||
{% endif %}
|
||||
{% url 'atlas:case_inline_field' case.pk 'diagnostic_certainty' as diag_url %}
|
||||
{% with endpoint_default=diag_url|add:"?show_label=0" endpoint_edit=diag_url|add:"?edit=1&show_label=0" %}
|
||||
@@ -268,9 +278,9 @@
|
||||
</div>
|
||||
{% if can_edit %}
|
||||
<button class="btn btn-sm btn-link text-muted p-0 ms-2 quick-edit-button"
|
||||
hx-get="{% url 'atlas:case_inline_field' case.pk 'description' %}?edit=1&show_label=0"
|
||||
hx-target="#case-inline-description"
|
||||
hx-swap="innerHTML">quick edit</button>
|
||||
hx-get="{% url 'atlas:case_inline_field' case.pk 'description' %}?edit=1&show_label=0"
|
||||
hx-target="#case-inline-description"
|
||||
hx-swap="outerHTML">quick edit</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -288,19 +298,17 @@
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center quick-edit-wrap">History
|
||||
{% if can_edit %}
|
||||
<button class="btn btn-sm btn-link text-muted p-0 quick-edit-button"
|
||||
<button class="btn btn-sm btn-link text-muted p-0 quick-edit-button"
|
||||
hx-get="{% url 'atlas:case_inline_field' case.pk 'history' %}?edit=1&show_label=0"
|
||||
hx-target="#case-inline-history"
|
||||
hx-swap="innerHTML">quick edit</button>
|
||||
hx-swap="outerHTML">quick edit</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="case-inline-history"
|
||||
hx-get="{% url 'atlas:case_inline_field' case.pk 'history' %}?show_label=0"
|
||||
hx-trigger="load"
|
||||
hx-swap="innerHTML">
|
||||
<div class="pre-whitespace">{{ case.history|linebreaks }}</div>
|
||||
</div>
|
||||
{% url 'atlas:case_inline_field' case.pk 'history' as history_url %}
|
||||
{% with endpoint_default=history_url|add:"?show_label=0" endpoint_edit=history_url|add:"?edit=1&show_label=0" %}
|
||||
{% include 'atlas/partials/case_inline_field.html' with show_label=0 editing=False field_label="History" can_edit=can_edit endpoint_url_default=endpoint_default endpoint_url_edit=endpoint_edit container_id='case-inline-history' field_kind='textarea' value=case.history display_value=case.history field_name='history' error_message='' %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -308,19 +316,17 @@
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center quick-edit-wrap">Discussion
|
||||
{% if can_edit %}
|
||||
<button class="btn btn-sm btn-link text-muted p-0 quick-edit-button"
|
||||
<button class="btn btn-sm btn-link text-muted p-0 quick-edit-button"
|
||||
hx-get="{% url 'atlas:case_inline_field' case.pk 'discussion' %}?edit=1&show_label=0"
|
||||
hx-target="#case-inline-discussion"
|
||||
hx-swap="innerHTML">quick edit</button>
|
||||
hx-swap="outerHTML">quick edit</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="case-inline-discussion"
|
||||
hx-get="{% url 'atlas:case_inline_field' case.pk 'discussion' %}?show_label=0"
|
||||
hx-trigger="load"
|
||||
hx-swap="innerHTML">
|
||||
<div class="pre-whitespace">{{ case.discussion|linebreaks }}</div>
|
||||
</div>
|
||||
{% url 'atlas:case_inline_field' case.pk 'discussion' as discussion_url %}
|
||||
{% with endpoint_default=discussion_url|add:"?show_label=0" endpoint_edit=discussion_url|add:"?edit=1&show_label=0" %}
|
||||
{% include 'atlas/partials/case_inline_field.html' with show_label=0 editing=False field_label="Discussion" can_edit=can_edit endpoint_url_default=endpoint_default endpoint_url_edit=endpoint_edit container_id='case-inline-discussion' field_kind='textarea' value=case.discussion display_value=case.discussion field_name='discussion' error_message='' %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -328,19 +334,17 @@
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center quick-edit-wrap">Report
|
||||
{% if can_edit %}
|
||||
<button class="btn btn-sm btn-link text-muted p-0 quick-edit-button"
|
||||
<button class="btn btn-sm btn-link text-muted p-0 quick-edit-button"
|
||||
hx-get="{% url 'atlas:case_inline_field' case.pk 'report' %}?edit=1&show_label=0"
|
||||
hx-target="#case-inline-report"
|
||||
hx-swap="innerHTML">quick edit</button>
|
||||
hx-swap="outerHTML">quick edit</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="case-inline-report"
|
||||
hx-get="{% url 'atlas:case_inline_field' case.pk 'report' %}?show_label=0"
|
||||
hx-trigger="load"
|
||||
hx-swap="innerHTML">
|
||||
<div class="pre-whitespace">{{ case.report|linebreaks }}</div>
|
||||
</div>
|
||||
{% url 'atlas:case_inline_field' case.pk 'report' as report_url %}
|
||||
{% with endpoint_default=report_url|add:"?show_label=0" endpoint_edit=report_url|add:"?edit=1&show_label=0" %}
|
||||
{% include 'atlas/partials/case_inline_field.html' with show_label=0 editing=False field_label="Report" can_edit=can_edit endpoint_url_default=endpoint_default endpoint_url_edit=endpoint_edit container_id='case-inline-report' field_kind='textarea' value=case.report display_value=case.report field_name='report' error_message='' %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
{# Unified single case item used by search results and recent-created lists #}
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center" data-case-pk="{{ case.pk }}">
|
||||
<div class="flex-fill me-3">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h6 class="mb-1">{{ case.title }}</h6>
|
||||
<small class="text-muted">{{ case.created_date|date:"Y-m-d" }}</small>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<small class="text-muted me-2">{% if case.author.all %}By {{ case.author.all|join:", " }}{% endif %}</small>
|
||||
{% for cond in case.condition.all %}
|
||||
{% if cond.name %}<span class="badge bg-secondary me-1" title="Condition: {{ cond.name }}">{{ cond.name }}</span>{% endif %}
|
||||
{% endfor %}
|
||||
{% for pres in case.presentation.all %}
|
||||
{% if pres.name %}<span class="badge bg-secondary me-1" title="Presentation: {{ pres.name }}">{{ pres.name }}</span>{% endif %}
|
||||
{% endfor %}
|
||||
{% for ss in case.subspecialty.all %}
|
||||
{% if ss.name %}<span class="badge bg-secondary" title="Subspecialty: {{ ss.name }}">{{ ss.name }}</span>{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<p class="mb-1 text-truncate">{% if case.description %}{{ case.description|truncatechars:140 }}{% endif %}</p>
|
||||
</div>
|
||||
<div class="ms-2 d-flex align-items-center">
|
||||
{% if collection %}
|
||||
<form class="m-0" hx-post="{% url 'atlas:add_case_to_collection' collection.pk %}" hx-target="#full-question-list" hx-swap="beforeend">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="case" value="{{ case.pk }}">
|
||||
<button type="submit" class="btn btn-sm btn-outline-primary">Add</button>
|
||||
</form>
|
||||
<a class="btn btn-sm btn-outline-secondary ms-2" href="{% url 'atlas:case_detail' case.pk %}" target="_blank" rel="noopener">View</a>
|
||||
{% else %}
|
||||
<a class="btn btn-sm btn-outline-secondary" href="{% url 'atlas:case_displaysets' case.pk %}">View</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,24 +1,16 @@
|
||||
<div class="case-inline-field">
|
||||
<div id="{{ container_id }}" class="case-inline-field">
|
||||
{% if show_label or editing %}
|
||||
<div class="d-flex {% if show_label %}justify-content-between{% else %}justify-content-end{% endif %} align-items-start gap-2">
|
||||
{% if show_label %}
|
||||
<strong>{{ field_label }}:</strong>
|
||||
{% endif %}
|
||||
{% if can_edit %}
|
||||
{% if editing %}
|
||||
<button class="btn btn-sm btn-outline-secondary"
|
||||
type="button"
|
||||
hx-get="{{ endpoint_url_default }}"
|
||||
hx-target="#{{ container_id }}"
|
||||
hx-swap="innerHTML">
|
||||
Cancel
|
||||
</button>
|
||||
{% else %}
|
||||
{% if not editing %}
|
||||
<button class="quick-edit-trigger quick-edit-button"
|
||||
type="button"
|
||||
hx-get="{{ endpoint_url_edit }}"
|
||||
hx-target="#{{ container_id }}"
|
||||
hx-swap="innerHTML">
|
||||
hx-swap="outerHTML">
|
||||
quick edit
|
||||
</button>
|
||||
{% endif %}
|
||||
@@ -27,17 +19,21 @@
|
||||
{% endif %}
|
||||
|
||||
{% if editing %}
|
||||
<form hx-post="{{ endpoint_url_default }}"
|
||||
<form hx-post="{{ endpoint_url_default }}"
|
||||
hx-target="#{{ container_id }}"
|
||||
hx-swap="innerHTML"
|
||||
hx-swap="outerHTML"
|
||||
class="mt-2">
|
||||
{% csrf_token %}
|
||||
{% if field_kind == "textarea" %}
|
||||
<textarea class="form-control" name="value" rows="4">{{ value|default_if_none:"" }}</textarea>
|
||||
{% elif field_kind == "select" %}
|
||||
<select class="form-select" name="value">
|
||||
<select class="form-select" name="value" {% if multiple %}multiple{% endif %}>
|
||||
{% for option_value, option_label in select_choices %}
|
||||
<option value="{{ option_value }}" {% if value|stringformat:"s" == option_value %}selected{% endif %}>{{ option_label }}</option>
|
||||
{% if multiple %}
|
||||
<option value="{{ option_value }}" {% if option_value|stringformat:"s" in selected_values %}selected{% endif %}>{{ option_label }}</option>
|
||||
{% else %}
|
||||
<option value="{{ option_value }}" {% if value|stringformat:"s" == option_value %}selected{% endif %}>{{ option_label }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% else %}
|
||||
@@ -64,8 +60,12 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="mt-2">
|
||||
<div class="mt-2 d-flex gap-2">
|
||||
<button class="btn btn-sm btn-primary" type="submit">Save</button>
|
||||
<button class="btn btn-sm btn-outline-secondary" type="button"
|
||||
hx-get="{{ endpoint_url_default }}"
|
||||
hx-target="#{{ container_id }}"
|
||||
hx-swap="outerHTML">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
{% else %}
|
||||
|
||||
@@ -2,38 +2,7 @@
|
||||
{% if cases and cases|length > 0 %}
|
||||
<div class="list-group mb-2">
|
||||
{% for case in cases %}
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center" data-case-pk="{{ case.pk }}">
|
||||
<div class="flex-fill me-3">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h6 class="mb-1">{{ case.title }}</h6>
|
||||
<small class="text-muted">{{ case.created_date|date:"Y-m-d" }}</small>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<small class="text-muted me-2">{% if case.author.all %}By {{ case.author.all|join:", " }}{% endif %}</small>
|
||||
{% for cond in case.condition.all %}
|
||||
{% if cond.name %}<span class="badge bg-secondary me-1" title="Condition: {{ cond.name }}">{{ cond.name }}</span>{% endif %}
|
||||
{% endfor %}
|
||||
{% for pres in case.presentation.all %}
|
||||
{% if pres.name %}<span class="badge bg-secondary me-1" title="Presentation: {{ pres.name }}">{{ pres.name }}</span>{% endif %}
|
||||
{% endfor %}
|
||||
{% for ss in case.subspecialty.all %}
|
||||
{% if ss.name %}<span class="badge bg-secondary" title="Subspecialty: {{ ss.name }}">{{ ss.name }}</span>{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<p class="mb-1 text-truncate">{% if case.description %}{{ case.description|truncatechars:140 }}{% endif %}</p>
|
||||
</div>
|
||||
<div class="ms-2">
|
||||
{% if collection %}
|
||||
<form class="m-0" hx-post="{% url 'atlas:add_case_to_collection' collection.pk %}" hx-target="#full-question-list" hx-swap="beforeend">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="case" value="{{ case.pk }}">
|
||||
<button type="submit" class="btn btn-sm btn-outline-primary">Add</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<a class="btn btn-sm btn-outline-secondary" href="{% url 'atlas:case_displaysets' case.pk %}">View</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% include 'atlas/partials/_case_search_item.html' with case=case collection=collection %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
@@ -46,39 +15,7 @@
|
||||
<div class="small text-muted mb-1">Recently created</div>
|
||||
<div class="list-group">
|
||||
{% for case in recent_cases %}
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center" data-case-pk="{{ case.pk }}">
|
||||
<div class="flex-fill me-3">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h6 class="mb-1">{{ case.title }}</h6>
|
||||
<small class="text-muted">{{ case.created_date|date:"Y-m-d" }}</small>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<small class="text-muted me-2">{% if case.author.all %}By {{ case.author.all|join:", " }}{% endif %}</small>
|
||||
{% for cond in case.condition.all %}
|
||||
{% if cond.name %}<span class="badge bg-secondary me-1" title="Condition: {{ cond.name }}">{{ cond.name }}</span>{% endif %}
|
||||
{% endfor %}
|
||||
{% for pres in case.presentation.all %}
|
||||
{% if pres.name %}<span class="badge bg-secondary me-1" title="Presentation: {{ pres.name }}">{{ pres.name }}</span>{% endif %}
|
||||
{% endfor %}
|
||||
{% for ss in case.subspecialty.all %}
|
||||
{% if ss.name %}<span class="badge bg-secondary" title="Subspecialty: {{ ss.name }}">{{ ss.name }}</span>{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<p class="mb-1 text-truncate">{% if case.description %}{{ case.description|truncatechars:100 }}{% endif %}</p>
|
||||
</div>
|
||||
<div class="ms-2 d-flex align-items-center">
|
||||
{% if collection %}
|
||||
<form class="m-0" hx-post="{% url 'atlas:add_case_to_collection' collection.pk %}" hx-target="#full-question-list" hx-swap="beforeend">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="case" value="{{ case.pk }}">
|
||||
<button type="submit" class="btn btn-sm btn-outline-primary">Add</button>
|
||||
</form>
|
||||
<a class="btn btn-sm btn-outline-secondary ms-2" href="{% url 'atlas:case_detail' case.pk %}" target="_blank" rel="noopener">View</a>
|
||||
{% else %}
|
||||
<a class="btn btn-sm btn-outline-secondary" href="{% url 'atlas:case_displaysets' case.pk %}">View</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% include 'atlas/partials/_case_search_item.html' with case=case collection=collection %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -192,9 +192,13 @@
|
||||
<script>
|
||||
// Handle selecting a case from the modal results to import selected series into it
|
||||
document.body.addEventListener('click', async function (e) {
|
||||
// Only handle clicks inside the case select modal results
|
||||
// Only handle clicks inside the case select modal results, but ignore clicks on interactive controls inside the item
|
||||
const anchor = e.target.closest('#case-search-results-modal .list-group-item, #case-search-results-modal .list-group-item-action');
|
||||
if (!anchor) return;
|
||||
if (e.target.closest('#case-search-results-modal .list-group-item a, #case-search-results-modal .list-group-item button, #case-search-results-modal .list-group-item form, #case-search-results-modal .list-group-item input')) {
|
||||
// Let buttons/links/forms behave normally (e.g. View link)
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
// Determine case pk: prefer data-case-pk, else parse from href
|
||||
let casePk = anchor.getAttribute('data-case-pk');
|
||||
@@ -208,24 +212,30 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// Gather selected series (same logic as import button)
|
||||
const selected = Array.from(document.querySelectorAll('input[name="selection"]:checked'))
|
||||
.filter(cb => !cb.disabled)
|
||||
.map(cb => cb.value);
|
||||
// Get a display title for confirmation
|
||||
let caseTitle = anchor.querySelector('h6') ? anchor.querySelector('h6').textContent.trim() : null;
|
||||
if (!caseTitle) caseTitle = `#${casePk}`;
|
||||
|
||||
// Confirm with the user before importing
|
||||
const checkboxes = Array.from(document.querySelectorAll('input[name="selection"]:checked'));
|
||||
const allCheckboxes = Array.from(document.querySelectorAll('input[name="selection"]'));
|
||||
const selectable = allCheckboxes.filter(cb => !cb.disabled).map(cb => cb.value);
|
||||
const selection = selected.length ? selected : selectable;
|
||||
if (!selection.length) {
|
||||
const selectionList = checkboxes.length ? checkboxes.map(cb => cb.value) : selectable;
|
||||
if (!selectionList.length) {
|
||||
alert('Please select at least one series to import into the case.');
|
||||
return;
|
||||
}
|
||||
const confirmMsg = `Import ${selectionList.length} series into case "${caseTitle}" (ID ${casePk})?`;
|
||||
if (!window.confirm(confirmMsg)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build import URL template and replace trailing 0 with casePk
|
||||
const importTemplate = "{% url 'api-1:import_dicoms_case' 0 %}";
|
||||
const importUrl = importTemplate.replace(/0\/?$/, casePk + '/');
|
||||
|
||||
const form = new URLSearchParams();
|
||||
for (const s of selection) form.append('selection', s);
|
||||
for (const s of selectionList) form.append('selection', s);
|
||||
const orderSeriesInput = document.querySelector('input[name="order-series"]:checked');
|
||||
if (orderSeriesInput) form.append('order-series', orderSeriesInput.value);
|
||||
|
||||
|
||||
+57
-18
@@ -761,6 +761,7 @@ CASE_INLINE_FIELD_CONFIG = {
|
||||
"discussion": {"label": "Discussion", "kind": "textarea"},
|
||||
"report": {"label": "Report", "kind": "textarea"},
|
||||
"diagnostic_certainty": {"label": "Diagnostic certainty", "kind": "select"},
|
||||
"subspecialty": {"label": "Subspecialty", "kind": "select"},
|
||||
}
|
||||
|
||||
|
||||
@@ -883,33 +884,69 @@ def case_inline_field(request, pk, field_name):
|
||||
show_label = request.GET.get("show_label", "1") not in ("0", "false", "False")
|
||||
error_message = ""
|
||||
|
||||
if request.method == "POST":
|
||||
if not can_edit:
|
||||
return HttpResponse(status=403)
|
||||
|
||||
editing = True
|
||||
cleaned_value, error_message = _validate_case_inline_value(
|
||||
field_name=field_name,
|
||||
raw_value=request.POST.get("value", ""),
|
||||
)
|
||||
if error_message:
|
||||
value = request.POST.get("value", "")
|
||||
# Special-case handling for many-to-many `subspecialty` field
|
||||
if field_name == "subspecialty":
|
||||
if request.method == "POST":
|
||||
if not can_edit:
|
||||
return HttpResponse(status=403)
|
||||
editing = True
|
||||
# Accept multiple values via POST list
|
||||
posted = request.POST.getlist("value")
|
||||
ids = []
|
||||
for v in posted:
|
||||
try:
|
||||
ids.append(int(v))
|
||||
except Exception:
|
||||
continue
|
||||
# keep only valid existing ids
|
||||
valid_ids = list(
|
||||
Subspecialty.objects.filter(pk__in=ids).values_list("pk", flat=True)
|
||||
)
|
||||
case.subspecialty.set(valid_ids)
|
||||
editing = False
|
||||
value = case.subspecialty.all()
|
||||
else:
|
||||
setattr(case, field_name, cleaned_value)
|
||||
case.save(update_fields=[field_name])
|
||||
editing = False
|
||||
value = getattr(case, field_name)
|
||||
value = case.subspecialty.all()
|
||||
if editing and not can_edit:
|
||||
editing = False
|
||||
else:
|
||||
value = getattr(case, field_name)
|
||||
if editing and not can_edit:
|
||||
editing = False
|
||||
if request.method == "POST":
|
||||
if not can_edit:
|
||||
return HttpResponse(status=403)
|
||||
|
||||
editing = True
|
||||
cleaned_value, error_message = _validate_case_inline_value(
|
||||
field_name=field_name,
|
||||
raw_value=request.POST.get("value", ""),
|
||||
)
|
||||
if error_message:
|
||||
value = request.POST.get("value", "")
|
||||
else:
|
||||
setattr(case, field_name, cleaned_value)
|
||||
case.save(update_fields=[field_name])
|
||||
editing = False
|
||||
value = getattr(case, field_name)
|
||||
else:
|
||||
value = getattr(case, field_name)
|
||||
if editing and not can_edit:
|
||||
editing = False
|
||||
|
||||
if field_name == "diagnostic_certainty":
|
||||
display_value = case.get_diagnostic_certainty_display()
|
||||
select_choices = [(str(choice.value), str(choice.label)) for choice in Case.CertaintyChoices]
|
||||
selected_values = []
|
||||
multiple = False
|
||||
elif field_name == "subspecialty":
|
||||
# For many-to-many, provide choices and selected values
|
||||
display_value = ", ".join([str(s) for s in case.subspecialty.all()])
|
||||
select_choices = [(str(s.pk), str(s.name)) for s in Subspecialty.objects.all()]
|
||||
selected_values = [str(s.pk) for s in case.subspecialty.all()]
|
||||
multiple = True
|
||||
else:
|
||||
display_value = value
|
||||
select_choices = []
|
||||
selected_values = []
|
||||
multiple = False
|
||||
|
||||
endpoint_url = reverse("atlas:case_inline_field", kwargs={"pk": case.pk, "field_name": field_name})
|
||||
if show_label:
|
||||
@@ -934,6 +971,8 @@ def case_inline_field(request, pk, field_name):
|
||||
"error_message": error_message,
|
||||
"suggestions": _get_case_inline_suggestions(case, field_name),
|
||||
"select_choices": select_choices,
|
||||
"selected_values": selected_values,
|
||||
"multiple": multiple,
|
||||
"endpoint_url_default": endpoint_url_default,
|
||||
"endpoint_url_edit": endpoint_url_edit,
|
||||
"container_id": f"case-inline-{field_name}",
|
||||
|
||||
Reference in New Issue
Block a user