diff --git a/public/views/control.js b/public/views/control.js index b1a3086..ca76a8d 100644 --- a/public/views/control.js +++ b/public/views/control.js @@ -77,10 +77,13 @@ function statusPill(s) { } function typeBadge(t) { - const type = t === 'feature' ? 'feature' : 'bug'; - const c = type === 'feature' ? '#7aa2e0' : '#e0b24b'; - return el('span', { class: 'badge', style: { background: 'transparent', border: `1px solid ${c}`, color: c } }, - type === 'feature' ? '✨ feature' : '🐞 bug'); + const map = { + feature: { c: '#7aa2e0', label: '✨ feature' }, + improvement: { c: '#5ec27a', label: '🛠 improvement' }, + bug: { c: '#e0b24b', label: '🐞 bug' }, + }; + const m = map[t] || map.bug; + return el('span', { class: 'badge', style: { background: 'transparent', border: `1px solid ${m.c}`, color: m.c } }, m.label); } // ---- group cache (used by approve/instances dropdowns) ---------------------- @@ -311,7 +314,7 @@ async function renderTickets(panel) { const statusSel = select([{ value: '', label: 'all' }, 'open', 'closed'], filter); statusSel.onchange = () => { filter = statusSel.value; loadList(); }; - const typeSel = select([{ value: '', label: 'all' }, { value: 'bug', label: '🐞 bug' }, { value: 'feature', label: '✨ feature' }], typeFilter); + const typeSel = select([{ value: '', label: 'all' }, { value: 'bug', label: '🐞 bug' }, { value: 'feature', label: '✨ feature' }, { value: 'improvement', label: '🛠 improvement' }], typeFilter); typeSel.onchange = () => { typeFilter = typeSel.value; loadList(); }; async function loadList() { @@ -357,6 +360,12 @@ async function renderTickets(panel) { return el('a', { class: 'ghost', href: safeHref(`${A}/tickets/${id}/logs/${attId}`), target: '_blank', rel: 'noopener', style: { marginRight: '0.4rem' } }, '↗ ' + (att.name || `log ${attId}`)); }); + const modules = (t.modules || []).map(att => { + const attId = att.id ?? att; + return el('a', { class: 'lk-url', href: safeHref(`${A}/tickets/${id}/modules/${attId}`), download: `module-${attId}.tar.gz`, + style: { color: 'var(--accent,#5ec27a)', marginRight: '0.5rem', fontSize: '0.8rem' } }, + '⬇ download shared module'); + }); mount(detail, el('div', { class: 'card', style: { display: 'grid', gap: '0.6rem' } }, @@ -370,6 +379,7 @@ async function renderTickets(panel) { el('div', { style: { whiteSpace: 'pre-wrap' } }, t.body || t.text || t.description || '(no text)'), images.length ? el('div', { style: { display: 'flex', flexWrap: 'wrap', gap: '0.5rem' } }, images) : null, logs.length ? el('div', {}, logs) : null, + modules.length ? el('div', {}, modules) : null, field('Admin notes', notesInput), el('div', { style: { display: 'flex', alignItems: 'center', gap: '0.6rem' } }, btn('Save notes', () => patch({ notes: notesInput.value }, 'notes saved'), 'primary'), msg)));