gabriel / musehub public
proposal_rows.html html
260 lines 11.6 KB
Raw
sha256:8e05daa29ba6702b4a2380a16d690ba31cc099d69c5c859bc6e6f16a0e945f99 Merge 'fix/deploy-memory-limits-and-log-group' into 'dev' —… Human 5 days ago
1 {# fragments/proposal_rows.html — HTMX fragment: enriched proposal list rows.
2 Rendered inline by proposal_list.html and returned as a bare fragment on tab/sort requests.
3 Required context: proposals (list[ProposalListEntry.model_dump()]), base_url (str), state (str)
4 #}
5
6 {# ── Macros ────────────────────────────────────────────────────────────────── #}
7
8 {% macro branch_type(branch) %}
9 {%- set parts = branch.split('/') -%}
10 {%- if parts | length > 1 -%}{{ parts[0] | trim }}{%- endif -%}
11 {% endmacro %}
12
13 {% macro strategy_label(s) %}
14 {%- if s == 'cherry_pick' -%}cherry pick
15 {%- elif s in ('overlay', 'weave', 'replay', 'selective', 'phased') -%}{{ s }}
16 {%- else -%}overlay
17 {%- endif -%}
18 {% endmacro %}
19
20 {% macro ptype_short(t) %}
21 {%- if t == 'state_merge' -%}merge
22 {%- elif t == 'stem_integration' -%}stem
23 {%- elif t == 'midi_evolution' -%}midi
24 {%- elif t == 'payment_settlement' -%}payment
25 {%- elif t == 'agent_delegation' -%}delegation
26 {%- elif t == 'identity_transition' -%}identity
27 {%- elif t == 'canonical_release' -%}release
28 {%- else -%}merge
29 {%- endif -%}
30 {% endmacro %}
31
32 {% macro semver_impact(btype) %}
33 {%- if btype in ('feat', 'feature') -%}minor
34 {%- elif btype in ('fix', 'bugfix', 'hotfix', 'patch') -%}patch
35 {%- elif btype in ('refactor', 'chore', 'docs', 'test', 'style') -%}patch
36 {%- elif btype in ('breaking', 'major') -%}major
37 {%- else -%}{%- endif -%}
38 {% endmacro %}
39
40 {% macro avatar_color(name) %}
41 {%- set palette = ['#1d4ed8','#059669','#d97706','#7c3aed','#db2777','#0891b2','#65a30d','#ea580c'] -%}
42 {{ palette[(name | length) % (palette | length)] }}
43 {% endmacro %}
44
45 {# ── Proposal list ─────────────────────────────────────────────────────────── #}
46 {% if proposals %}
47 <div class="prl-list" id="prl-list-inner">
48 {% for proposal in proposals %}
49 {%- set btype = branch_type(proposal.from_branch) | trim -%}
50 {%- set impact = semver_impact(btype) | trim -%}
51 {%- set _ptype = proposal.proposal_type or 'state_merge' -%}
52 {%- set _pshort = ptype_short(_ptype) | trim -%}
53 {%- set _slabel = strategy_label(proposal.merge_strategy or '') | trim -%}
54 <a href="{{ base_url }}/proposals/{{ proposal.proposal_id }}"
55 class="prl-row prl-row--{{ proposal.state }}{% if proposal.all_merge_conditions_met %} prl-row--ready{% endif %}{% if proposal.is_blocked %} prl-row--blocked{% endif %}">
56
57 {# Index column #}
58 <span class="prl-row-num">#{{ proposal.proposal_number }}</span>
59
60 <div class="prl-row-body">
61
62 {# ── Line 1: key-value signal chips ── #}
63 <div class="prl-row-hd">
64
65 {# type chip — only after merge #}
66 {%- if proposal.state == 'merged' %}
67 <span class="prl-kv prl-kv--type prl-kv--type-{{ _ptype | replace('_', '-') }}"
68 title="Proposal type: {{ _ptype }}">
69 <span class="prl-kv-k">type</span><span class="prl-kv-v">{{ _pshort }}</span>
70 </span>
71 {%- endif %}
72
73 {# risk chip — only when non-zero #}
74 {%- if proposal.aggregate_risk_band and proposal.aggregate_risk_band != 'none' %}
75 <span class="prl-kv prl-kv--risk prl-kv--risk-{{ proposal.aggregate_risk_band }}"
76 title="Risk score: {{ '%.0f' | format(proposal.aggregate_risk_score * 100) }}%">
77 <span class="prl-kv-k">risk</span>
78 <span class="prl-kv-v">
79 <span class="prl-kv-risk-bar" style="width:{{ [((proposal.aggregate_risk_score * 100) | round(0)), 100] | min }}%"></span>
80 {{ proposal.aggregate_risk_band }}
81 </span>
82 </span>
83 {%- endif %}
84
85 {# strategy chip — only after merge #}
86 {%- if proposal.state == 'merged' and _slabel %}
87 <span class="prl-kv prl-kv--strategy" title="Merge strategy: {{ proposal.merge_strategy }}">
88 <span class="prl-kv-k">strategy</span><span class="prl-kv-v">{{ _slabel }}</span>
89 </span>
90 {%- endif %}
91
92 {# blocked chip #}
93 {%- if proposal.is_blocked %}
94 <span class="prl-kv prl-kv--blocked" title="Blocked by #{{ proposal.blocked_by | join(', #') }}">
95 <span class="prl-kv-k">{{ icon("lock", 9) }}</span><span class="prl-kv-v">blocked · #{{ proposal.blocked_by | join(' #') }}</span>
96 </span>
97 {%- endif %}
98
99 {# blocks chip #}
100 {%- if proposal.blocks %}
101 <span class="prl-kv prl-kv--blocks" title="Blocks #{{ proposal.blocks | join(', #') }}">
102 <span class="prl-kv-k">{{ icon("lock", 9) }}</span><span class="prl-kv-v">blocks · #{{ proposal.blocks | join(' #') }}</span>
103 </span>
104 {%- endif %}
105
106 {# ready chip #}
107 {%- if proposal.all_merge_conditions_met %}
108 <span class="prl-kv prl-kv--ready">
109 <span class="prl-kv-k">{{ icon("check-circle", 9) }}</span><span class="prl-kv-v">ready</span>
110 </span>
111 {%- endif %}
112
113 {# settling chip #}
114 {%- if proposal.payment_settling %}
115 <span class="prl-kv prl-kv--settling">
116 <span class="prl-kv-k">{{ icon("clock", 9) }}</span><span class="prl-kv-v">settling</span>
117 </span>
118 {%- endif %}
119
120 {# draft chip #}
121 {%- if proposal.is_draft %}
122 <span class="prl-kv prl-kv--draft">
123 <span class="prl-kv-k">{{ icon("edit-2", 9) }}</span><span class="prl-kv-v">draft</span>
124 </span>
125 {%- endif %}
126
127 </div>
128
129 {# ── Line 2: title ── #}
130 <div class="prl-row-title">{{ proposal.title }}</div>
131
132 {# ── Line 3: left = branch/approvals/conflicts · right = 3-row quality column ── #}
133 <div class="prl-row-meta">
134
135 <span class="prl-branch prl-branch--from">
136 {{ icon("merge", 10) }}
137 {{ proposal.from_branch }}
138 </span>
139 {{ icon("arrow-right", 10, "prl-arrow") }}
140 <span class="prl-branch">{{ proposal.to_branch }}</span>
141
142 {%- if proposal.required_approvals > 0 %}
143 <span class="prl-meta-dot">·</span>
144 <span class="prl-approval-dots" title="{{ proposal.approval_count }}/{{ proposal.required_approvals }} approvals">
145 {%- for i in range(proposal.required_approvals) %}
146 <span class="prl-approval-pip{% if i < proposal.approval_count %} prl-approval-pip--filled{% endif %}"></span>
147 {%- endfor %}
148 <span class="prl-approval-label">{{ proposal.approval_count }}/{{ proposal.required_approvals }}</span>
149 </span>
150 {%- endif %}
151
152 {%- if proposal.simulation_conflict_count is not none and proposal.simulation_conflict_count > 0 %}
153 <span class="prl-meta-dot">·</span>
154 <span class="prl-conflict-count" title="{{ proposal.simulation_conflict_count }} conflict{{ 's' if proposal.simulation_conflict_count != 1 }} (simulated)">
155 {{ icon("alert-triangle", 9) }} {{ proposal.simulation_conflict_count }}c
156 </span>
157 {%- elif proposal.simulation_conflict_count == 0 %}
158 <span class="prl-meta-dot">·</span>
159 <span class="prl-conflict-count prl-conflict-count--clean" title="No conflicts (simulated)">
160 {{ icon("check", 9) }} 0c
161 </span>
162 {%- endif %}
163
164 {# Right column — semver / health (optional) / provenance #}
165 <span class="prl-row-meta-right">
166
167 {%- if impact %}
168 <span class="prl-meta-semver">
169 <span class="prl-kv prl-kv--semver prl-kv--semver-{{ impact }}">
170 <span class="prl-kv-k">semver</span><span class="prl-kv-v">{{ impact }}</span>
171 </span>
172 </span>
173 {%- endif %}
174
175 {%- if proposal.breakage_count > 0 or proposal.test_gap_count > 0 %}
176 <span class="prl-meta-health">
177 {%- if proposal.breakage_count > 0 %}
178 <span class="prl-kv prl-kv--breakage" title="{{ proposal.breakage_count }} structural breakage{{ 's' if proposal.breakage_count != 1 }}">
179 <span class="prl-kv-k">{{ icon("alert-triangle", 9) }}</span><span class="prl-kv-v">{{ proposal.breakage_count }} breakage{{ 's' if proposal.breakage_count != 1 }}</span>
180 </span>
181 {%- endif %}
182 {%- if proposal.test_gap_count > 0 %}
183 <span class="prl-kv prl-kv--gap" title="{{ proposal.test_gap_count }} symbol{{ 's' if proposal.test_gap_count != 1 }} changed without test coverage">
184 <span class="prl-kv-k">{{ icon("experiment", 9) }}</span><span class="prl-kv-v">{{ proposal.test_gap_count }} gap{{ 's' if proposal.test_gap_count != 1 }}</span>
185 </span>
186 {%- endif %}
187 </span>
188 {%- endif %}
189
190 <span class="prl-meta-provenance">
191 <span class="prl-actor">
192 <img class="prl-sigil" src="/avatars/handle/{{ proposal.author | urlencode }}.svg"
193 alt="{{ proposal.author }}" width="20" height="20"
194 loading="lazy">
195 {{ proposal.author or 'unknown' }}
196 {%- if proposal.author_type == 'agent' %}
197 <span class="prl-author-badge prl-author-badge--agent" title="{{ proposal.agent_model or 'agent' }}">{{ icon("cpu", 9) }}</span>
198 {%- endif %}
199 </span>
200 <span class="prl-meta-dot">·</span>
201 <span class="prl-date">{{ proposal.created_at | fmtrelative }}</span>
202 </span>
203
204 </span>
205
206 </div>
207
208 </div>
209
210 {# Aside — merged/abandoned state labels only ─────────────────────────── #}
211 <div class="prl-row-aside">
212 {%- if proposal.state == 'merged' and proposal.merged_at %}
213 <span class="prl-merged-label">
214 {{ icon("check", 10) }}
215 {{ proposal.merged_at | fmtdate }}
216 </span>
217 {%- endif %}
218 {%- if proposal.state == 'abandoned' %}
219 <span class="prl-closed-label">abandoned</span>
220 {%- endif %}
221 </div>
222
223 {{ icon("chevron-right", 14, "prl-chevron") }}
224
225 </a>
226 {% endfor %}
227 </div>
228
229 {% else %}
230 {# ── Empty state ─────────────────────────────────────────────────────────── #}
231 <div class="prl-empty">
232 <div class="prl-empty-icon">
233 {{ icon("merge", 52, "icon--light-stroke") }}
234 </div>
235 <div class="prl-empty-title">
236 {% if state == 'open' %}No open merge proposals
237 {% elif state == 'merged' %}No merged proposals yet
238 {% elif state == 'abandoned' %}No abandoned proposals
239 {% else %}No merge proposals yet{% endif %}
240 </div>
241 <div class="prl-empty-desc">
242 {% if state == 'open' %}
243 Push a branch and open a merge proposal to propose changes with symbol-level diffs.
244 {% elif state == 'merged' %}
245 Merged proposals will appear here once changes land on the target branch.
246 {% elif state == 'abandoned' %}
247 Proposals closed without merging will appear here.
248 {% else %}
249 Create a branch, push your changes, and open a merge proposal to start reviewing.
250 {% endif %}
251 </div>
252 {% if state in ('open', 'all') %}
253 <div class="prl-empty-cli">
254 <span class="prl-empty-cli-prompt">$</span>
255 <span class="prl-empty-cli-cmd">muse push local</span>
256 <span class="prl-empty-cli-hint">then open a merge proposal above</span>
257 </div>
258 {% endif %}
259 </div>
260 {% endif %}
File History 3 commits
sha256:8e05daa29ba6702b4a2380a16d690ba31cc099d69c5c859bc6e6f16a0e945f99 Merge 'fix/deploy-memory-limits-and-log-group' into 'dev' —… Human 5 days ago
sha256:3fadb0439bba9451b89229676971c0d4a40900dec7810e9d5f8791b8d950d505 fix: install.sh version from latest published tarball, not … Sonnet 4.6 minor 97 days ago
sha256:763eb2cb8675073b84c19345b27586d2ed939a9aee97c5479b69f502f1a70eff fix(tests): update test suite to match current implementation Sonnet 4.6 patch 118 days ago