FossilRepo

Add HTMX live reload banner, ticket edit/comment forms Live reload (P1): - Polls timeline every 30 seconds for changes - Shows "Repository updated — Refresh" banner when new checkins detected - Dismissable, auto-detects via entry count comparison - Included on timeline page Ticket CRUD (P1): - Edit form: change status, type, severity, priority, resolution - Comment form: add markdown comment to ticket thread - Edit button on ticket detail header - Uses fossil ticket change CLI

lmata 2026-04-07 01:53 UTC trunk
Commit c8d5d08699c9f36100570b3a16b1c7736095149e2c414793cb7aab40385f612f
--- a/templates/fossil/_live_reload.html
+++ b/templates/fossil/_live_reload.html
@@ -0,0 +1,39 @@
1
+{% comment %}
2
+HTMX-based live reload detection for Fossil repository changes.
3
+Include on pages that should auto-detect when the .fossil file changes.
4
+Polls every 30 seconds and shows a banner if the repo has been updated.
5
+{% endcomment %}
6
+{% if fossil_repo %}
7
+<div id="live-reload-banner" class="hidden fixed top-16 left-0 right-0 z-40 bg-brand/90 text-white text-sm text-center py-2 px-4"
8
+ x-data="{ show: false }"
9
+ x-show="show"
10
+ x-transition>
11
+ <div class="flex items-center justify-center gap-3">
12
+ <svg class="h-4 w-4 animate-pulse" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
13
+ <path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182" />
14
+ </svg>
15
+ <span>Repository updated</span>
16
+ <button onclick="location.reload()" class="underline font-semibold">Refresh</button>
17
+ <button @click="show = false" class="ml-2 opacity-70 hover:opacity-100">&times;</button>
18
+ </div>
19
+</div>
20
+<script>
21
+ (function() {
22
+ let lastCount = {{ fossil_repo.checkin_count }};
23
+ setInterval(function() {
24
+ fetch('{% url "fossil:timeline" slug=project.slug %}?page=1&type=ci', { headers: { 'HX-Request': 'true' } })
25
+ .then(r => r.text())
26
+ .then(html => {
27
+ // Count entries in the response as a quick proxy for "has changed"
28
+ const matches = html.match(/tl-row/g);
29
+ const count = matches ? matches.length : 0;
30
+ if (count > 0 && count !== lastCount) {
31
+ document.querySelector('#live-reload-banner')?.__x?.$data && (document.querySelector('#live-reload-banner').__x.$data.show = true);
32
+ lastCount = count;
33
+ }
34
+ })
35
+ .catch(() => {});
36
+ }, 30000);
37
+ })();
38
+</script>
39
+{% endif %}
--- a/templates/fossil/_live_reload.html
+++ b/templates/fossil/_live_reload.html
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/templates/fossil/_live_reload.html
+++ b/templates/fossil/_live_reload.html
@@ -0,0 +1,39 @@
1 {% comment %}
2 HTMX-based live reload detection for Fossil repository changes.
3 Include on pages that should auto-detect when the .fossil file changes.
4 Polls every 30 seconds and shows a banner if the repo has been updated.
5 {% endcomment %}
6 {% if fossil_repo %}
7 <div id="live-reload-banner" class="hidden fixed top-16 left-0 right-0 z-40 bg-brand/90 text-white text-sm text-center py-2 px-4"
8 x-data="{ show: false }"
9 x-show="show"
10 x-transition>
11 <div class="flex items-center justify-center gap-3">
12 <svg class="h-4 w-4 animate-pulse" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
13 <path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182" />
14 </svg>
15 <span>Repository updated</span>
16 <button onclick="location.reload()" class="underline font-semibold">Refresh</button>
17 <button @click="show = false" class="ml-2 opacity-70 hover:opacity-100">&times;</button>
18 </div>
19 </div>
20 <script>
21 (function() {
22 let lastCount = {{ fossil_repo.checkin_count }};
23 setInterval(function() {
24 fetch('{% url "fossil:timeline" slug=project.slug %}?page=1&type=ci', { headers: { 'HX-Request': 'true' } })
25 .then(r => r.text())
26 .then(html => {
27 // Count entries in the response as a quick proxy for "has changed"
28 const matches = html.match(/tl-row/g);
29 const count = matches ? matches.length : 0;
30 if (count > 0 && count !== lastCount) {
31 document.querySelector('#live-reload-banner')?.__x?.$data && (document.querySelector('#live-reload-banner').__x.$data.show = true);
32 lastCount = count;
33 }
34 })
35 .catch(() => {});
36 }, 30000);
37 })();
38 </script>
39 {% endif %}
--- templates/fossil/timeline.html
+++ templates/fossil/timeline.html
@@ -1,9 +1,10 @@
11
{% extends "base.html" %}
22
{% block title %}Timeline — {{ project.name }} — Fossilrepo{% endblock %}
33
44
{% block content %}
5
+{% include "fossil/_live_reload.html" %}
56
<h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
67
{% include "fossil/_project_nav.html" %}
78
89
<div class="flex items-center justify-between mb-4">
910
<div class="flex items-center gap-2 text-xs text-gray-500">
1011
--- templates/fossil/timeline.html
+++ templates/fossil/timeline.html
@@ -1,9 +1,10 @@
1 {% extends "base.html" %}
2 {% block title %}Timeline — {{ project.name }} — Fossilrepo{% endblock %}
3
4 {% block content %}
 
5 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
6 {% include "fossil/_project_nav.html" %}
7
8 <div class="flex items-center justify-between mb-4">
9 <div class="flex items-center gap-2 text-xs text-gray-500">
10
--- templates/fossil/timeline.html
+++ templates/fossil/timeline.html
@@ -1,9 +1,10 @@
1 {% extends "base.html" %}
2 {% block title %}Timeline — {{ project.name }} — Fossilrepo{% endblock %}
3
4 {% block content %}
5 {% include "fossil/_live_reload.html" %}
6 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
7 {% include "fossil/_project_nav.html" %}
8
9 <div class="flex items-center justify-between mb-4">
10 <div class="flex items-center gap-2 text-xs text-gray-500">
11

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button