diff --git a/CLAUDE.md b/CLAUDE.md index 8d7c0ff..5ddcfd3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -41,6 +41,15 @@ docker compose exec web python manage.py createsuperuser docker compose exec web python manage.py setup_groups ``` +## Branching and Release Workflow + +- **`main`** — production branch. Only updated via PR from `develop`. +- **`develop`** — integration branch. All feature work merges here first. +- **Feature branches** — branch from `develop`, PR back to `develop`. +- **Release flow**: `feature-branch → develop (PR) → main (PR)`. Never PR directly to `main` from a feature branch. +- **Hotfixes**: branch from `main`, PR to `main`, then cherry-pick or merge back to `develop`. +- When committing directly to `develop` (e.g. small fixes), no PR is needed for the `develop` commit itself — the PR happens when `develop` merges to `main`. + ## Architecture ### Django Apps diff --git a/src/assets/views.py b/src/assets/views.py index e190652..5c63733 100644 --- a/src/assets/views.py +++ b/src/assets/views.py @@ -2351,12 +2351,23 @@ def location_detail(request, pk): descendant_ids = [loc.pk for loc in location.get_descendants()] all_location_ids = [location.pk] + descendant_ids + # Prefetch primary image to avoid N+1 queries + primary_image_prefetch = Prefetch( + "images", + queryset=AssetImage.objects.filter(is_primary=True), + to_attr="primary_images", + ) + # Base querysets for three tabs - present_qs = Asset.objects.filter( - current_location_id__in=all_location_ids, - status="active", - checked_out_to__isnull=True, - ).select_related("category", "category__department", "checked_out_to") + present_qs = ( + Asset.objects.filter( + current_location_id__in=all_location_ids, + status="active", + checked_out_to__isnull=True, + ) + .select_related("category", "category__department", "checked_out_to") + .prefetch_related(primary_image_prefetch) + ) # Subquery: due_date from most recent checkout transaction latest_checkout_due = ( @@ -2370,13 +2381,18 @@ def location_detail(request, pk): checked_out_to__isnull=False, ) .select_related("category", "category__department", "checked_out_to") + .prefetch_related(primary_image_prefetch) .annotate(checkout_due_date=Subquery(latest_checkout_due)) ) - draft_qs = Asset.objects.filter( - current_location_id__in=all_location_ids, - status="draft", - ).select_related("category", "category__department", "checked_out_to") + draft_qs = ( + Asset.objects.filter( + current_location_id__in=all_location_ids, + status="draft", + ) + .select_related("category", "category__department", "checked_out_to") + .prefetch_related(primary_image_prefetch) + ) # Tab counts present_count = present_qs.count() diff --git a/src/templates/assets/location_detail.html b/src/templates/assets/location_detail.html index 2215218..f745786 100644 --- a/src/templates/assets/location_detail.html +++ b/src/templates/assets/location_detail.html @@ -164,6 +164,7 @@

{{ child.name }}

+ @@ -175,6 +176,15 @@

{{ child.name }}

{% for asset in page_obj %} + @@ -202,7 +212,15 @@

{{ child.name }}

{% for asset in page_obj %} -
+
+
+ {% if asset.primary_image %} + + {% else %} + + {% endif %} +
+
{{ asset.name }}
{{ asset.barcode }}
@@ -223,6 +241,8 @@

{{ child.name }}

{% if asset.department %}{{ asset.department.name }}{% endif %} {{ asset.get_condition_display }}
+
+
{% endfor %}
diff --git a/src/templates/assets/location_form.html b/src/templates/assets/location_form.html index c2e180f..f73d3cf 100644 --- a/src/templates/assets/location_form.html +++ b/src/templates/assets/location_form.html @@ -54,6 +54,14 @@

Active

+ +
+ {{ form.is_checkable }} +
+ +

Enable check-out/check-in for this location as a unit. Intended for portable containers (boxes, cases, flight cases).

+
+
Name Barcode Category
+
+ {% if asset.primary_image %} + + {% else %} + + {% endif %} +
+
{{ asset.name }}