FossilRepo

fossilrepo / templates / fossil / partials / timeline_entries.html
Source Blame History 126 lines
7e1aaf6… ragelink 1 {% load fossil_filters %}
4ce269c… ragelink 2 <style>
4ce269c… ragelink 3 .tl-dag { position: relative; flex-shrink: 0; }
4ce269c… ragelink 4 .tl-node {
4ce269c… ragelink 5 position: absolute; top: 50%; z-index: 2; border-radius: 50%;
4ce269c… ragelink 6 transform: translate(-50%, -50%); width: 10px; height: 10px;
4ce269c… ragelink 7 }
c588255… ragelink 8 .tl-node-ci { border: 2px solid; }
c588255… ragelink 9 .tl-node-merge {
c588255… ragelink 10 border: 2px solid; border-radius: 2px;
c588255… ragelink 11 transform: translate(-50%, -50%) rotate(45deg);
c588255… ragelink 12 }
c588255… ragelink 13 .tl-node-leaf {
c588255… ragelink 14 border: 2px solid; background: transparent !important;
c588255… ragelink 15 }
4ce269c… ragelink 16 .tl-node-w { background: #3b82f6; border: 2px solid #60a5fa; width: 8px; height: 8px; }
4ce269c… ragelink 17 .tl-node-t { background: #eab308; border: 2px solid #facc15; width: 8px; height: 8px; }
4ce269c… ragelink 18 .tl-node-f { background: #a855f7; border: 2px solid #c084fc; width: 8px; height: 8px; }
4ce269c… ragelink 19 .tl-node-other { background: #6b7280; border: 2px solid #9ca3af; width: 8px; height: 8px; }
c588255… ragelink 20 .tl-vline { position: absolute; width: 2px; top: 0; bottom: 0; transform: translateX(-50%); opacity: 0.4; }
c588255… ragelink 21 .tl-connector {
c588255… ragelink 22 position: absolute; top: 40%; z-index: 1; border-radius: 0 0 4px 4px;
c588255… ragelink 23 border-bottom: 2px solid; border-left: 2px solid; border-right: 2px solid;
c588255… ragelink 24 height: 30%; opacity: 0.5;
c588255… ragelink 25 }
c588255… ragelink 26 .tl-connector-merge {
c588255… ragelink 27 top: 20%; border-radius: 4px 4px 0 0;
c588255… ragelink 28 border-top: 2px solid; border-left: 2px solid; border-right: 2px solid;
c588255… ragelink 29 border-bottom: none; height: 30%; opacity: 0.5;
c588255… ragelink 30 }
4ce269c… ragelink 31 .tl-date { font-size: 0.8rem; font-weight: 700; color: #d1d5db; padding: 8px 0 4px; border-bottom: 1px solid #374151; margin-bottom: 2px; }
2f13242… ragelink 32 .tl-row { display: flex; min-height: 28px; align-items: center; flex-wrap: wrap; transition: background-color 150ms ease; border-radius: 4px; }
2f13242… ragelink 33 .tl-row:hover { background: rgba(255,255,255,0.04); }
4ce269c… ragelink 34 .tl-time { width: 42px; flex-shrink: 0; text-align: right; font-size: 0.75rem; color: #6b7280; font-variant-numeric: tabular-nums; }
4ce269c… ragelink 35 .tl-msg { flex: 1; min-width: 0; font-size: 0.8125rem; color: #e5e5e5; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
4ce269c… ragelink 36 .tl-msg a { color: #e5e5e5; text-decoration: none; }
4ce269c… ragelink 37 .tl-msg a:hover { color: #e8677a; }
313537c… ragelink 38 .tl-meta { display: flex; align-items: center; gap: 8px; flex-shrink: 0; padding-left: 12px; flex-wrap: wrap; }
313537c… ragelink 39 @media (max-width: 639px) {
313537c… ragelink 40 .tl-meta { display: none; }
313537c… ragelink 41 .tl-dag { display: none; }
313537c… ragelink 42 .tl-row { padding: 4px 0; }
313537c… ragelink 43 }
4ce269c… ragelink 44 .tl-hash { font-family: ui-monospace, monospace; font-size: 0.7rem; color: #DC394C; text-decoration: none; }
4ce269c… ragelink 45 .tl-hash:hover { color: #e8677a; text-decoration: underline; }
4ce269c… ragelink 46 .tl-user { font-size: 0.7rem; color: #9ca3af; text-decoration: none; }
4ce269c… ragelink 47 .tl-user:hover { color: #e8677a; }
4ce269c… ragelink 48 .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; }
4ce269c… ragelink 49 .tl-badge { font-size: 0.6rem; padding: 0 4px; border-radius: 3px; font-weight: 600; }
4ce269c… ragelink 50 .tl-badge-w { background: rgba(59,130,246,0.15); color: #93c5fd; }
4ce269c… ragelink 51 .tl-badge-t { background: rgba(234,179,8,0.15); color: #fde047; }
4ce269c… ragelink 52 .tl-badge-f { background: rgba(168,85,247,0.15); color: #d8b4fe; }
4ce269c… ragelink 53 </style>
4ce269c… ragelink 54
4ce269c… ragelink 55 <div id="timeline-entries">
4ce269c… ragelink 56 {% if entries %}
4ce269c… ragelink 57 {% load tz %}
4ce269c… ragelink 58 {% for item in entries %}
4ce269c… ragelink 59 {% with e=item.entry %}
4ce269c… ragelink 60
4ce269c… ragelink 61 {# Date header — show when date changes #}
4ce269c… ragelink 62 {% ifchanged e.timestamp|date:"Y-m-d" %}
4ce269c… ragelink 63 <div class="tl-date">{{ e.timestamp|date:"Y-m-d, l" }}</div>
4ce269c… ragelink 64 {% endifchanged %}
4ce269c… ragelink 65
4ce269c… ragelink 66 <div class="tl-row">
4ce269c… ragelink 67 {# DAG column #}
4ce269c… ragelink 68 <div class="tl-dag" style="width: {{ item.graph_width }}px;">
c588255… ragelink 69 {# Vertical rail lines — colored per rail #}
4ce269c… ragelink 70 {% for line in item.lines %}
c588255… ragelink 71 <div class="tl-vline" style="left: {{ line.x }}px; background: {{ line.color }};"></div>
2eca4eb… ragelink 72 {% endfor %}
c588255… ragelink 73 {# Horizontal connectors — fork (branch-out) and merge (branch-in) #}
2eca4eb… ragelink 74 {% for conn in item.connectors %}
c588255… ragelink 75 <div class="{% if conn.type == 'merge' %}tl-connector-merge{% else %}tl-connector{% endif %}"
c588255… ragelink 76 style="left:{{ conn.left }}px; width:{{ conn.width }}px; border-color:{{ conn.color }};"></div>
4ce269c… ragelink 77 {% endfor %}
c588255… ragelink 78 {# Node — style varies: merge diamond, leaf open circle, normal filled circle #}
c588255… ragelink 79 {% if e.event_type == 'ci' %}
c588255… ragelink 80 <div class="tl-node {% if item.is_merge %}tl-node-merge{% elif item.is_leaf %}tl-node-ci tl-node-leaf{% else %}tl-node-ci{% endif %}"
c588255… ragelink 81 style="left: {{ item.node_x }}px; {% if item.is_merge %}background: {{ item.node_color }}; border-color: {{ item.node_color }};{% elif item.is_leaf %}border-color: {{ item.node_color }};{% else %}background: {{ item.node_color }}; border-color: {{ item.node_color }};{% endif %}"></div>
c588255… ragelink 82 {% elif e.event_type == 'w' %}
c588255… ragelink 83 <div class="tl-node tl-node-w" style="left: {{ item.node_x }}px;"></div>
c588255… ragelink 84 {% elif e.event_type == 't' %}
c588255… ragelink 85 <div class="tl-node tl-node-t" style="left: {{ item.node_x }}px;"></div>
c588255… ragelink 86 {% elif e.event_type == 'f' %}
c588255… ragelink 87 <div class="tl-node tl-node-f" style="left: {{ item.node_x }}px;"></div>
c588255… ragelink 88 {% else %}
c588255… ragelink 89 <div class="tl-node tl-node-other" style="left: {{ item.node_x }}px;"></div>
c588255… ragelink 90 {% endif %}
4ce269c… ragelink 91 </div>
4ce269c… ragelink 92
4ce269c… ragelink 93 {# Time #}
4ce269c… ragelink 94 <div class="tl-time">{{ e.timestamp|date:"H:i" }}</div>
4ce269c… ragelink 95
4ce269c… ragelink 96 {# Message #}
4ce269c… ragelink 97 <div class="tl-msg" style="padding-left: 10px;">
4ce269c… ragelink 98 {% if e.event_type == "ci" %}
4ce269c… ragelink 99 <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=e.uuid %}">{{ e.comment|default:"(no comment)"|truncatechars:90 }}</a>
4ce269c… ragelink 100 {% elif e.event_type == "w" %}
4ce269c… ragelink 101 <span class="tl-badge tl-badge-w">wiki</span> {{ e.comment|default:"(no comment)"|truncatechars:80 }}
4ce269c… ragelink 102 {% elif e.event_type == "t" %}
4ce269c… ragelink 103 <span class="tl-badge tl-badge-t">ticket</span> {{ e.comment|default:"(no comment)"|truncatechars:80 }}
4ce269c… ragelink 104 {% elif e.event_type == "f" %}
4ce269c… ragelink 105 <span class="tl-badge tl-badge-f">forum</span> {{ e.comment|default:"(no comment)"|truncatechars:80 }}
4ce269c… ragelink 106 {% else %}
4ce269c… ragelink 107 {{ e.comment|default:"(no comment)"|truncatechars:80 }}
4ce269c… ragelink 108 {% endif %}
4ce269c… ragelink 109 </div>
4ce269c… ragelink 110
4ce269c… ragelink 111 {# Meta: hash, user, branch #}
4ce269c… ragelink 112 <div class="tl-meta">
4ce269c… ragelink 113 {% if e.event_type == "ci" %}
4ce269c… ragelink 114 {% include "fossil/_copy_hash.html" with hash=e.uuid slug=project.slug %}
4ce269c… ragelink 115 {% endif %}
fcd8df3… ragelink 116 <a href="{% url 'fossil:user_activity' slug=project.slug username=e.user %}" class="tl-user">{{ e.user|display_user }}</a>
4ce269c… ragelink 117 {% if e.branch %}<span class="tl-branch">{{ e.branch }}</span>{% endif %}
4ce269c… ragelink 118 </div>
4ce269c… ragelink 119 </div>
4ce269c… ragelink 120
4ce269c… ragelink 121 {% endwith %}
4ce269c… ragelink 122 {% endfor %}
4ce269c… ragelink 123 {% else %}
4ce269c… ragelink 124 <p class="text-sm text-gray-500 py-8 text-center">No timeline entries.</p>
4ce269c… ragelink 125 {% endif %}
4ce269c… ragelink 126 </div>

Keyboard Shortcuts

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