FossilRepo

Redesign timeline to match Fossil/SQLite style - Date group headers (bold date + day name, border separator) - Compact single-line entries: time | DAG | message | hash user branch - Inline layout instead of card-based (dense, scannable) - Messages truncated with ellipsis, clickable to checkin detail - Clickable hashes and usernames - Color-coded inline badges for wiki/ticket/forum events - Branch pills with brand color - Smaller, tighter DAG nodes

lmata 2026-04-06 17:01 trunk
Commit 3091ffb3ea58aa73dc9253dd1cae651ab6f9b01fd558f8200b21a691fce495a2
--- templates/fossil/partials/timeline_entries.html
+++ templates/fossil/partials/timeline_entries.html
@@ -1,97 +1,92 @@
11
<style>
2
- .dag-col { position: relative; flex-shrink: 0; }
3
- .dag-node {
4
- position: absolute; top: 50%; z-index: 2; border-radius: 50%;
5
- transform: translate(-50%, -50%);
6
- }
7
- .dag-node-ci { width: 12px; height: 12px; background: #DC394C; border: 2px solid #e8677a; }
8
- .dag-node-merge { width: 12px; height: 12px; background: #DC394C; border: 2px solid #e8677a; border-radius: 2px; transform: translate(-50%, -50%) rotate(45deg); }
9
- .dag-node-w { width: 10px; height: 10px; background: #3b82f6; border: 2px solid #60a5fa; }
10
- .dag-node-t { width: 10px; height: 10px; background: #eab308; border: 2px solid #facc15; }
11
- .dag-node-f { width: 10px; height: 10px; background: #a855f7; border: 2px solid #c084fc; }
12
- .dag-node-other { width: 10px; height: 10px; background: #6b7280; border: 2px solid #9ca3af; }
13
- .dag-vline {
14
- position: absolute; width: 2px; top: 0; bottom: 0;
15
- transform: translateX(-50%);
16
- }
17
- .dag-vline-ci { background: rgba(220,57,76,0.35); }
18
- .dag-vline-other { background: rgba(107,114,128,0.25); }
19
- .dag-connect {
20
- position: absolute; top: 75%; height: 25%;
21
- border: 0; border-bottom: 2px solid rgba(220,57,76,0.35);
22
- border-radius: 0 0 6px 0;
23
- z-index: 1;
24
- }
2
+ .tl-dag { position: relative; flex-shrink: 0; }
3
+ .tl-node {
4
+ position: absolute; top: 50%; z-index: 2; border-radius: 50%;
5
+ transform: translate(-50%, -50%); width: 10px; height: 10px;
6
+ }
7
+ .tl-node-ci { background: #DC394C; border: 2px solid #e8677a; }
8
+ .tl-node-merge { background: #DC394C; border: 2px solid #e8677a; border-radius: 2px; transform: translate(-50%, -50%) rotate(45deg); }
9
+ .tl-node-w { background: #3b82f6; border: 2px solid #60a5fa; width: 8px; height: 8px; }
10
+ .tl-node-t { background: #eab308; border: 2px solid #facc15; width: 8px; height: 8px; }
11
+ .tl-node-f { background: #a855f7; border: 2px solid #c084fc; width: 8px; height: 8px; }
12
+ .tl-node-other { background: #6b7280; border: 2px solid #9ca3af; width: 8px; height: 8px; }
13
+ .tl-vline { position: absolute; width: 2px; top: 0; bottom: 0; transform: translateX(-50%); }
14
+ .tl-vline-ci { background: rgba(220,57,76,0.3); }
15
+ .tl-vline-other { background: rgba(107,114,128,0.2); }
16
+ .tl-date { font-size: 0.8rem; font-weight: 700; color: #d1d5db; padding: 8px 0 4px; border-bottom: 1px solid #374151; margin-bottom: 2px; }
17
+ .tl-row { display: flex; min-height: 28px; align-items: center; }
18
+ .tl-row:hover { background: rgba(255,255,255,0.02); }
19
+ .tl-time { width: 42px; flex-shrink: 0; text-align: right; font-size: 0.75rem; color: #6b7280; font-variant-numeric: tabular-nums; }
20
+ .tl-msg { flex: 1; min-width: 0; font-size: 0.8125rem; color: #e5e5e5; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
21
+ .tl-msg a { color: #e5e5e5; text-decoration: none; }
22
+ .tl-msg a:hover { color: #e8677a; }
23
+ .tl-meta { display: flex; align-items: center; gap: 8px; flex-shrink: 0; padding-left: 12px; }
24
+ .tl-hash { font-family: ui-monospace, monospace; font-size: 0.7rem; color: #DC394C; text-decoration: none; }
25
+ .tl-hash:hover { color: #e8677a; text-decoration: underline; }
26
+ .tl-user { font-size: 0.7rem; color: #9ca3af; text-decoration: none; }
27
+ .tl-user:hover { color: #e8677a; }
28
+ .tl-branch { font-size: 0.65rem; padding: 1px 6px; border-radius: 9999px; background: rgba(220,57,76,0.1); border: 1px solid rgba(220,57,76,0.2); color: #e8677a; white-space: nowrap; }
29
+ .tl-badge { font-size: 0.6rem; padding: 0 4px; border-radius: 3px; font-weight: 600; }
30
+ .tl-badge-w { background: rgba(59,130,246,0.15); color: #93c5fd; }
31
+ .tl-badge-t { background: rgba(234,179,8,0.15); color: #fde047; }
32
+ .tl-badge-f { background: rgba(168,85,247,0.15); color: #d8b4fe; }
2533
</style>
2634
2735
<div id="timeline-entries">
2836
{% if entries %}
29
- {% for item in entries %}
30
- <div class="flex" style="min-height: 56px;">
31
-
32
- <!-- DAG graph column -->
33
- <div class="dag-col" style="width: {{ item.graph_width }}px;">
34
- <!-- Vertical rail lines -->
35
- {% for line in item.lines %}
36
- <div class="dag-vline dag-vline-ci" style="left: {{ line.x }}px;"></div>
37
- {% endfor %}
38
-
39
- <!-- Node -->
40
- <div class="dag-node {% if item.entry.is_merge %}dag-node-merge{% elif item.entry.event_type == 'ci' %}dag-node-ci{% elif item.entry.event_type == 'w' %}dag-node-w{% elif item.entry.event_type == 't' %}dag-node-t{% elif item.entry.event_type == 'f' %}dag-node-f{% else %}dag-node-other{% endif %}"
41
- style="left: {{ item.node_x }}px;"></div>
42
-
43
- <!-- Branch/merge connector -->
37
+ {% load tz %}
38
+ {% for item in entries %}
39
+ {% with e=item.entry %}
40
+
41
+ {# Date header — show when date changes #}
42
+ {% ifchanged e.timestamp|date:"Y-m-d" %}
43
+ <div class="tl-date">{{ e.timestamp|date:"Y-m-d, l" }}</div>
44
+ {% endifchanged %}
45
+
46
+ <div class="tl-row">
47
+ {# DAG column #}
48
+ <div class="tl-dag" style="width: {{ item.graph_width }}px;">
49
+ {% for line in item.lines %}
50
+ <div class="tl-vline tl-vline-ci" style="left: {{ line.x }}px;"></div>
51
+ {% endfor %}
52
+ <div class="tl-node {% if e.is_merge %}tl-node-merge{% elif e.event_type == 'ci' %}tl-node-ci{% elif e.event_type == 'w' %}tl-node-w{% elif e.event_type == 't' %}tl-node-t{% elif e.event_type == 'f' %}tl-node-f{% else %}tl-node-other{% endif %}"
53
+ style="left: {{ item.node_x }}px;"></div>
4454
{% if item.connector %}
45
- <div class="dag-connect"
46
- style="left: {{ item.connector.left }}px; width: {{ item.connector.width }}px;
47
- border-left: 2px solid rgba(220,57,76,0.35);
48
- border-right: 2px solid rgba(220,57,76,0.35);"></div>
49
- {% endif %}
50
- </div>
51
-
52
- <!-- Content -->
53
- <div class="flex-1 py-1 min-w-0">
54
- <div class="rounded-lg bg-gray-800 border border-gray-700 px-4 py-2.5 hover:border-gray-600 transition-colors">
55
- <div class="flex items-start justify-between gap-3">
56
- <div class="flex-1 min-w-0">
57
- {% if item.entry.event_type == "ci" %}
58
- <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=item.entry.uuid %}" class="text-sm text-gray-100 leading-snug hover:text-brand-light">{{ item.entry.comment|default:"(no comment)"|truncatechars:120 }}</a>
59
- {% else %}
60
- <p class="text-sm text-gray-100 leading-snug">{{ item.entry.comment|default:"(no comment)"|truncatechars:120 }}</p>
61
- {% endif %}
62
- <div class="mt-1 flex items-center gap-3 flex-wrap">
63
- <a href="{% url 'fossil:user_activity' slug=project.slug username=item.entry.user %}" class="text-xs text-gray-400 hover:text-brand-light">{{ item.entry.user }}</a>
64
- <span class="text-xs text-gray-600">{{ item.entry.timestamp|date:"Y-m-d H:i" }}</span>
65
- {% if item.entry.branch %}
66
- <span class="inline-flex items-center rounded-md bg-brand/10 border border-brand/20 px-1.5 py-0.5 text-xs text-brand-light">
67
- {{ item.entry.branch }}
68
- </span>
69
- {% endif %}
70
- {% if item.entry.event_type == "ci" %}
71
- <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=item.entry.uuid %}" class="text-xs font-mono text-brand-light hover:text-brand">{{ item.entry.uuid|truncatechars:10 }}</a>
72
- {% endif %}
73
- </div>
74
- </div>
75
- <div class="flex-shrink-0">
76
- {% if item.entry.event_type == "ci" %}
77
- <span class="inline-flex rounded-full bg-green-900/50 px-2 py-0.5 text-xs font-semibold text-green-300">checkin</span>
78
- {% elif item.entry.event_type == "w" %}
79
- <span class="inline-flex rounded-full bg-blue-900/50 px-2 py-0.5 text-xs font-semibold text-blue-300">wiki</span>
80
- {% elif item.entry.event_type == "t" %}
81
- <span class="inline-flex rounded-full bg-yellow-900/50 px-2 py-0.5 text-xs font-semibold text-yellow-300">ticket</span>
82
- {% elif item.entry.event_type == "f" %}
83
- <span class="inline-flex rounded-full bg-purple-900/50 px-2 py-0.5 text-xs font-semibold text-purple-300">forum</span>
84
- {% else %}
85
- <span class="inline-flex rounded-full bg-gray-700 px-2 py-0.5 text-xs font-semibold text-gray-300">{{ item.entry.event_type }}</span>
86
- {% endif %}
87
- </div>
88
- </div>
89
- </div>
90
- </div>
91
-
92
- </div>
55
+ <div style="position:absolute; top:75%; height:25%; left:{{ item.connector.left }}px; width:{{ item.connector.width }}px; border-bottom:2px solid rgba(220,57,76,0.3); border-left:2px solid rgba(220,57,76,0.3); border-right:2px solid rgba(220,57,76,0.3); border-radius:0 0 4px 4px; z-index:1;"></div>
56
+ {% endif %}
57
+ </div>
58
+
59
+ {# Time #}
60
+ <div class="tl-time">{{ e.timestamp|date:"H:i" }}</div>
61
+
62
+ {# Message #}
63
+ <div class="tl-msg" style="padding-left: 10px;">
64
+ {% if e.event_type == "ci" %}
65
+ <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=e.uuid %}">{{ e.comment|default:"(no comment)"|truncatechars:90 }}</a>
66
+ {% elif e.event_type == "w" %}
67
+ <span class="tl-badge tl-badge-w">wiki</span> {{ e.comment|default:"(no comment)"|truncatechars:80 }}
68
+ {% elif e.event_type == "t" %}
69
+ <span class="tl-badge tl-badge-t">ticket</span> {{ e.comment|default:"(no comment)"|truncatechars:80 }}
70
+ {% elif e.event_type == "f" %}
71
+ <span class="tl-badge tl-badge-f">forum</span> {{ e.comment|default:"(no comment)"|truncatechars:80 }}
72
+ {% else %}
73
+ {{ e.comment|default:"(no comment)"|truncatechars:80 }}
74
+ {% endif %}
75
+ </div>
76
+
77
+ {# Meta: hash, user, branch #}
78
+ <div class="tl-meta">
79
+ {% if e.event_type == "ci" %}
80
+ <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=e.uuid %}" class="tl-hash">{{ e.uuid|truncatechars:10 }}</a>
81
+ {% endif %}
82
+ <a href="{% url 'fossil:user_activity' slug=project.slug username=e.user %}" class="tl-user">{{ e.user }}</a>
83
+ {% if e.branch %}<span class="tl-branch">{{ e.branch }}</span>{% endif %}
84
+ </div>
85
+ </div>
86
+
87
+ {% endwith %}
9388
{% endfor %}
9489
{% else %}
9590
<p class="text-sm text-gray-500 py-8 text-center">No timeline entries.</p>
9691
{% endif %}
9792
</div>
9893
--- templates/fossil/partials/timeline_entries.html
+++ templates/fossil/partials/timeline_entries.html
@@ -1,97 +1,92 @@
1 <style>
2 .dag-col { position: relative; flex-shrink: 0; }
3 .dag-node {
4 position: absolute; top: 50%; z-index: 2; border-radius: 50%;
5 transform: translate(-50%, -50%);
6 }
7 .dag-node-ci { width: 12px; height: 12px; background: #DC394C; border: 2px solid #e8677a; }
8 .dag-node-merge { width: 12px; height: 12px; background: #DC394C; border: 2px solid #e8677a; border-radius: 2px; transform: translate(-50%, -50%) rotate(45deg); }
9 .dag-node-w { width: 10px; height: 10px; background: #3b82f6; border: 2px solid #60a5fa; }
10 .dag-node-t { width: 10px; height: 10px; background: #eab308; border: 2px solid #facc15; }
11 .dag-node-f { width: 10px; height: 10px; background: #a855f7; border: 2px solid #c084fc; }
12 .dag-node-other { width: 10px; height: 10px; background: #6b7280; border: 2px solid #9ca3af; }
13 .dag-vline {
14 position: absolute; width: 2px; top: 0; bottom: 0;
15 transform: translateX(-50%);
16 }
17 .dag-vline-ci { background: rgba(220,57,76,0.35); }
18 .dag-vline-other { background: rgba(107,114,128,0.25); }
19 .dag-connect {
20 position: absolute; top: 75%; height: 25%;
21 border: 0; border-bottom: 2px solid rgba(220,57,76,0.35);
22 border-radius: 0 0 6px 0;
23 z-index: 1;
24 }
 
 
 
 
 
 
 
 
25 </style>
26
27 <div id="timeline-entries">
28 {% if entries %}
29 {% for item in entries %}
30 <div class="flex" style="min-height: 56px;">
31
32 <!-- DAG graph column -->
33 <div class="dag-col" style="width: {{ item.graph_width }}px;">
34 <!-- Vertical rail lines -->
35 {% for line in item.lines %}
36 <div class="dag-vline dag-vline-ci" style="left: {{ line.x }}px;"></div>
37 {% endfor %}
38
39 <!-- Node -->
40 <div class="dag-node {% if item.entry.is_merge %}dag-node-merge{% elif item.entry.event_type == 'ci' %}dag-node-ci{% elif item.entry.event_type == 'w' %}dag-node-w{% elif item.entry.event_type == 't' %}dag-node-t{% elif item.entry.event_type == 'f' %}dag-node-f{% else %}dag-node-other{% endif %}"
41 style="left: {{ item.node_x }}px;"></div>
42
43 <!-- Branch/merge connector -->
 
 
44 {% if item.connector %}
45 <div class="dag-connect"
46 style="left: {{ item.connector.left }}px; width: {{ item.connector.width }}px;
47 border-left: 2px solid rgba(220,57,76,0.35);
48 border-right: 2px solid rgba(220,57,76,0.35);"></div>
49 {% endif %}
50 </div>
51
52 <!-- Content -->
53 <div class="flex-1 py-1 min-w-0">
54 <div class="rounded-lg bg-gray-800 border border-gray-700 px-4 py-2.5 hover:border-gray-600 transition-colors">
55 <div class="flex items-start justify-between gap-3">
56 <div class="flex-1 min-w-0">
57 {% if item.entry.event_type == "ci" %}
58 <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=item.entry.uuid %}" class="text-sm text-gray-100 leading-snug hover:text-brand-light">{{ item.entry.comment|default:"(no comment)"|truncatechars:120 }}</a>
59 {% else %}
60 <p class="text-sm text-gray-100 leading-snug">{{ item.entry.comment|default:"(no comment)"|truncatechars:120 }}</p>
61 {% endif %}
62 <div class="mt-1 flex items-center gap-3 flex-wrap">
63 <a href="{% url 'fossil:user_activity' slug=project.slug username=item.entry.user %}" class="text-xs text-gray-400 hover:text-brand-light">{{ item.entry.user }}</a>
64 <span class="text-xs text-gray-600">{{ item.entry.timestamp|date:"Y-m-d H:i" }}</span>
65 {% if item.entry.branch %}
66 <span class="inline-flex items-center rounded-md bg-brand/10 border border-brand/20 px-1.5 py-0.5 text-xs text-brand-light">
67 {{ item.entry.branch }}
68 </span>
69 {% endif %}
70 {% if item.entry.event_type == "ci" %}
71 <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=item.entry.uuid %}" class="text-xs font-mono text-brand-light hover:text-brand">{{ item.entry.uuid|truncatechars:10 }}</a>
72 {% endif %}
73 </div>
74 </div>
75 <div class="flex-shrink-0">
76 {% if item.entry.event_type == "ci" %}
77 <span class="inline-flex rounded-full bg-green-900/50 px-2 py-0.5 text-xs font-semibold text-green-300">checkin</span>
78 {% elif item.entry.event_type == "w" %}
79 <span class="inline-flex rounded-full bg-blue-900/50 px-2 py-0.5 text-xs font-semibold text-blue-300">wiki</span>
80 {% elif item.entry.event_type == "t" %}
81 <span class="inline-flex rounded-full bg-yellow-900/50 px-2 py-0.5 text-xs font-semibold text-yellow-300">ticket</span>
82 {% elif item.entry.event_type == "f" %}
83 <span class="inline-flex rounded-full bg-purple-900/50 px-2 py-0.5 text-xs font-semibold text-purple-300">forum</span>
84 {% else %}
85 <span class="inline-flex rounded-full bg-gray-700 px-2 py-0.5 text-xs font-semibold text-gray-300">{{ item.entry.event_type }}</span>
86 {% endif %}
87 </div>
88 </div>
89 </div>
90 </div>
91
92 </div>
93 {% endfor %}
94 {% else %}
95 <p class="text-sm text-gray-500 py-8 text-center">No timeline entries.</p>
96 {% endif %}
97 </div>
98
--- templates/fossil/partials/timeline_entries.html
+++ templates/fossil/partials/timeline_entries.html
@@ -1,97 +1,92 @@
1 <style>
2 .tl-dag { position: relative; flex-shrink: 0; }
3 .tl-node {
4 position: absolute; top: 50%; z-index: 2; border-radius: 50%;
5 transform: translate(-50%, -50%); width: 10px; height: 10px;
6 }
7 .tl-node-ci { background: #DC394C; border: 2px solid #e8677a; }
8 .tl-node-merge { background: #DC394C; border: 2px solid #e8677a; border-radius: 2px; transform: translate(-50%, -50%) rotate(45deg); }
9 .tl-node-w { background: #3b82f6; border: 2px solid #60a5fa; width: 8px; height: 8px; }
10 .tl-node-t { background: #eab308; border: 2px solid #facc15; width: 8px; height: 8px; }
11 .tl-node-f { background: #a855f7; border: 2px solid #c084fc; width: 8px; height: 8px; }
12 .tl-node-other { background: #6b7280; border: 2px solid #9ca3af; width: 8px; height: 8px; }
13 .tl-vline { position: absolute; width: 2px; top: 0; bottom: 0; transform: translateX(-50%); }
14 .tl-vline-ci { background: rgba(220,57,76,0.3); }
15 .tl-vline-other { background: rgba(107,114,128,0.2); }
16 .tl-date { font-size: 0.8rem; font-weight: 700; color: #d1d5db; padding: 8px 0 4px; border-bottom: 1px solid #374151; margin-bottom: 2px; }
17 .tl-row { display: flex; min-height: 28px; align-items: center; }
18 .tl-row:hover { background: rgba(255,255,255,0.02); }
19 .tl-time { width: 42px; flex-shrink: 0; text-align: right; font-size: 0.75rem; color: #6b7280; font-variant-numeric: tabular-nums; }
20 .tl-msg { flex: 1; min-width: 0; font-size: 0.8125rem; color: #e5e5e5; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
21 .tl-msg a { color: #e5e5e5; text-decoration: none; }
22 .tl-msg a:hover { color: #e8677a; }
23 .tl-meta { display: flex; align-items: center; gap: 8px; flex-shrink: 0; padding-left: 12px; }
24 .tl-hash { font-family: ui-monospace, monospace; font-size: 0.7rem; color: #DC394C; text-decoration: none; }
25 .tl-hash:hover { color: #e8677a; text-decoration: underline; }
26 .tl-user { font-size: 0.7rem; color: #9ca3af; text-decoration: none; }
27 .tl-user:hover { color: #e8677a; }
28 .tl-branch { font-size: 0.65rem; padding: 1px 6px; border-radius: 9999px; background: rgba(220,57,76,0.1); border: 1px solid rgba(220,57,76,0.2); color: #e8677a; white-space: nowrap; }
29 .tl-badge { font-size: 0.6rem; padding: 0 4px; border-radius: 3px; font-weight: 600; }
30 .tl-badge-w { background: rgba(59,130,246,0.15); color: #93c5fd; }
31 .tl-badge-t { background: rgba(234,179,8,0.15); color: #fde047; }
32 .tl-badge-f { background: rgba(168,85,247,0.15); color: #d8b4fe; }
33 </style>
34
35 <div id="timeline-entries">
36 {% if entries %}
37 {% load tz %}
38 {% for item in entries %}
39 {% with e=item.entry %}
40
41 {# Date header — show when date changes #}
42 {% ifchanged e.timestamp|date:"Y-m-d" %}
43 <div class="tl-date">{{ e.timestamp|date:"Y-m-d, l" }}</div>
44 {% endifchanged %}
45
46 <div class="tl-row">
47 {# DAG column #}
48 <div class="tl-dag" style="width: {{ item.graph_width }}px;">
49 {% for line in item.lines %}
50 <div class="tl-vline tl-vline-ci" style="left: {{ line.x }}px;"></div>
51 {% endfor %}
52 <div class="tl-node {% if e.is_merge %}tl-node-merge{% elif e.event_type == 'ci' %}tl-node-ci{% elif e.event_type == 'w' %}tl-node-w{% elif e.event_type == 't' %}tl-node-t{% elif e.event_type == 'f' %}tl-node-f{% else %}tl-node-other{% endif %}"
53 style="left: {{ item.node_x }}px;"></div>
54 {% if item.connector %}
55 <div style="position:absolute; top:75%; height:25%; left:{{ item.connector.left }}px; width:{{ item.connector.width }}px; border-bottom:2px solid rgba(220,57,76,0.3); border-left:2px solid rgba(220,57,76,0.3); border-right:2px solid rgba(220,57,76,0.3); border-radius:0 0 4px 4px; z-index:1;"></div>
56 {% endif %}
57 </div>
58
59 {# Time #}
60 <div class="tl-time">{{ e.timestamp|date:"H:i" }}</div>
61
62 {# Message #}
63 <div class="tl-msg" style="padding-left: 10px;">
64 {% if e.event_type == "ci" %}
65 <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=e.uuid %}">{{ e.comment|default:"(no comment)"|truncatechars:90 }}</a>
66 {% elif e.event_type == "w" %}
67 <span class="tl-badge tl-badge-w">wiki</span> {{ e.comment|default:"(no comment)"|truncatechars:80 }}
68 {% elif e.event_type == "t" %}
69 <span class="tl-badge tl-badge-t">ticket</span> {{ e.comment|default:"(no comment)"|truncatechars:80 }}
70 {% elif e.event_type == "f" %}
71 <span class="tl-badge tl-badge-f">forum</span> {{ e.comment|default:"(no comment)"|truncatechars:80 }}
72 {% else %}
73 {{ e.comment|default:"(no comment)"|truncatechars:80 }}
74 {% endif %}
75 </div>
76
77 {# Meta: hash, user, branch #}
78 <div class="tl-meta">
79 {% if e.event_type == "ci" %}
80 <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=e.uuid %}" class="tl-hash">{{ e.uuid|truncatechars:10 }}</a>
81 {% endif %}
82 <a href="{% url 'fossil:user_activity' slug=project.slug username=e.user %}" class="tl-user">{{ e.user }}</a>
83 {% if e.branch %}<span class="tl-branch">{{ e.branch }}</span>{% endif %}
84 </div>
85 </div>
86
87 {% endwith %}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88 {% endfor %}
89 {% else %}
90 <p class="text-sm text-gray-500 py-8 text-center">No timeline entries.</p>
91 {% endif %}
92 </div>
93

Keyboard Shortcuts

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