diff --git a/admin/DashboardController.php b/admin/DashboardController.php
index e11b413..ffccc2d 100644
--- a/admin/DashboardController.php
+++ b/admin/DashboardController.php
@@ -2537,47 +2537,186 @@ HTML;
🔀 Flujos
-
Acciones que se ejecutan cuando un comando o fila de menú es seleccionada.
+
Acciones que se ejecutan cuando un comando o botón de menú es seleccionado.
HTML;
+ // Pre-build select options for menus and endpoints
+ $menuOptHtml = '
';
+ foreach (array_keys($menus) as $mk) {
+ $menuOptHtml .= '
';
+ }
+ $epOptHtml = '
';
+ foreach ($companyEndpoints as $ep) {
+ $epOptHtml .= '
';
+ }
+ $flowKeys = array_keys($flows);
+
$flowIdx = 0;
foreach ($flows as $fk => $flow) {
- $ft = $flow['type'] ?? 'text';
- $fMsg = self::h($flow['message'] ?? '');
- $fFn = self::h($flow['function'] ?? 'forward_to_ai');
- $fMenu = self::h($flow['menu'] ?? '');
- echo "
";
+ $ft = $flow['type'] ?? 'text';
+ $fMsg = self::h($flow['message'] ?? '');
+ $fFn = $flow['function'] ?? 'forward_to_ai';
+ $fMenu = $flow['menu'] ?? '';
+ $params = $flow['params'] ?? [];
+ $epKey = self::h($params['endpoint_key'] ?? $flow['endpoint_key'] ?? '');
+ $dMode = self::h($params['date_mode'] ?? '');
+ $cap = self::h($params['caption'] ?? $flow['caption'] ?? '');
+ $fname = self::h($params['filename'] ?? $flow['filename'] ?? '');
+ $prompt = self::h($flow['prompt'] ?? '');
+ $mGroup = self::h($flow['meta_group'] ?? '');
+ $mKey = self::h($flow['meta_key'] ?? '');
+ $nNode = $flow['next_node'] ?? '';
+ $srcEp = self::h($flow['source_endpoint_key'] ?? '');
+ $valF = self::h($flow['value_field'] ?? 'id');
+ $lblF = self::h($flow['label_field'] ?? 'nombre');
+ $header = self::h($flow['header'] ?? '');
+ $body = self::h($flow['body'] ?? '');
+ $secTit = self::h($flow['section_title'] ?? '');
+
+ // Build menu select with current selection
+ $menuSelHtml = '
';
+ foreach (array_keys($menus) as $mk) {
+ $sel = $fMenu === $mk ? ' selected' : '';
+ $menuSelHtml .= '
';
+ }
+ // Build endpoint select with current selection
+ $epSelHtml = '
';
+ foreach ($companyEndpoints as $ep) {
+ $sel = $epKey === self::h($ep['endpoint_key']) ? ' selected' : '';
+ $epSelHtml .= '
';
+ }
+ // For dynamic_list source endpoint
+ $dlEpSelHtml = '
';
+ foreach ($companyEndpoints as $ep) {
+ $sel = $srcEp === self::h($ep['endpoint_key']) ? ' selected' : '';
+ $dlEpSelHtml .= '
';
+ }
+ // For submit_form endpoint
+ $sfEpSelHtml = '
';
+ foreach ($companyEndpoints as $ep) {
+ $sel = $epKey === self::h($ep['endpoint_key']) ? ' selected' : '';
+ $sfEpSelHtml .= '
';
+ }
+ // Next-node select
+ $nnSelHtml = '
';
+ foreach ($flowKeys as $ofk) {
+ if ($ofk === $fk) continue;
+ $sel = $nNode === $ofk ? ' selected' : '';
+ $nnSelHtml .= '
';
+ }
+
+ $showText = $ft === 'text' ? '' : 'display:none';
+ $showMenu = $ft === 'menu' ? '' : 'display:none';
+ $showFn = $ft === 'function' ? '' : 'display:none';
+ $showEp = ($ft === 'function' && $fFn === 'api_report') ? '' : 'display:none';
+ $showCollect = $ft === 'collect_input' ? '' : 'display:none';
+ $showDynList = $ft === 'dynamic_list' ? '' : 'display:none';
+ $showSubmit = $ft === 'submit_form' ? '' : 'display:none';
+
+ $fnOpts = '';
+ foreach (['goodbye' => '↩️ Salir (goodbye)', 'api_report' => '📄 Descargar informe', 'forward_to_ai' => '🤖 Escalar a IA', 'forward_to_agent' => '👤 Escalar a agente'] as $fv => $fl) {
+ $fnOpts .= '
';
+ }
+ $dmOpts = '';
+ foreach (['' => 'Sin fecha', 'today' => 'Hoy', 'last_30' => 'Últimos 30 días'] as $dv => $dl) {
+ $dmOpts .= '
';
+ }
+
+ echo "
+
";
$flowIdx++;
}
echo <<✕
' +
- '
';
- container.appendChild(div);
+// Flows — mostrar/ocultar secciones según tipo seleccionado
+function flowTabChange(sel) {
+ const card = sel.closest('.item-card');
+ const v = sel.value;
+ const map = {
+ 'ftg-text': v==='text', 'ftg-menu': v==='menu', 'ftg-fn': v==='function',
+ 'ftg-collect': v==='collect_input', 'ftg-dynlist': v==='dynamic_list', 'ftg-submit': v==='submit_form'
+ };
+ for (const [cls, show] of Object.entries(map)) {
+ const el = card.querySelector('.' + cls);
+ if (el) el.style.display = show ? 'flex' : 'none';
+ }
+ if (v !== 'function') {
+ const ep = card.querySelector('.ftg-ep');
+ if (ep) ep.style.display = 'none';
+ }
}
-function flowTypeChange(sel) {
+function flowFnTabChange(sel) {
const card = sel.closest('.item-card');
- card.querySelector('.flow-text').style.display = sel.value === 'text' ? '' : 'none';
- card.querySelector('.flow-function').style.display = sel.value === 'function' ? '' : 'none';
- card.querySelector('.flow-menu').style.display = sel.value === 'menu' ? '' : 'none';
+ const ep = card.querySelector('.ftg-ep');
+ if (ep) ep.style.display = sel.value === 'api_report' ? 'flex' : 'none';
}
function updatePreview() {
diff --git a/public/index.php b/public/index.php
index 2e9e46e..8cfa247 100644
--- a/public/index.php
+++ b/public/index.php
@@ -382,20 +382,85 @@ $routes = [
if (!empty($menus)) $config['menus'] = $menus;
// Flows
- $flowKeys = $_POST['flow_key'] ?? [];
- $flowTypes = $_POST['flow_type'] ?? [];
- $flowMessages = $_POST['flow_message'] ?? [];
- $flowFunctions = $_POST['flow_function'] ?? [];
- $flowMenus = $_POST['flow_menu'] ?? [];
+ $flowKeys = $_POST['flow_key'] ?? [];
+ $flowTypes = $_POST['flow_type'] ?? [];
+ $flowMessages = $_POST['flow_message'] ?? [];
+ $flowFunctions = $_POST['flow_function'] ?? [];
+ $flowMenus = $_POST['flow_menu'] ?? [];
+ $flowEpKeys = $_POST['flow_ep_key'] ?? [];
+ $flowDateModes = $_POST['flow_date_mode'] ?? [];
+ $flowFilenames = $_POST['flow_filename'] ?? [];
+ $flowCaptions = $_POST['flow_caption'] ?? [];
+ $flowPrompts = $_POST['flow_prompt'] ?? [];
+ $flowMetaGrps = $_POST['flow_meta_group'] ?? [];
+ $flowMetaKeys = $_POST['flow_meta_key'] ?? [];
+ $flowNextNodes = $_POST['flow_next_node'] ?? [];
+ $flowDlEps = $_POST['flow_dl_ep'] ?? [];
+ $flowValFields = $_POST['flow_val_field'] ?? [];
+ $flowLblFields = $_POST['flow_lbl_field'] ?? [];
+ $flowHeaders = $_POST['flow_header'] ?? [];
+ $flowBodies = $_POST['flow_body'] ?? [];
+ $flowSecTitles = $_POST['flow_sec_title'] ?? [];
+ $flowDlGroups = $_POST['flow_dl_meta_group']?? [];
+ $flowDlKeys = $_POST['flow_dl_meta_key'] ?? [];
+ $flowDlNexts = $_POST['flow_dl_next'] ?? [];
+ $flowSfEps = $_POST['flow_sf_ep'] ?? [];
+ $flowSfGroups = $_POST['flow_sf_meta_group']?? [];
+ $flowSfFnames = $_POST['flow_sf_filename'] ?? [];
+ $flowSfCaps = $_POST['flow_sf_caption'] ?? [];
+
$flows = [];
foreach ($flowKeys as $i => $fk) {
- $fk = trim($fk);
- if ($fk === '') continue;
+ $fk = trim($fk);
$ftype = $flowTypes[$i] ?? 'text';
+ if ($fk === '') continue;
+
$f = ['type' => $ftype];
- if ($ftype === 'text') $f['message'] = trim($flowMessages[$i] ?? '');
- elseif ($ftype === 'function') $f['function'] = trim($flowFunctions[$i] ?? 'forward_to_ai');
- elseif ($ftype === 'menu') $f['menu'] = trim($flowMenus[$i] ?? '');
+
+ if ($ftype === 'text') {
+ $f['message'] = trim($flowMessages[$i] ?? '');
+
+ } elseif ($ftype === 'menu') {
+ $f['menu'] = trim($flowMenus[$i] ?? '');
+
+ } elseif ($ftype === 'function') {
+ $fn = trim($flowFunctions[$i] ?? 'forward_to_ai');
+ $f['function'] = $fn;
+ if ($fn === 'api_report') {
+ $f['params'] = [
+ 'endpoint_key' => trim($flowEpKeys[$i] ?? ''),
+ 'date_mode' => trim($flowDateModes[$i] ?? ''),
+ 'caption' => trim($flowCaptions[$i] ?? ''),
+ 'filename' => trim($flowFilenames[$i] ?? ''),
+ ];
+ }
+
+ } elseif ($ftype === 'collect_input') {
+ $nn = trim($flowNextNodes[$i] ?? '');
+ $f['prompt'] = trim($flowPrompts[$i] ?? '');
+ $f['meta_group'] = trim($flowMetaGrps[$i] ?? '');
+ $f['meta_key'] = trim($flowMetaKeys[$i] ?? '');
+ $f['next_node'] = $nn !== '' ? $nn : null;
+
+ } elseif ($ftype === 'dynamic_list') {
+ $nn = trim($flowDlNexts[$i] ?? '');
+ $f['source_endpoint_key'] = trim($flowDlEps[$i] ?? '');
+ $f['value_field'] = trim($flowValFields[$i] ?? 'id');
+ $f['label_field'] = trim($flowLblFields[$i] ?? 'nombre');
+ $f['header'] = trim($flowHeaders[$i] ?? '');
+ $f['body'] = trim($flowBodies[$i] ?? '');
+ $f['section_title'] = trim($flowSecTitles[$i] ?? '');
+ $f['meta_group'] = trim($flowDlGroups[$i] ?? '');
+ $f['meta_key'] = trim($flowDlKeys[$i] ?? '');
+ $f['next_node'] = $nn !== '' ? $nn : null;
+
+ } elseif ($ftype === 'submit_form') {
+ $f['endpoint_key'] = trim($flowSfEps[$i] ?? '');
+ $f['meta_group'] = trim($flowSfGroups[$i] ?? '');
+ $f['filename'] = trim($flowSfFnames[$i] ?? '');
+ $f['caption'] = trim($flowSfCaps[$i] ?? '');
+ }
+
$flows[$fk] = $f;
}
if (!empty($flows)) $config['flows'] = $flows;