- Specialist Editor Change (all components in same overview), modal editors to allow for more complex configuration of Agents, Tasks and Tools

- Strengthening dynamic forms
This commit is contained in:
Josako
2025-10-28 17:35:36 +01:00
parent b3ee2f7ce9
commit d6041ebb27
13 changed files with 736 additions and 427 deletions

View File

@@ -12,6 +12,21 @@ if (typeof window.EveAI === 'undefined') {
window.EveAI.ListView = {
// Opslag voor lijst-view instanties
instances: {},
// Registry voor custom formatters (kan uitgebreid worden door templates)
formatters: {
// typeBadge: toont een badge voor agent/task/tool (robuust met Bootstrap 5 classes)
typeBadge: function(cell) {
const raw = (cell.getValue() || '').toString();
const val = raw.toLowerCase();
const map = {
'agent': { cls: 'badge text-bg-primary', label: 'Agent' },
'task': { cls: 'badge text-bg-warning', label: 'Task' },
'tool': { cls: 'badge text-bg-info', label: 'Tool' },
};
const conf = map[val] || { cls: 'badge text-bg-secondary', label: (raw ? raw : 'Item') };
return `<span class="${conf.cls}">${conf.label}</span>`;
}
},
/**
* Initialiseer een Tabulator lijst-view
@@ -24,19 +39,50 @@ window.EveAI.ListView = {
const defaultConfig = {
height: 600,
layout: "fitColumns",
selectable: true,
selectable: 1, // single-row selection for consistent UX across Tabulator versions
movableColumns: true,
pagination: "local",
paginationSize: 15,
paginationSizeSelector: [10, 15, 20, 50, 100],
};
// Respecteer eventueel meegegeven tableHeight alias
if (config && typeof config.tableHeight !== 'undefined' && typeof config.height === 'undefined') {
config.height = config.tableHeight;
}
// Los string-formatters op naar functies via registry
if (config && Array.isArray(config.columns)) {
config.columns = config.columns.map(col => {
const newCol = { ...col };
if (typeof newCol.formatter === 'string' && window.EveAI && window.EveAI.ListView && window.EveAI.ListView.formatters) {
const key = newCol.formatter.trim();
const fmt = window.EveAI.ListView.formatters[key];
if (typeof fmt === 'function') {
newCol.formatter = fmt;
}
}
return newCol;
});
}
const tableConfig = {...defaultConfig, ...config};
// Enforce single-row selection across Tabulator versions
if (tableConfig.selectable === true) {
tableConfig.selectable = 1;
}
// Respect and enforce unique row index across Tabulator versions
if (config && typeof config.index === 'string' && config.index) {
// Tabulator v4/v5
tableConfig.index = config.index;
// Tabulator v6+ (alias)
tableConfig.indexField = config.index;
}
// Voeg rij selectie event toe
tableConfig.rowSelectionChanged = (data, rows) => {
console.log("Rij selectie gewijzigd:", rows.length, "rijen geselecteerd");
// Update de geselecteerde rij in onze instance
if (this.instances[elementId]) {
this.instances[elementId].selectedRow = rows.length > 0 ? rows[0].getData() : null;
@@ -60,6 +106,26 @@ window.EveAI.ListView = {
this.updateActionButtons(elementId);
}, 0);
// Forceer enkelvoudige selectie op klik voor consistente UX
try {
table.on('rowClick', function(e, row) {
// voorkom multi-select: altijd eerst deselecteren
row.getTable().deselectRow();
row.select();
});
table.on('cellClick', function(e, cell) {
const row = cell.getRow();
row.getTable().deselectRow();
row.select();
});
// Optioneel: cursor als pointer bij hover
table.on('rowFormatter', function(row) {
row.getElement().style.cursor = 'pointer';
});
} catch (e) {
console.warn('Kon click-selectie handlers niet registreren:', e);
}
return table;
} catch (error) {
console.error(`Fout bij het initialiseren van Tabulator voor ${elementId}:`, error);
@@ -168,16 +234,94 @@ window.EveAI.ListView = {
}
};
// Functie om beschikbaar te maken in templates
function handleListViewAction(action, requiresSelection) {
// Vind het tableId op basis van de button die is aangeklikt
const target = event?.target || event?.srcElement;
// Functie om beschikbaar te maken in templates (met guard en expliciete event-parameter)
if (typeof window.handleListViewAction !== 'function') {
window.handleListViewAction = function(action, requiresSelection, e) {
const evt = e || undefined; // geen gebruik van deprecated window.event
const target = evt && (evt.target || evt.srcElement);
// Vind het formulier en tableId op basis daarvan
const form = target ? target.closest('form') : null;
const tableId = form ? form.id.replace('-form', '') : 'unknown_table';
// 1) Bepaal tableId zo robuust mogelijk
let tableId = null;
if (target) {
// Zoek het werkelijke trigger element (button/anchor) i.p.v. een child node
const trigger = (typeof target.closest === 'function') ? target.closest('button, a') : target;
return window.EveAI.ListView.handleAction(action, requiresSelection, tableId);
// a) Respecteer expliciete data-attribute op knop
tableId = trigger && trigger.getAttribute ? trigger.getAttribute('data-table-id') : null;
if (!tableId) {
// b) Zoek dichtstbijzijnde container met een tabulator-list-view erin
const containerEl = trigger && typeof trigger.closest === 'function' ? trigger.closest('.container') : null;
const scopedTable = containerEl ? containerEl.querySelector('.tabulator-list-view') : null;
tableId = scopedTable ? scopedTable.id : null;
}
if (!tableId) {
// c) Val terug op dichtstbijzijnde form id-afleiding (enkel als het een -form suffix heeft)
const form = trigger && typeof trigger.closest === 'function' ? trigger.closest('form') : null;
if (form && typeof form.id === 'string' && form.id.endsWith('-form')) {
tableId = form.id.slice(0, -'-form'.length);
}
}
}
if (!tableId) {
// d) Laatste redmiddel: pak de eerste tabulator-list-view op de pagina
const anyTable = document.querySelector('.tabulator-list-view');
tableId = anyTable ? anyTable.id : null;
}
if (!tableId) {
console.error('Kan tableId niet bepalen voor action:', action);
return false;
}
const listView = window.EveAI && window.EveAI.ListView ? window.EveAI.ListView : null;
const instance = listView && listView.instances ? listView.instances[tableId] : null;
// 2) Indien selectie vereist, enforce
if (requiresSelection === true) {
if (!instance || !instance.selectedRow) {
// Probeer nog de Tabulator API als instance ontbreekt
try {
const table = Tabulator.findTable(`#${tableId}`)[0];
const rows = table ? table.getSelectedRows() : [];
if (!rows || rows.length === 0) {
alert('Selecteer eerst een item uit de lijst.');
return false;
}
if (instance) instance.selectedRow = rows[0].getData();
} catch (_) {
alert('Selecteer eerst een item uit de lijst.');
return false;
}
}
}
// 3) Embedded handler krijgt voorrang
const embeddedHandlers = listView && listView.embeddedHandlers ? listView.embeddedHandlers : null;
const embedded = embeddedHandlers && embeddedHandlers[tableId];
if (typeof embedded === 'function') {
try {
embedded(action, instance ? instance.selectedRow : null, tableId);
return true;
} catch (err) {
console.error('Embedded handler error:', err);
return false;
}
}
// 4) Vervallen naar legacy form submit/JS handler
if (listView && typeof listView.handleAction === 'function') {
return listView.handleAction(action, requiresSelection, tableId);
}
// 5) Allerbeste laatste fallback probeer form submit met hidden inputs
const actionInput = document.getElementById(`${tableId}-action`);
if (actionInput) actionInput.value = action;
const form = document.getElementById(`${tableId}-form`);
if (form) { form.submit(); return true; }
console.error('Geen geldige handler gevonden voor action:', action);
return false;
}
}
console.log('EveAI List View component geladen');