148 lines
4.5 KiB
JavaScript
148 lines
4.5 KiB
JavaScript
/**
|
|
* Session creation modal
|
|
*/
|
|
|
|
import { createSession } from '../app.js';
|
|
|
|
let overlay;
|
|
|
|
export function initSessionForm() {
|
|
overlay = document.getElementById('modal-overlay');
|
|
|
|
overlay.innerHTML = `
|
|
<div class="modal">
|
|
<div class="modal-header">
|
|
<h2>New Session</h2>
|
|
<button class="btn-icon" id="modal-close">×</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="form-group">
|
|
<label>Project Profile (JSON)</label>
|
|
<textarea id="field-profile" spellcheck="false">{
|
|
"name": "",
|
|
"tech_stack": [],
|
|
"description": ""
|
|
}</textarea>
|
|
<div class="error-text hidden" id="err-profile"></div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Immutable Rules</label>
|
|
<div class="rules-list" id="rules-list">
|
|
<div class="rule-row">
|
|
<input type="text" placeholder="Add a rule..." />
|
|
<button class="btn btn-sm" id="btn-add-rule">+</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Metadata (JSON)</label>
|
|
<textarea id="field-metadata" spellcheck="false">{}</textarea>
|
|
<div class="error-text hidden" id="err-metadata"></div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button class="btn" id="btn-cancel">Cancel</button>
|
|
<button class="btn btn-primary" id="btn-create">Create Session</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
document.getElementById('modal-close').addEventListener('click', closeModal);
|
|
document.getElementById('btn-cancel').addEventListener('click', closeModal);
|
|
document.getElementById('btn-create').addEventListener('click', handleCreate);
|
|
document.getElementById('btn-add-rule').addEventListener('click', addRuleRow);
|
|
|
|
overlay.addEventListener('click', (e) => {
|
|
if (e.target === overlay) closeModal();
|
|
});
|
|
|
|
// Format JSON on blur
|
|
for (const id of ['field-profile', 'field-metadata']) {
|
|
document.getElementById(id).addEventListener('blur', (e) => {
|
|
try {
|
|
const parsed = JSON.parse(e.target.value);
|
|
e.target.value = JSON.stringify(parsed, null, 2);
|
|
e.target.nextElementSibling.classList.add('hidden');
|
|
} catch (err) {
|
|
e.target.nextElementSibling.textContent = `Invalid JSON: ${err.message}`;
|
|
e.target.nextElementSibling.classList.remove('hidden');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function addRuleRow() {
|
|
const list = document.getElementById('rules-list');
|
|
const addBtn = document.getElementById('btn-add-rule');
|
|
const row = document.createElement('div');
|
|
row.className = 'rule-row';
|
|
row.innerHTML = `
|
|
<input type="text" placeholder="Add a rule..." />
|
|
<button class="btn btn-sm btn-danger remove-rule">−</button>
|
|
`;
|
|
row.querySelector('.remove-rule').addEventListener('click', () => row.remove());
|
|
list.insertBefore(row, addBtn.closest('.rule-row'));
|
|
}
|
|
|
|
function getRules() {
|
|
const inputs = document.querySelectorAll('#rules-list input');
|
|
return Array.from(inputs).map(i => i.value.trim()).filter(Boolean);
|
|
}
|
|
|
|
function validateJSON(id) {
|
|
const el = document.getElementById(id);
|
|
try {
|
|
return JSON.parse(el.value);
|
|
} catch (err) {
|
|
const errEl = document.getElementById(`err-${id.replace('field-', '')}`);
|
|
errEl.textContent = `Invalid JSON: ${err.message}`;
|
|
errEl.classList.remove('hidden');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async function handleCreate() {
|
|
const profile = validateJSON('field-profile');
|
|
const metadata = validateJSON('field-metadata');
|
|
if (profile === null || metadata === null) return;
|
|
|
|
const rules = getRules();
|
|
|
|
const btn = document.getElementById('btn-create');
|
|
btn.disabled = true;
|
|
btn.textContent = 'Creating...';
|
|
|
|
try {
|
|
await createSession({
|
|
project_profile: profile,
|
|
immutable_rules: rules,
|
|
metadata,
|
|
});
|
|
closeModal();
|
|
resetForm();
|
|
} catch (e) {
|
|
alert(`Failed: ${e.message}`);
|
|
} finally {
|
|
btn.disabled = false;
|
|
btn.textContent = 'Create Session';
|
|
}
|
|
}
|
|
|
|
function resetForm() {
|
|
document.getElementById('field-profile').value = '{\n "name": "",\n "tech_stack": [],\n "description": ""\n}';
|
|
document.getElementById('field-metadata').value = '{}';
|
|
const list = document.getElementById('rules-list');
|
|
const rows = list.querySelectorAll('.rule-row');
|
|
rows.forEach((r, i) => { if (i < rows.length - 1) r.remove(); });
|
|
const lastInput = list.querySelector('input');
|
|
if (lastInput) lastInput.value = '';
|
|
}
|
|
|
|
export function openSessionForm() {
|
|
overlay.classList.add('open');
|
|
}
|
|
|
|
function closeModal() {
|
|
overlay.classList.remove('open');
|
|
}
|