// auto-split module function parseTemplate(text) { if (window.jsyaml && typeof jsyaml.load === 'function') { try { return jsyaml.load(text); } catch (e) {} } try { return JSON.parse(text); } catch (e) {} throw new Error('Vorlage konnte weder als YAML noch JSON gelesen werden.'); } function captureEditsIntoTemplate() { if (!template) return; const rows = [...(els.stepsTableBody?.querySelectorAll('tr') || [])]; template.steps = rows.map((row, i) => { const kind = row.getAttribute('data-kind') || 'step'; if (kind === 'group') { return { kind: 'group', title: (row.querySelector('.tpl-group-title')?.value || '').trim(), collapsed: row.getAttribute('data-collapsed') === '1' }; } return { kind: 'step', id: (row.querySelector('.tpl-id')?.value || '').trim() || `step-${String(i+1).padStart(3,'0')}`, title: (row.querySelector('.tpl-title')?.value || row.querySelector('.tpl-title')?.textContent || '').trim(), expected: (row.querySelector('.tpl-expected')?.value || '').trim(), required: !!(row.querySelector('.tpl-required')?.checked), status: row.querySelector('select.status')?.value || '', comment: row.querySelector('.run-comment')?.value || '', evidence: row.querySelector('.run-evidence')?.value || '' }; }); } function nextStepNumber() { const stepsOnly = (template?.steps || []).filter(s => (s.kind || s.type || 'step') === 'step'); // Versuche numerischen Suffix aus "step-XYZ" zu lesen, sonst zähle Steps const nums = stepsOnly .map(s => String(s.id || '')) .map(id => { const m = id.match(/step-(\d+)/i); return m ? parseInt(m[1], 10) : null; }) .filter(n => Number.isFinite(n)); const base = nums.length ? Math.max(...nums) : stepsOnly.length; return base + 1; } function makeStepId(n) { const num = String(Math.max(1, n)).padStart(3, '0'); return `step-${num}`; } function renumberSteps() { if (!template || !Array.isArray(template.steps)) return; let n = 1; template.steps.forEach(s => { const k = s.kind || s.type || 'step'; if (k !== 'step') return; const id = `step-${String(n).padStart(3,'0')}`; s.id = id; n++; }); } function ensureRenumberAndRender() { renumberSteps(); renderSteps(template.steps); recomputeGroupStyles(); } function renderSteps(steps) { if (!els.stepsTableBody) return; els.stepsTableBody.innerHTML = ''; let groupCollapsed = false; steps.forEach((s, idx) => { if ((s.kind || 'step') === 'group') { const trG = document.createElement('tr'); trG.setAttribute('data-kind', 'group'); trG.className = 'group-row'; if (s.collapsed) trG.setAttribute('data-collapsed', '1'); /* drag via handle only */ // trG.setAttribute('draggable','true'); trG.innerHTML = `
⋮⋮
`; els.stepsTableBody.appendChild(trG); groupCollapsed = !!s.collapsed; return; } const id = s.id || ''; const tr = document.createElement('tr'); tr.setAttribute('data-kind', 'step'); /* drag via handle only */ // tr.setAttribute('draggable','true'); if (groupCollapsed) tr.setAttribute('data-hidden', '1'); tr.innerHTML = `
${s.required ? '📌' : ''}
⋮⋮
`; els.stepsTableBody.appendChild(tr); updateStatusClass(tr.querySelector('select.status')); // nach jedem Render Schritt neu bewerten recomputeGroupStyles(); }); } function recomputeGroupStyles() { try { const body = els.stepsTableBody; if (!body) return; const rows = [...body.querySelectorAll('tr')]; // Collect groups with following step rows until next group let groups = []; let current = null; rows.forEach(r => { const kind = r.getAttribute('data-kind') || 'step'; if (kind === 'group') { current = { row: r, steps: [] }; groups.push(current); } else if (current) { current.steps.push(r); } }); groups.forEach(g => { g.row.classList.remove('group-ok', 'group-fail'); const statuses = g.steps.map(tr => (tr.querySelector('select.status')?.value || '').toUpperCase()); if (!statuses.length) return; const allPass = statuses.every(s => s === 'PASS'); const anyFail = statuses.some(s => s === 'FAIL' || s === 'BLOCKED'); if (allPass) g.row.classList.add('group-ok'); else if (anyFail) g.row.classList.add('group-fail'); }); } catch (e) { console.warn('recomputeGroupStyles failed', e); } } function enforceDragHandleOnly() { if (!els.stepsTableBody) return; els.stepsTableBody.querySelectorAll('tr[draggable="true"]').forEach(tr => tr.setAttribute('draggable', 'false')); els.stepsTableBody.querySelectorAll('.drag-handle').forEach(h => h.setAttribute('draggable', 'true')); }