Skip to content

Commit cf352a6

Browse files
Add edit section features (#672)
2 parents 868a9b1 + 6a0795b commit cf352a6

File tree

6 files changed

+88
-34
lines changed

6 files changed

+88
-34
lines changed

backend/projectify/lib/htmx.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from urllib.parse import unquote, urlsplit, urlunsplit
1717

1818
from django.http import HttpRequest, HttpResponse
19-
from django.http.response import HttpResponseBase
19+
from django.http.response import HttpResponseBase, HttpResponseRedirectBase
2020
from django.utils.functional import cached_property
2121

2222
from asgiref.sync import iscoroutinefunction, markcoroutinefunction
@@ -121,6 +121,24 @@ def triggering_event(self) -> Any:
121121
return value
122122

123123

124+
class HttpResponseClientRedirect(HttpResponseRedirectBase):
125+
status_code = 200
126+
127+
def __init__(self, redirect_to: str, *args: Any, **kwargs: Any) -> None:
128+
if kwargs.get("preserve_request"):
129+
raise ValueError(
130+
"The 'preserve_request' argument is not supported for "
131+
"HttpResponseClientRedirect.",
132+
)
133+
super().__init__(redirect_to, *args, **kwargs)
134+
self["HX-Redirect"] = self["Location"]
135+
del self["Location"]
136+
137+
@property
138+
def url(self) -> str:
139+
return self["HX-Redirect"]
140+
141+
124142
class HttpResponseClientRefresh(HttpResponse):
125143
def __init__(self) -> None:
126144
super().__init__()

backend/projectify/workspace/dashboard_urls.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
)
1717
from projectify.workspace.views.section import (
1818
section_create_view,
19+
section_delete_view,
1920
section_update_view,
2021
)
2122
from projectify.workspace.views.task import (
@@ -144,6 +145,8 @@
144145
path("<uuid:section_uuid>/create-task", task_create, name="create-task"),
145146
# Update section
146147
path("<uuid:section_uuid>/update", section_update_view, name="update"),
148+
# Delete section
149+
path("<uuid:section_uuid>/delete", section_delete_view, name="delete"),
147150
)
148151
task_patterns = (
149152
path("<uuid:task_uuid>", task_detail, name="detail"),

backend/projectify/workspace/templates/workspace/project_detail/section.html

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,24 @@
55
<section data-section class="flex flex-col" id={{ section.uuid }}>
66
<header class="sticky top-0 flex w-full flex-row items-center justify-between bg-foreground px-4 py-2">
77
<div data-figma-name="Section header"
8-
class="flex min-w-0 shrink flex-row gap-4 text-base-content">
8+
class="flex min-w-0 shrink flex-row gap-4 items-center text-base-content">
99
<span class="h-5">{% include "heroicons/chevron-down.svg" %}</span>
10-
<h1 class="line-clamp-1 min-w-0 shrink font-bold">{{ section.title }}</h1>
10+
<div class="flex flex-row items-center">
11+
<h1 class="line-clamp-1 min-w-0 shrink font-bold">{{ section.title }}</h1>
12+
<a href="{% url 'dashboard:sections:update' section.uuid %}"
13+
aria-label="{% translate "Update section" %}"
14+
class="text-tertiary-content hover:text-tertiary-content-hover active:bg-tertiary-pressed active:text-tertiary-content-hover text-base flex min-w-max flex-row justify-center gap-2 rounded-lg px-4 py-2 font-bold disabled:bg-transparent disabled:text-disabled-content">
15+
<span class="h-4">{% include "heroicons/pencil.svg" %}</span>
16+
</a>
17+
</div>
1118
</div>
1219
<div class="flex shrink-0 flex-row items-center gap-1"
1320
data-figma-name="Right side">
1421
<a href="{% url "dashboard:sections:create-task" section.uuid %}"
1522
class="w-full text-tertiary-content hover:text-tertiary-content-hover active:bg-tertiary-pressed active:text-tertiary-content-hover text-base flex min-w-max flex-row justify-center gap-2 rounded-lg px-4 py-2 font-bold disabled:bg-transparent disabled:text-disabled-content">
1623
<span class="h-6">{% include "heroicons/plus.svg" %}</span>
17-
{% translate "Add task" %}
24+
{% translate "Add Task" %}
1825
</a>
19-
{# TODO make this a more button-y link, too #}
20-
<div class="shrink-0">
21-
{% url 'dashboard:sections:update' section.uuid as edit_section_url %}
22-
{% anchor href=edit_section_url label=_("Edit section") %}
23-
</div>
2426
</div>
2527
</header>
2628
<table class="flex flex-col gap-2 rounded-b-2xl bg-foreground p-4 lg:grid lg:grid-cols-[8fr_3fr_max-content] lg:gap-4">

backend/projectify/workspace/templates/workspace/section_update.html

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
class="min-w-0 grow"
1313
role="presentation">
1414
{{ form.errors }}
15-
<div class="flex h-full flex-col p-4 pt-0">
15+
<div class="flex h-full flex-col gap-8 p-4 pt-0">
1616
<div class="flex flex-col gap-8">
1717
<div class="flex flex-col gap-6">
1818
{{ form.title.as_field_group }}
@@ -26,29 +26,38 @@
2626
{% url 'dashboard:projects:detail' section.project.uuid as back_url %}
2727
{% anchor href=back_url label=_("Go back") %}
2828
</div>
29-
{% csrf_token %}
29+
<div class="flex flex-col gap-4">
30+
<h2 class="font-bold text-xl">{% translate "Section Actions" %}</h2>
31+
<div class="flex flex-col items-start gap-2">
32+
<h3 class="font-bold text-lg">{% translate "Move Section" %}</h3>
33+
<button class="flex flex-row gap-2 items-center"
34+
type="submit"
35+
name="action"
36+
value="move_up">
37+
<div class="h-4 w-4">{% include "heroicons/chevron-up.svg" %}</div>
38+
{% translate "Move up" %}
39+
</button>
40+
<button class="flex flex-row gap-2 items-center"
41+
type="submit"
42+
name="action"
43+
value="move_down">
44+
<div class="h-4 w-4">{% include "heroicons/chevron-down.svg" %}</div>
45+
{% translate "Move down" %}
46+
</button>
47+
</div>
48+
<div>
49+
<h3 class="font-bold text-lg">{% translate "Delete section" %}</h3>
50+
<button class="flex items-center gap-2 font-bold text-destructive"
51+
type="submit"
52+
hx-post="{% url 'dashboard:sections:delete' section_uuid=section.uuid %}"
53+
hx-confirm="{% translate "Are you sure you want to delete this section?" %}">
54+
<div class="h-4 w-4">{% include "heroicons/trash.svg" %}</div>
55+
{% translate "Delete this section" %}
56+
</button>
57+
</div>
58+
</div>
3059
</div>
3160
</div>
61+
{% csrf_token %}
3262
</form>
33-
<h2>{% translate "Section Actions" %}</h2>
34-
<div class="flex flex-col gap-4">
35-
<div>
36-
<h3>{% translate "Move Section" %}</h3>
37-
<div class="flex gap-2">
38-
<form method="post" class="inline">
39-
{% csrf_token %}
40-
<button type="submit" name="action" value="move_up">{% translate "Move Up" %}</button>
41-
</form>
42-
<form method="post" class="inline">
43-
{% csrf_token %}
44-
<button type="submit" name="action" value="move_down">{% translate "Move Down" %}</button>
45-
</form>
46-
</div>
47-
</div>
48-
<div>
49-
<h3>{% translate "Delete Section" %}</h3>
50-
{% url 'dashboard:sections:confirm-delete' section_uuid=section.uuid as delete_url %}
51-
{# TODO: Add delete section link when confirm-delete view is implemented #}
52-
</div>
53-
</div>
5463
{% endblock form_content %}

backend/projectify/workspace/views/section.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from django.shortcuts import render
1212
from django.urls import reverse
1313
from django.utils.translation import gettext_lazy as _
14+
from django.views.decorators.http import require_POST
1415

1516
from rest_framework import serializers, status
1617
from rest_framework.exceptions import NotFound
@@ -19,6 +20,7 @@
1920
from rest_framework.views import APIView
2021

2122
from projectify.lib.error_schema import DeriveSchema
23+
from projectify.lib.htmx import HttpResponseClientRedirect
2224
from projectify.lib.schema import extend_schema
2325
from projectify.lib.types import AuthenticatedHttpRequest
2426
from projectify.lib.views import platform_view
@@ -207,6 +209,25 @@ def section_update_view(
207209
return HttpResponseRedirect(project_url)
208210

209211

212+
@platform_view
213+
@require_POST
214+
def section_delete_view(
215+
request: AuthenticatedHttpRequest, section_uuid: UUID
216+
) -> HttpResponse:
217+
"""Update section view."""
218+
section = section_find_for_user_and_uuid(
219+
user=request.user, section_uuid=section_uuid
220+
)
221+
if section is None:
222+
raise Http404(_("Section not found for this UUID"))
223+
224+
project_url = reverse(
225+
"dashboard:projects:detail", args=(section.project.uuid,)
226+
)
227+
section_delete(who=request.user, section=section)
228+
return HttpResponseClientRedirect(project_url)
229+
230+
210231
class SectionCreate(APIView):
211232
"""Create a section."""
212233

docs/remove-fe-overlays.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ Missing: Delete button, style link; Justus 2025-12-05
202202
This replaces the **Edit section title** modal.
203203

204204
- [x] **View**: Create an update section view with the address `/dashboard/section/<uuid:section_uuid>/update`
205-
- [ ] **Link**: Change the ellipsis `...` button to say `Update section` in the section header and style it. Link to this view
205+
- [x] **Link**: Change the ellipsis `...` button to a pencil button next to the
206+
section title with `aria-label`.
206207
- [x] **Form contents**:
207208
- [x] Show section **title** and **description** fields
208209
- [x] **Update section**: Save the form contents to the section. Redirect back to
@@ -212,7 +213,7 @@ This replaces the **Edit section title** modal.
212213
- [x] **Section move** form:
213214
- [x] **Move up**: Move the section above the previous section
214215
- [x] **Move down**: Move the section below the next section
215-
- [ ] **Delete** button: Show a confirmation dialog. If the user presses **Ok**,
216+
- [x] **Delete** button: Show a confirmation dialog. If the user presses **Ok**,
216217
delete the section.
217218

218219
## Project archive

0 commit comments

Comments
 (0)