From 457fc76f9d6edee8728003257f143ee180d1e426 Mon Sep 17 00:00:00 2001 From: S4NKALP Date: Sun, 28 Jun 2026 19:15:35 +0545 Subject: [PATCH] feat(templates/projects): add manage statuses button and restricted mode UI Provides admin UI to manage statuses and prevents moving tickets to completed statuses --- templates/projects/board.html | 157 +++++++++++++++++- templates/projects/detail.html | 152 ++++++++++++++++- templates/projects/form.html | 15 +- templates/projects/list.html | 4 +- .../projects/partials/board_columns.html | 41 ++--- 5 files changed, 330 insertions(+), 39 deletions(-) diff --git a/templates/projects/board.html b/templates/projects/board.html index dacd7cf..283bd52 100644 --- a/templates/projects/board.html +++ b/templates/projects/board.html @@ -33,6 +33,18 @@ newTicketOpen: false, exportOpen: false, filterOpen: false, + manageStatusesOpen: false, + + createStatusName: '', + createStatusColor: '#6B7280', + createStatusOrder: '0', + createStatusCompleted: false, + + editStatusId: null, + editStatusName: '', + editStatusColor: '', + editStatusOrder: '0', + editStatusCompleted: false, ticketName: '', ticketDescription: '', @@ -187,6 +199,9 @@ touch.clientY >= rect.top && touch.clientY <= rect.bottom) targetColumn = col; col.classList.remove('bg-blue-50', 'dark:bg-blue-900/20'); }); + {% if not can_move_to_completed %} + if (targetColumn && targetColumn.getAttribute('data-status-completed') === 'true') targetColumn = null; + {% endif %} if (targetColumn && targetColumn !== originalColumn) this.moveTicketToStatus(this.draggingTicket, targetColumn.getAttribute('data-status-id')); this.draggingTicket = null; @@ -209,6 +224,9 @@ col.addEventListener('drop', (e) => { e.preventDefault(); col.classList.remove('bg-blue-50', 'dark:bg-blue-900/20'); + {% if not can_move_to_completed %} + if (col.getAttribute('data-status-completed') === 'true') return; + {% endif %} if (this.draggingTicket) { this.moveTicketToStatus(this.draggingTicket, col.getAttribute('data-status-id')); this.draggingTicket = null; @@ -297,6 +315,11 @@ class="space-y-6" + {% if is_admin %} + + {% endif %} @@ -345,6 +368,12 @@ class="space-y-6" View Only ModeYou can view tickets but cannot move them +{% elif not can_move_to_completed %} +
+
+ Restricted ModeYou can move tickets to active statuses only +
+
{% endif %} @@ -354,7 +383,7 @@ class="space-y-6"
{% for col in columns %}
+ data-status-id="{{ col.status.id }}" data-status-completed="{{ col.status.is_completed|lower }}">
@@ -416,11 +445,11 @@ class="space-y-6" {% if ticket.assignees.all %} {% for assignee in ticket.assignees.all|slice:":2" %}
- {{ assignee.get_full_name|default:assignee.username|first|upper }} - {{ assignee.get_full_name|default:assignee.username|truncatechars:8 }} + {{ assignee.get_full_name|default:assignee.username|first|upper }} + {{ assignee.get_full_name|default:assignee.username|truncatechars:8 }}
{% endfor %} - {% if ticket.assignees.all|length > 2 %}
+{{ ticket.assignees.all|length|add:"-2" }}
{% endif %} + {% if ticket.assignees.all|length > 2 %}
+{{ ticket.assignees.all|length|add:"-2" }}
{% endif %} {% else %}
Unassigned @@ -609,6 +638,126 @@ class="space-y-6"
+ +
+
+
+
+

Manage Ticket Statuses

+ +
+ + +
+

New Status

+
+ {% csrf_token %} + +
+ + +
+
+ +
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + + + + + + + + + + + {% for col in columns %} + + + + + + + + {% empty %} + + {% endfor %} + +
NameColorOrderCompletedActions
{{ col.status.name }} + + {{ col.status.color }} + + {{ col.status.sort_order }} + {% if col.status.is_completed %} + Yes + {% else %} + No + {% endif %} + + +
+ {% csrf_token %} + +
+ + +
+ + + + +
+ + +
+ +
+ {% csrf_token %} + + +
+
+
No statuses found.
+
+
+
+
+ {% endif %}
{% endblock %} diff --git a/templates/projects/detail.html b/templates/projects/detail.html index 086e49f..b9069d6 100644 --- a/templates/projects/detail.html +++ b/templates/projects/detail.html @@ -174,6 +174,11 @@

Ticket Statuses

+ {% if is_admin %} + + {% endif %}
@@ -203,6 +208,7 @@ {% if "color" in statuses_columns %}Color{% endif %} {% if "sort_order" in statuses_columns %}Order{% endif %} {% if "is_completed" in statuses_columns %}Completed{% endif %} + {% if is_admin %}Actions{% endif %} @@ -212,9 +218,23 @@ {% if "color" in statuses_columns %}{{ s.color }}{% endif %} {% if "sort_order" in statuses_columns %}{{ s.sort_order }}{% endif %} {% if "is_completed" in statuses_columns %}{% if s.is_completed %}Yes{% else %}No{% endif %}{% endif %} + {% if is_admin %} + + + + + + {% csrf_token %} + + + + + {% endif %} {% empty %} - No statuses found. + No statuses found. {% endfor %} @@ -558,6 +578,126 @@ {% include "components/external_dashboard_modal.html" with show_state="$store.projectDetail.externalModalOpen" %} + +
+
+
+
+

Manage Ticket Statuses

+ +
+ + +
+

New Status

+
+ {% csrf_token %} + +
+ + +
+
+ +
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + + + + + + + + + + + {% for s in statuses %} + + + + + + + + {% empty %} + + {% endfor %} + +
NameColorOrderCompletedActions
{{ s.name }} + + {{ s.color }} + + {{ s.sort_order }} + {% if s.is_completed %} + Yes + {% else %} + No + {% endif %} + + +
+ {% csrf_token %} + +
+ + +
+ + + + +
+ + +
+ +
+ {% csrf_token %} + + +
+
+
No statuses found.
+
+
+
+
+ {% endblock %} {% block extra_scripts %} @@ -571,6 +711,16 @@ notesSelectedIds: [], viewNoteOpen: false, viewNoteData: { id: '', title: '', content: '' }, + manageStatusesOpen: false, + createStatusName: '', + createStatusColor: '#6B7280', + createStatusOrder: '0', + createStatusCompleted: false, + editStatusId: null, + editStatusName: '', + editStatusColor: '', + editStatusOrder: '0', + editStatusCompleted: false, }); }); diff --git a/templates/projects/form.html b/templates/projects/form.html index b48828e..3ffe8ec 100644 --- a/templates/projects/form.html +++ b/templates/projects/form.html @@ -111,20 +111,9 @@
{% if not project %} -
- - +
+ After creating the project, you can define custom ticket statuses in the project settings.
- {% else %} -
{% endif %}
diff --git a/templates/projects/list.html b/templates/projects/list.html index f011a14..d0eccf0 100644 --- a/templates/projects/list.html +++ b/templates/projects/list.html @@ -17,7 +17,7 @@

{{ page_obj.paginator.count }} total projects

- {% if request.user.role != "member" %} + {% if request.user.is_admin %} New Project {% endif %}
@@ -215,7 +215,7 @@

No projects yet

- {% if request.user.role != "member" %} + {% if request.user.is_admin %} Create your first project {% endif %} diff --git a/templates/projects/partials/board_columns.html b/templates/projects/partials/board_columns.html index 7055203..c92ba67 100644 --- a/templates/projects/partials/board_columns.html +++ b/templates/projects/partials/board_columns.html @@ -19,26 +19,29 @@
{% for col in columns %} -
+ $el.classList.remove('ring-2', 'ring-blue-500'); + if (!dragging) return; + {% if not user_can_move_to_completed %} + if ($el.dataset.statusCompleted === 'true') return; + {% endif %} + const tid = dragging; + dragging = null; + const csrf = (document.cookie.split('; ').find(c => c.startsWith('csrftoken')) || '').split('=')[1]; + fetch('/api/tickets/' + tid + '/move/', { + method: 'PATCH', + headers: {'Content-Type': 'application/json', 'X-CSRFToken': csrf}, + body: JSON.stringify({status_id: $el.dataset.statusId}) + }).then(r => { + if (r.ok) { + const s = document.querySelector('[x-model=sort]'); + htmx.ajax('GET', '/dashboard/board/{{ project.id }}/data/?sort=' + (s ? s.value : 'created_at_desc'), {target: '#board-container', swap: 'outerHTML'}); + } + }); + ">
@@ -66,12 +69,12 @@
{% for assignee in ticket.assignees.all|slice:":3" %} -
+
{{ assignee.get_full_name|default:assignee.username|make_list|first|upper }}
{% endfor %} {% if ticket.assignees.count > 3 %} -
+{{ ticket.assignees.count|add:"-3" }}
+
+{{ ticket.assignees.count|add:"-3" }}
{% endif %}
{% if ticket.due_date %}