// Model Groups Management Page
class ModelGroupsPage {
constructor() {
this.container = document.getElementById('page-content');
}
async render() {
this.container.innerHTML = `
`;
await this.loadGroups();
}
async loadGroups() {
try {
const groups = await api.get('/api/model-groups');
const list = document.getElementById('model-groups-list');
if (!groups || groups.length === 0) {
list.innerHTML = 'No model groups defined. Create one to enable auto-routing.
';
return;
}
let html = '';
html += '| Group ID | Strategy | Targets | Actions | ';
html += '
';
groups.forEach(g => {
html += '';
html += '' + this.esc(g.id) + ' | ';
html += '' + this.esc(g.strategy) + ' | ';
html += '' + this.esc(g.targets) + ' | ';
html += '';
html += ' ';
html += '';
html += ' |
';
});
html += '
';
list.innerHTML = html;
} catch (err) {
document.getElementById('model-groups-list').innerHTML =
'Failed to load model groups: ' + this.esc(err.message) + '
';
}
}
showCreateForm() {
this.renderForm(null);
}
async showEditForm(id) {
try {
const groups = await api.get('/api/model-groups');
const group = groups.find(g => g.id === id);
if (group) this.renderForm(group);
} catch (err) {
alert('Failed to load group: ' + err.message);
}
}
renderForm(group) {
const isEdit = !!group;
const form = document.getElementById('model-group-form');
form.style.display = 'block';
form.innerHTML = `
${isEdit ? 'Edit' : 'Create'} Model Group
`;
document.getElementById('mg-strategy').onchange = function() {
var isClassifier = this.value === 'classifier';
document.getElementById('mg-selector-row').style.display = isClassifier ? '' : 'none';
document.getElementById('mg-threshold-row').style.display = isClassifier ? '' : 'none';
document.getElementById('mg-rules-row').style.display = isClassifier ? 'none' : '';
};
}
async saveGroup(event, isEdit) {
event.preventDefault();
var id = document.getElementById('mg-id').value.trim();
var strategy = document.getElementById('mg-strategy').value;
var targets = document.getElementById('mg-targets').value;
var selectorModel = document.getElementById('mg-selector-model').value.trim() || null;
var thresholdVal = document.getElementById('mg-threshold').value;
var rules = document.getElementById('mg-rules').value.trim() || null;
try { JSON.parse(targets); } catch (e) { alert('Targets must be valid JSON array'); return; }
if (rules) { try { JSON.parse(rules); } catch (e) { alert('Heuristic rules must be valid JSON'); return; } }
var body = { id: id, strategy: strategy, targets: targets, selector_model: selectorModel, heuristic_rules: rules };
if (thresholdVal) body.complexity_threshold = parseInt(thresholdVal);
try {
if (isEdit) {
await api.put('/api/model-groups/' + encodeURIComponent(id), body);
} else {
await api.post('/api/model-groups', body);
}
document.getElementById('model-group-form').style.display = 'none';
await this.loadGroups();
} catch (err) {
alert('Failed to save: ' + err.message);
}
}
async deleteGroup(id) {
if (!confirm('Delete model group "' + id + '"? This cannot be undone.')) return;
try {
await api.delete('/api/model-groups/' + encodeURIComponent(id));
await this.loadGroups();
} catch (err) {
alert('Failed to delete: ' + err.message);
}
}
esc(str) {
if (!str) return '';
return String(str).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"');
}
}
var modelGroupsPage = new ModelGroupsPage();