proposal_rows.html
html
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