@cccarv82/freya 2.8.3 → 2.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/web-ui.js +227 -97
- package/cli/web.js +95 -84
- package/package.json +1 -1
package/cli/web-ui.js
CHANGED
|
@@ -330,6 +330,47 @@
|
|
|
330
330
|
}
|
|
331
331
|
}
|
|
332
332
|
|
|
333
|
+
// Unified input → Oracle (RAG): reads from the main inboxText textarea
|
|
334
|
+
async function askFreyaFromInput() {
|
|
335
|
+
const ta = $('inboxText');
|
|
336
|
+
const query = ta ? (ta.value || '').trim() : '';
|
|
337
|
+
if (!query) {
|
|
338
|
+
setPill('err', 'vazio');
|
|
339
|
+
setTimeout(() => setPill('ok', 'pronto'), 800);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (ta) ta.value = '';
|
|
344
|
+
|
|
345
|
+
// Update mode tag
|
|
346
|
+
const tag = $('chatModeTag');
|
|
347
|
+
if (tag) { tag.textContent = 'oracle'; tag.style.color = 'var(--accent)'; tag.style.borderColor = 'var(--accent)'; }
|
|
348
|
+
|
|
349
|
+
chatAppend('user', query);
|
|
350
|
+
setPill('run', 'pesquisando…');
|
|
351
|
+
|
|
352
|
+
const typingId = 'typing-' + Date.now();
|
|
353
|
+
chatAppend('assistant', '<div class="typing-indicator"><span></span><span></span><span></span></div>', { id: typingId, html: true });
|
|
354
|
+
|
|
355
|
+
try {
|
|
356
|
+
const sessionId = ensureChatSession();
|
|
357
|
+
const r = await api('/api/chat/ask', { dir: dirOrDefault(), sessionId, query });
|
|
358
|
+
const answer = r && r.answer ? r.answer : 'Não encontrei registro';
|
|
359
|
+
|
|
360
|
+
const el = $(typingId);
|
|
361
|
+
if (el) el.remove();
|
|
362
|
+
|
|
363
|
+
chatAppend('assistant', answer, { markdown: true });
|
|
364
|
+
setPill('ok', 'pronto');
|
|
365
|
+
if (tag) setTimeout(() => { tag.textContent = 'oracle'; tag.style.color = ''; tag.style.borderColor = ''; }, 2000);
|
|
366
|
+
} catch (e) {
|
|
367
|
+
const el = $(typingId);
|
|
368
|
+
if (el) el.remove();
|
|
369
|
+
setPill('err', 'falhou');
|
|
370
|
+
chatAppend('assistant', '❌ ' + String(e && e.message ? e.message : e));
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
333
374
|
function setOut(text) {
|
|
334
375
|
state.lastText = text || '';
|
|
335
376
|
const el = $('reportPreview');
|
|
@@ -1317,11 +1358,65 @@
|
|
|
1317
1358
|
}
|
|
1318
1359
|
}
|
|
1319
1360
|
|
|
1361
|
+
// Priority → color + icon
|
|
1362
|
+
function priColor(pri) {
|
|
1363
|
+
const p = String(pri || '').toUpperCase();
|
|
1364
|
+
if (p === 'CRITICAL') return { dot: '#ef4444', label: 'CRÍTICA' };
|
|
1365
|
+
if (p === 'HIGH') return { dot: '#f97316', label: 'ALTA' };
|
|
1366
|
+
if (p === 'MEDIUM') return { dot: '#eab308', label: 'MÉDIA' };
|
|
1367
|
+
if (p === 'LOW') return { dot: '#22c55e', label: 'BAIXA' };
|
|
1368
|
+
return { dot: 'var(--muted)', label: p || '—' };
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
// Severity → color
|
|
1372
|
+
function sevColor(sev) {
|
|
1373
|
+
const s = String(sev || '').toUpperCase();
|
|
1374
|
+
if (s === 'CRITICAL') return '#ef4444';
|
|
1375
|
+
if (s === 'HIGH') return '#f97316';
|
|
1376
|
+
if (s === 'MEDIUM') return '#eab308';
|
|
1377
|
+
return '#94a3b8';
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1320
1380
|
function renderSwimlanes(tasks, blockers) {
|
|
1321
1381
|
const el = $('swimlaneContainer');
|
|
1322
1382
|
if (!el) return;
|
|
1323
1383
|
el.innerHTML = '';
|
|
1324
1384
|
|
|
1385
|
+
// Update top-level summary chips
|
|
1386
|
+
const chips = $('focusSummaryChips');
|
|
1387
|
+
if (chips) {
|
|
1388
|
+
chips.innerHTML = '';
|
|
1389
|
+
if (blockers.length > 0) {
|
|
1390
|
+
const bc = document.createElement('span');
|
|
1391
|
+
bc.style.cssText = 'font-size:11px; font-weight:700; padding:2px 8px; border-radius:10px; background:rgba(239,68,68,0.12); color:#f87171; border:1px solid rgba(239,68,68,0.3);';
|
|
1392
|
+
bc.textContent = blockers.length + ' blocker' + (blockers.length > 1 ? 's' : '');
|
|
1393
|
+
chips.appendChild(bc);
|
|
1394
|
+
}
|
|
1395
|
+
if (tasks.length > 0) {
|
|
1396
|
+
const tc = document.createElement('span');
|
|
1397
|
+
tc.style.cssText = 'font-size:11px; font-weight:700; padding:2px 8px; border-radius:10px; background:rgba(34,197,94,0.10); color:#4ade80; border:1px solid rgba(34,197,94,0.25);';
|
|
1398
|
+
tc.textContent = tasks.length + ' task' + (tasks.length > 1 ? 's' : '');
|
|
1399
|
+
chips.appendChild(tc);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
// Update progress bar (tasks completed today vs total — we show pending count)
|
|
1404
|
+
const progWrap = $('focusProgressWrap');
|
|
1405
|
+
const progBar = $('focusProgressBar');
|
|
1406
|
+
const progLabel = $('focusProgressLabel');
|
|
1407
|
+
if (progWrap) {
|
|
1408
|
+
if (tasks.length > 0 || blockers.length > 0) {
|
|
1409
|
+
progWrap.style.display = 'flex';
|
|
1410
|
+
// We only have pending tasks here; show blockers impact
|
|
1411
|
+
const blocker_pct = blockers.length === 0 ? 100 : Math.max(10, Math.round((1 - blockers.length / Math.max(tasks.length + blockers.length, 1)) * 100));
|
|
1412
|
+
if (progBar) progBar.style.width = blocker_pct + '%';
|
|
1413
|
+
if (progBar) progBar.style.background = blockers.length > 0 ? '#f97316' : 'var(--accent)';
|
|
1414
|
+
if (progLabel) progLabel.textContent = blockers.length > 0 ? blockers.length + ' blocking' : 'tudo livre';
|
|
1415
|
+
} else {
|
|
1416
|
+
progWrap.style.display = 'none';
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1325
1420
|
const groups = {};
|
|
1326
1421
|
const addGroup = (slug) => {
|
|
1327
1422
|
const key = slug || 'Global / Sem Projeto';
|
|
@@ -1337,41 +1432,55 @@
|
|
|
1337
1432
|
if (b === 'Global / Sem Projeto') return -1;
|
|
1338
1433
|
return a.localeCompare(b);
|
|
1339
1434
|
});
|
|
1340
|
-
|
|
1341
1435
|
sortedKeys.sort((a, b) => groups[b].blockers.length - groups[a].blockers.length);
|
|
1342
1436
|
|
|
1343
1437
|
if (sortedKeys.length === 0) {
|
|
1344
1438
|
const empty = document.createElement('div');
|
|
1345
|
-
empty.
|
|
1346
|
-
empty.
|
|
1439
|
+
empty.style.cssText = 'display:flex; flex-direction:column; align-items:center; justify-content:center; padding:48px 24px; gap:8px; flex:1;';
|
|
1440
|
+
empty.innerHTML = '<div style="font-size:28px; line-height:1;">✅</div>'
|
|
1441
|
+
+ '<div style="font-size:14px; font-weight:600; color:var(--text);">Dia limpo!</div>'
|
|
1442
|
+
+ '<div style="font-size:12px; color:var(--muted); text-align:center;">Nenhuma tarefa pendente (DO_NOW) nem bloqueios em aberto. Use o campo acima para registrar o que estiver fazendo.</div>';
|
|
1347
1443
|
el.appendChild(empty);
|
|
1348
1444
|
return;
|
|
1349
1445
|
}
|
|
1350
1446
|
|
|
1351
1447
|
const createTaskRow = (t) => {
|
|
1352
1448
|
const row = document.createElement('div');
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
row.
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
+ '<div style="
|
|
1360
|
-
+ '<
|
|
1361
|
-
+ '<
|
|
1449
|
+
const pc = priColor(t.priority);
|
|
1450
|
+
row.style.cssText = 'display:flex; justify-content:space-between; gap:10px; align-items:center; padding:10px 16px; background:var(--bg); border-bottom:1px solid var(--border); transition:background 0.15s;';
|
|
1451
|
+
row.onmouseover = () => row.style.background = 'var(--paper)';
|
|
1452
|
+
row.onmouseout = () => row.style.background = 'var(--bg)';
|
|
1453
|
+
row.innerHTML =
|
|
1454
|
+
'<div style="display:flex; align-items:center; gap:10px; min-width:0; flex:1;">'
|
|
1455
|
+
+ '<div style="width:8px; height:8px; border-radius:50%; background:' + pc.dot + '; flex-shrink:0;" title="Prioridade: ' + escapeHtml(pc.label) + '"></div>'
|
|
1456
|
+
+ '<div style="min-width:0;">'
|
|
1457
|
+
+ '<div style="font-weight:600; font-size:13px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">' + escapeHtml(t.description || '') + '</div>'
|
|
1458
|
+
+ '<div style="font-size:11px; color:var(--muted); margin-top:2px;">'
|
|
1459
|
+
+ escapeHtml(pc.label)
|
|
1460
|
+
+ (t.category ? ' · <span style="font-family:var(--mono);">' + escapeHtml(t.category) + '</span>' : '')
|
|
1362
1461
|
+ '</div>'
|
|
1462
|
+
+ '</div></div>'
|
|
1463
|
+
+ '<div style="display:flex; gap:6px; flex-shrink:0;">'
|
|
1464
|
+
+ '<button class="btn small complete-btn" type="button" style="padding:3px 10px; font-size:11px;" title="Marcar como concluída">✓ Concluir</button>'
|
|
1465
|
+
+ '<button class="btn small edit-btn" type="button" style="padding:3px 8px; font-size:11px;">✎</button>'
|
|
1363
1466
|
+ '</div>';
|
|
1364
1467
|
row.querySelector('.edit-btn').onclick = () => editTask(t);
|
|
1365
1468
|
row.querySelector('.complete-btn').onclick = async () => {
|
|
1469
|
+
const btn = row.querySelector('.complete-btn');
|
|
1470
|
+
btn.disabled = true;
|
|
1471
|
+
btn.textContent = '…';
|
|
1366
1472
|
try {
|
|
1367
|
-
setPill('run', '
|
|
1473
|
+
setPill('run', 'concluindo…');
|
|
1368
1474
|
await api('/api/tasks/complete', { dir: dirOrDefault(), id: t.id });
|
|
1475
|
+
row.style.opacity = '0.4';
|
|
1476
|
+
row.style.pointerEvents = 'none';
|
|
1369
1477
|
await refreshToday();
|
|
1370
|
-
setPill('ok', '
|
|
1478
|
+
setPill('ok', 'concluída');
|
|
1371
1479
|
setTimeout(() => setPill('ok', 'pronto'), 800);
|
|
1372
1480
|
} catch (e) {
|
|
1373
|
-
|
|
1374
|
-
|
|
1481
|
+
btn.disabled = false;
|
|
1482
|
+
btn.textContent = '✓ Concluir';
|
|
1483
|
+
setPill('err', 'falhou');
|
|
1375
1484
|
}
|
|
1376
1485
|
};
|
|
1377
1486
|
return row;
|
|
@@ -1379,81 +1488,57 @@
|
|
|
1379
1488
|
|
|
1380
1489
|
const createBlockerRow = (b) => {
|
|
1381
1490
|
const row = document.createElement('div');
|
|
1382
|
-
row.className = 'rep';
|
|
1383
|
-
row.style.borderLeft = '4px solid var(--warn)';
|
|
1384
|
-
row.style.background = 'var(--warn-bg)';
|
|
1385
1491
|
const sev = String(b.severity || '').toUpperCase();
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1492
|
+
const color = sevColor(sev);
|
|
1493
|
+
const when = fmtWhen(new Date(b.createdAt || Date.now()).getTime());
|
|
1494
|
+
row.style.cssText = 'display:flex; justify-content:space-between; gap:10px; align-items:center; padding:10px 16px; border-bottom:1px solid rgba(239,68,68,0.15); border-left:3px solid ' + color + '; background:rgba(239,68,68,0.04); transition:background 0.15s;';
|
|
1495
|
+
row.onmouseover = () => row.style.background = 'rgba(239,68,68,0.08)';
|
|
1496
|
+
row.onmouseout = () => row.style.background = 'rgba(239,68,68,0.04)';
|
|
1497
|
+
row.innerHTML =
|
|
1498
|
+
'<div style="display:flex; align-items:flex-start; gap:10px; min-width:0; flex:1;">'
|
|
1499
|
+
+ '<div style="flex-shrink:0; margin-top:1px;">'
|
|
1500
|
+
+ '<span style="font-size:10px; font-weight:800; letter-spacing:0.5px; padding:2px 6px; border-radius:4px; background:' + color + '22; color:' + color + '; border:1px solid ' + color + '44;">' + escapeHtml(sev || 'BLOCKER') + '</span>'
|
|
1393
1501
|
+ '</div>'
|
|
1394
|
-
+ '
|
|
1502
|
+
+ '<div style="min-width:0; flex:1;">'
|
|
1503
|
+
+ '<div style="font-weight:600; font-size:13px; color:var(--text);">' + escapeHtml(b.title || '') + '</div>'
|
|
1504
|
+
+ '<div style="font-size:11px; color:var(--muted); margin-top:3px;">🕐 ' + escapeHtml(when) + '</div>'
|
|
1505
|
+
+ '</div></div>'
|
|
1506
|
+
+ '<button class="btn small edit-btn" type="button" style="padding:3px 8px; font-size:11px; flex-shrink:0; border-color:' + color + '66; color:' + color + ';">✎</button>';
|
|
1395
1507
|
row.querySelector('.edit-btn').onclick = () => editBlocker(b);
|
|
1396
1508
|
return row;
|
|
1397
1509
|
};
|
|
1398
1510
|
|
|
1399
1511
|
for (const key of sortedKeys) {
|
|
1400
1512
|
const g = groups[key];
|
|
1513
|
+
const bCount = g.blockers.length;
|
|
1514
|
+
const tCount = g.tasks.length;
|
|
1515
|
+
const hasBlockers = bCount > 0;
|
|
1516
|
+
|
|
1401
1517
|
const swimlane = document.createElement('div');
|
|
1402
|
-
swimlane.
|
|
1403
|
-
swimlane.style.border = '1px solid var(--border)';
|
|
1404
|
-
swimlane.style.borderRadius = '8px';
|
|
1405
|
-
swimlane.style.boxShadow = 'none';
|
|
1406
|
-
swimlane.style.overflow = 'hidden';
|
|
1518
|
+
swimlane.style.cssText = 'border-bottom:1px solid var(--border); overflow:hidden;';
|
|
1407
1519
|
|
|
1408
1520
|
const head = document.createElement('div');
|
|
1409
|
-
head.style.
|
|
1410
|
-
|
|
1411
|
-
head.style.alignItems = 'center';
|
|
1412
|
-
head.style.cursor = 'pointer';
|
|
1413
|
-
head.style.padding = '10px 16px';
|
|
1414
|
-
head.style.background = 'var(--bg2)';
|
|
1415
|
-
head.style.borderBottom = '1px solid var(--border)';
|
|
1416
|
-
head.style.transition = 'background 0.2s';
|
|
1521
|
+
head.style.cssText = 'display:flex; justify-content:space-between; align-items:center; cursor:pointer; padding:9px 16px; background:var(--bg2); transition:background 0.15s;'
|
|
1522
|
+
+ (hasBlockers ? 'border-left:3px solid #f97316;' : 'border-left:3px solid transparent;');
|
|
1417
1523
|
head.onmouseover = () => head.style.background = 'var(--paper2)';
|
|
1418
1524
|
head.onmouseout = () => head.style.background = 'var(--bg2)';
|
|
1419
1525
|
|
|
1420
|
-
const bCount = g.blockers.length;
|
|
1421
|
-
const tCount = g.tasks.length;
|
|
1422
|
-
|
|
1423
1526
|
head.innerHTML = `
|
|
1424
|
-
<div style="
|
|
1425
|
-
<svg width="
|
|
1426
|
-
<span style="font-family:
|
|
1527
|
+
<div style="display:flex; align-items:center; gap:8px; min-width:0;">
|
|
1528
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="flex-shrink:0; opacity:0.5; transition:transform 0.2s;"><polyline points="6 9 12 15 18 9"></polyline></svg>
|
|
1529
|
+
<span style="font-family:var(--mono); font-size:12px; font-weight:700; color:var(--accent); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">${escapeHtml(key)}</span>
|
|
1427
1530
|
</div>
|
|
1428
|
-
<div style="display:flex; gap:
|
|
1429
|
-
${bCount > 0 ? `<span style="
|
|
1430
|
-
${tCount > 0 ? `<span style="
|
|
1531
|
+
<div style="display:flex; gap:5px; align-items:center; flex-shrink:0;">
|
|
1532
|
+
${bCount > 0 ? `<span style="font-size:11px; font-weight:700; padding:2px 7px; border-radius:10px; background:rgba(239,68,68,0.12); color:#f87171; border:1px solid rgba(239,68,68,0.3);">⛔ ${bCount}</span>` : ''}
|
|
1533
|
+
${tCount > 0 ? `<span style="font-size:11px; font-weight:700; padding:2px 7px; border-radius:10px; background:rgba(34,197,94,0.10); color:#4ade80; border:1px solid rgba(34,197,94,0.25);">✓ ${tCount}</span>` : ''}
|
|
1431
1534
|
</div>
|
|
1432
1535
|
`;
|
|
1433
1536
|
|
|
1434
1537
|
const body = document.createElement('div');
|
|
1435
|
-
body.style.
|
|
1436
|
-
|
|
1437
|
-
body.
|
|
1438
|
-
|
|
1439
|
-
for (const b of g.blockers) {
|
|
1440
|
-
const r = createBlockerRow(b);
|
|
1441
|
-
r.style.margin = '0';
|
|
1442
|
-
r.style.borderRadius = '0';
|
|
1443
|
-
r.style.borderBottom = '1px solid var(--border)';
|
|
1444
|
-
r.style.borderLeft = '4px solid var(--warn)';
|
|
1445
|
-
r.style.boxShadow = 'none';
|
|
1446
|
-
body.appendChild(r);
|
|
1447
|
-
}
|
|
1448
|
-
for (const t of g.tasks) {
|
|
1449
|
-
const r = createTaskRow(t);
|
|
1450
|
-
r.style.margin = '0';
|
|
1451
|
-
r.style.borderRadius = '0';
|
|
1452
|
-
r.style.borderBottom = '1px solid var(--border)';
|
|
1453
|
-
r.style.borderLeft = '4px solid transparent';
|
|
1454
|
-
r.style.boxShadow = 'none';
|
|
1455
|
-
body.appendChild(r);
|
|
1456
|
-
}
|
|
1538
|
+
body.style.cssText = 'display:flex; flex-direction:column; background:var(--bg);';
|
|
1539
|
+
|
|
1540
|
+
for (const b of g.blockers) body.appendChild(createBlockerRow(b));
|
|
1541
|
+
for (const t of g.tasks) body.appendChild(createTaskRow(t));
|
|
1457
1542
|
|
|
1458
1543
|
let isOpen = true;
|
|
1459
1544
|
head.onclick = () => {
|
|
@@ -1484,22 +1569,30 @@
|
|
|
1484
1569
|
|
|
1485
1570
|
function renderBlockersInsights(payload) {
|
|
1486
1571
|
const el = $('blockersInsights');
|
|
1572
|
+
const wrap = $('blockersInsightsWrap');
|
|
1487
1573
|
if (!el) return;
|
|
1574
|
+
|
|
1488
1575
|
if (!payload || !payload.summary) {
|
|
1489
|
-
|
|
1576
|
+
// Hide the strip if no content
|
|
1577
|
+
if (wrap) wrap.style.display = 'none';
|
|
1490
1578
|
return;
|
|
1491
1579
|
}
|
|
1580
|
+
|
|
1492
1581
|
const lines = [];
|
|
1493
|
-
lines.push('<div
|
|
1582
|
+
lines.push('<div style="margin-bottom:6px; color:var(--text);">' + escapeHtml(payload.summary) + '</div>');
|
|
1494
1583
|
if (payload.suggestions && payload.suggestions.length) {
|
|
1495
|
-
lines.push('<div
|
|
1496
|
-
lines.push('<ul style="margin:
|
|
1584
|
+
lines.push('<div style="font-weight:600; font-size:11px; text-transform:uppercase; letter-spacing:0.5px; color:var(--muted); margin:8px 0 4px;">Próximos passos</div>');
|
|
1585
|
+
lines.push('<ul style="margin:0 0 0 14px; padding:0;">' + payload.suggestions.map((s) => '<li style="margin-bottom:3px;">' + escapeHtml(s) + '</li>').join('') + '</ul>');
|
|
1497
1586
|
}
|
|
1498
1587
|
if (payload.top && payload.top.length) {
|
|
1499
|
-
lines.push('<div
|
|
1500
|
-
lines.push('<ul style="margin:
|
|
1588
|
+
lines.push('<div style="font-weight:600; font-size:11px; text-transform:uppercase; letter-spacing:0.5px; color:var(--muted); margin:8px 0 4px;">Top blockers</div>');
|
|
1589
|
+
lines.push('<ul style="margin:0 0 0 14px; padding:0;">' + payload.top.map((b) => {
|
|
1590
|
+
const c = sevColor(String(b.severity || '').toUpperCase());
|
|
1591
|
+
return '<li style="margin-bottom:3px;"><span style="color:' + c + '; font-weight:700;">' + escapeHtml(String(b.severity || '')) + '</span> — ' + escapeHtml(String(b.title || '')) + '</li>';
|
|
1592
|
+
}).join('') + '</ul>');
|
|
1501
1593
|
}
|
|
1502
1594
|
el.innerHTML = lines.join('');
|
|
1595
|
+
if (wrap) wrap.style.display = 'block';
|
|
1503
1596
|
}
|
|
1504
1597
|
|
|
1505
1598
|
async function refreshBlockersInsights() {
|
|
@@ -1872,22 +1965,6 @@
|
|
|
1872
1965
|
if (isCompanionPage) {
|
|
1873
1966
|
refreshHealthChecklist();
|
|
1874
1967
|
}
|
|
1875
|
-
// On Dashboard: reveal the reportPreviewPanel so the user can see the output.
|
|
1876
|
-
// The panel is hidden by default (display:none) and only shown after a report runs.
|
|
1877
|
-
const previewPanel = $('reportPreviewPanel');
|
|
1878
|
-
if (previewPanel) {
|
|
1879
|
-
previewPanel.style.display = '';
|
|
1880
|
-
const titleEl = $('reportPreviewTitle');
|
|
1881
|
-
const labels = {
|
|
1882
|
-
status: 'Relatório Executivo',
|
|
1883
|
-
'sm-weekly': 'SM Weekly Report',
|
|
1884
|
-
blockers: 'Relatório de Bloqueios',
|
|
1885
|
-
daily: 'Daily Summary',
|
|
1886
|
-
report: 'Relatório Semanal'
|
|
1887
|
-
};
|
|
1888
|
-
if (titleEl) titleEl.textContent = labels[name] || 'Relatório Gerado';
|
|
1889
|
-
previewPanel.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
1890
|
-
}
|
|
1891
1968
|
setPill('ok', name + ' ok');
|
|
1892
1969
|
} catch (e) {
|
|
1893
1970
|
setPill('err', name + ' failed');
|
|
@@ -1895,6 +1972,50 @@
|
|
|
1895
1972
|
}
|
|
1896
1973
|
}
|
|
1897
1974
|
|
|
1975
|
+
async function runReportPage(name) {
|
|
1976
|
+
// Disable all generation buttons and show spinner
|
|
1977
|
+
const genBtns = document.querySelectorAll('.reportsGenBar button');
|
|
1978
|
+
const spinner = $('reportsGenStatus');
|
|
1979
|
+
genBtns.forEach(b => { b.disabled = true; });
|
|
1980
|
+
if (spinner) spinner.style.display = '';
|
|
1981
|
+
|
|
1982
|
+
try {
|
|
1983
|
+
saveLocal();
|
|
1984
|
+
const r = await api('/api/report', { dir: dirOrDefault(), script: name });
|
|
1985
|
+
|
|
1986
|
+
// Refresh the full reports list and expand the newest report
|
|
1987
|
+
await refreshReportsPage();
|
|
1988
|
+
|
|
1989
|
+
// Auto-expand the first (newest) report in state.reports
|
|
1990
|
+
if (state.reports && state.reports.length > 0) {
|
|
1991
|
+
const newest = state.reports[0];
|
|
1992
|
+
state.reportExpanded[newest.relPath] = true;
|
|
1993
|
+
// Store the generated text directly so the card shows it immediately
|
|
1994
|
+
if (r.reportText) {
|
|
1995
|
+
state.reportTexts[newest.relPath] = r.reportText;
|
|
1996
|
+
}
|
|
1997
|
+
renderReportsPage();
|
|
1998
|
+
// Scroll to top of reportsGrid so user sees the expanded card
|
|
1999
|
+
const grid = $('reportsGrid');
|
|
2000
|
+
if (grid) grid.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
2001
|
+
}
|
|
2002
|
+
} catch (e) {
|
|
2003
|
+
// Show error inline in the gen bar
|
|
2004
|
+
if (spinner) {
|
|
2005
|
+
spinner.style.display = '';
|
|
2006
|
+
spinner.textContent = '❌ ' + (e && e.message ? e.message : 'Erro ao gerar relatório');
|
|
2007
|
+
setTimeout(() => {
|
|
2008
|
+
if (spinner) { spinner.style.display = 'none'; spinner.textContent = '⏳ Gerando...'; }
|
|
2009
|
+
}, 4000);
|
|
2010
|
+
}
|
|
2011
|
+
} finally {
|
|
2012
|
+
genBtns.forEach(b => { b.disabled = false; });
|
|
2013
|
+
if (spinner && !spinner.textContent.startsWith('❌')) {
|
|
2014
|
+
spinner.style.display = 'none';
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
|
|
1898
2019
|
async function exportObsidian() {
|
|
1899
2020
|
try {
|
|
1900
2021
|
setPill('run', 'exporting…');
|
|
@@ -2097,16 +2218,21 @@
|
|
|
2097
2218
|
if (!ta) return;
|
|
2098
2219
|
const text = (ta.value || '').trim();
|
|
2099
2220
|
if (!text) {
|
|
2100
|
-
setPill('err', '
|
|
2221
|
+
setPill('err', 'vazio');
|
|
2222
|
+
setTimeout(() => setPill('ok', 'pronto'), 800);
|
|
2101
2223
|
return;
|
|
2102
2224
|
}
|
|
2103
2225
|
|
|
2226
|
+
// Update mode tag
|
|
2227
|
+
const tag = $('chatModeTag');
|
|
2228
|
+
if (tag) { tag.textContent = 'inbox'; tag.style.color = 'var(--primary)'; tag.style.borderColor = 'var(--primary)'; }
|
|
2229
|
+
|
|
2104
2230
|
chatAppend('user', text);
|
|
2105
2231
|
|
|
2106
|
-
setPill('run', '
|
|
2232
|
+
setPill('run', 'salvando…');
|
|
2107
2233
|
await api('/api/inbox/add', { dir: dirOrDefault(), text });
|
|
2108
2234
|
|
|
2109
|
-
setPill('run', '
|
|
2235
|
+
setPill('run', 'processando…');
|
|
2110
2236
|
const r = await api('/api/agents/plan', { dir: dirOrDefault(), text });
|
|
2111
2237
|
|
|
2112
2238
|
state.lastPlan = r.plan || '';
|
|
@@ -2136,9 +2262,11 @@
|
|
|
2136
2262
|
setPill('ok', 'planned');
|
|
2137
2263
|
}
|
|
2138
2264
|
|
|
2265
|
+
const tag2 = $('chatModeTag');
|
|
2266
|
+
if (tag2) setTimeout(() => { tag2.textContent = 'oracle'; tag2.style.color = ''; tag2.style.borderColor = ''; }, 1500);
|
|
2139
2267
|
setTimeout(() => setPill('ok', 'pronto'), 1200);
|
|
2140
2268
|
} catch (e) {
|
|
2141
|
-
setPill('err', '
|
|
2269
|
+
setPill('err', 'falhou');
|
|
2142
2270
|
}
|
|
2143
2271
|
}
|
|
2144
2272
|
|
|
@@ -2314,6 +2442,7 @@
|
|
|
2314
2442
|
window.doMigrate = doMigrate;
|
|
2315
2443
|
window.pickDir = pickDir;
|
|
2316
2444
|
window.runReport = runReport;
|
|
2445
|
+
window.runReportPage = runReportPage;
|
|
2317
2446
|
window.publish = publish;
|
|
2318
2447
|
window.refreshReports = refreshReports;
|
|
2319
2448
|
window.refreshToday = refreshToday;
|
|
@@ -2356,4 +2485,5 @@
|
|
|
2356
2485
|
window.exportChatObsidian = exportChatObsidian;
|
|
2357
2486
|
window.askFreya = askFreya;
|
|
2358
2487
|
window.askFreyaInline = askFreyaInline;
|
|
2488
|
+
window.askFreyaFromInput = askFreyaFromInput;
|
|
2359
2489
|
})();
|
package/cli/web.js
CHANGED
|
@@ -1207,88 +1207,72 @@ function buildHtml(safeDefault, appVersion) {
|
|
|
1207
1207
|
</div>
|
|
1208
1208
|
|
|
1209
1209
|
<div class="centerBody">
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
<
|
|
1210
|
+
<!-- Unified Input + Chat Panel -->
|
|
1211
|
+
<section style="margin-bottom: 24px; display: grid; grid-template-columns: 1fr 1.6fr; gap: 16px; height: 420px; max-height: 480px;">
|
|
1212
|
+
|
|
1213
|
+
<!-- Left: Unified Input -->
|
|
1214
|
+
<div class="promptBar" style="width: 100%; border-radius: 20px; height: 100%; display: flex; flex-direction: column; overflow: hidden;">
|
|
1215
|
+
<div class="promptMeta" style="flex-shrink:0;">
|
|
1216
|
+
<div class="promptTitle" style="display: flex; align-items: center; gap: 8px;">
|
|
1217
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="color: var(--primary)"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg>
|
|
1218
|
+
<span>Freya Input</span>
|
|
1219
1219
|
</div>
|
|
1220
|
-
<
|
|
1220
|
+
<div id="status" class="small">pronto</div>
|
|
1221
1221
|
</div>
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1222
|
+
|
|
1223
|
+
<textarea id="inboxText" placeholder="Cole updates, decisões, blockers... ou faça uma pergunta à Freya. ▸ Salvar & Processar → extrai tarefas e blockers ▸ Perguntar → consulta o histórico (RAG)" style="resize:none; flex: 1; min-height: 0; border-radius: 0; border-left: none; border-right: none; border-top: none; border-bottom: 1px solid var(--border); padding: 14px 16px; font-size: 13px; line-height: 1.6;"
|
|
1224
|
+
onkeydown="if((event.metaKey||event.ctrlKey)&&event.key==='Enter'){event.preventDefault();window.saveAndPlan();}"></textarea>
|
|
1225
|
+
|
|
1226
|
+
<!-- Primary actions -->
|
|
1227
|
+
<div style="padding: 10px 14px 6px; display: flex; gap: 8px; flex-wrap: wrap; flex-shrink:0;">
|
|
1228
|
+
<button class="btn primary small" type="button" onclick="saveAndPlan()" style="flex:1; min-width: 120px;" title="Ctrl+Enter">
|
|
1229
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="display:inline;vertical-align:-2px;margin-right:5px"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg>
|
|
1230
|
+
Salvar & Processar
|
|
1231
|
+
</button>
|
|
1232
|
+
<button class="btn small" type="button" onclick="window.askFreyaFromInput()" style="flex:1; min-width: 90px;" title="Consulta semântica ao histórico">
|
|
1233
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:inline;vertical-align:-2px;margin-right:5px"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
|
|
1234
|
+
Perguntar
|
|
1235
|
+
</button>
|
|
1236
|
+
</div>
|
|
1237
|
+
|
|
1238
|
+
<!-- Toggles + secondary -->
|
|
1239
|
+
<div style="padding: 0 14px 12px; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px; flex-shrink:0;">
|
|
1240
|
+
<div class="promptToggles" style="margin:0;">
|
|
1241
|
+
<label class="toggleRow" title="Aplica o plano automaticamente após processar">
|
|
1229
1242
|
<input id="autoApply" type="checkbox" checked style="width:auto; margin: 0;" onchange="toggleAutoApply()" />
|
|
1230
1243
|
Auto-apply
|
|
1231
1244
|
</label>
|
|
1232
|
-
<label class="toggleRow">
|
|
1245
|
+
<label class="toggleRow" title="Roda relatórios sugeridos após aplicar">
|
|
1233
1246
|
<input id="autoRunReports" type="checkbox" style="width:auto; margin: 0;" onchange="toggleAutoRunReports()" />
|
|
1234
|
-
Auto-
|
|
1247
|
+
Auto-reports
|
|
1235
1248
|
</label>
|
|
1236
1249
|
</div>
|
|
1250
|
+
<div style="display:flex; gap:6px;">
|
|
1251
|
+
<button class="btn small" type="button" onclick="runSuggestedReports()" title="Rodar relatórios sugeridos pelo último plan" style="font-size:11px; padding: 3px 8px;">📋 Sugeridos</button>
|
|
1252
|
+
<button class="btn small" type="button" onclick="exportChatObsidian()" style="font-size:11px; padding: 3px 8px;" title="Exportar conversa para Obsidian">⬆ Log</button>
|
|
1253
|
+
</div>
|
|
1237
1254
|
</div>
|
|
1238
1255
|
</div>
|
|
1239
1256
|
|
|
1257
|
+
<!-- Right: Unified Chat Thread (Oracle responses + Plan outputs) -->
|
|
1240
1258
|
<div class="panel" style="height: 100%; display: flex; flex-direction: column;">
|
|
1241
|
-
<div class="panelHead">
|
|
1242
|
-
<b style="display: flex; align-items: center; gap: 8px;">
|
|
1243
|
-
<svg width="
|
|
1244
|
-
|
|
1259
|
+
<div class="panelHead" style="flex-shrink:0;">
|
|
1260
|
+
<b style="display: flex; align-items: center; gap: 8px; font-size:13px;">
|
|
1261
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="color:var(--accent)"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg>
|
|
1262
|
+
Conversa com a Freya
|
|
1245
1263
|
</b>
|
|
1246
1264
|
<div class="stack">
|
|
1247
|
-
<
|
|
1248
|
-
</div>
|
|
1249
|
-
</div>
|
|
1250
|
-
<div class="panelBody" style="flex:1; display:flex; flex-direction:column; padding:0; background:var(--glass-bg); min-height:0;">
|
|
1251
|
-
<div id="chatThread" style="flex:1; overflow-y:auto; overflow-x:hidden; padding:12px; display:flex; flex-direction:column; gap:8px;"></div>
|
|
1252
|
-
<div style="padding: 12px; border-top: 1px solid var(--glass-border); display:flex; gap: 8px; background: var(--paper);">
|
|
1253
|
-
<input type="text" id="oracleInput" autocomplete="off" style="flex:1;" placeholder="Pergunte algo à Freya..." onkeydown="if(event.key==='Enter') window.askFreyaInline()" />
|
|
1254
|
-
<button class="btn primary small" type="button" onclick="window.askFreyaInline()">Enviar</button>
|
|
1265
|
+
<span id="chatModeTag" style="font-size:11px; padding:2px 8px; border-radius:10px; background:var(--bg2); color:var(--muted); border:1px solid var(--border);">oracle</span>
|
|
1255
1266
|
</div>
|
|
1256
1267
|
</div>
|
|
1257
|
-
|
|
1258
|
-
</section>
|
|
1259
|
-
|
|
1260
|
-
<section class="utilityGrid" id="dashboardControls" style="display:grid; grid-template-columns: 1fr; gap: 16px; margin-bottom: 24px;">
|
|
1261
|
-
<div class="utilityCard" style="display:flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 16px;">
|
|
1262
|
-
<div>
|
|
1263
|
-
<div class="utilityHead" style="margin-bottom: 4px; color: var(--text);">Relatórios Rápidos</div>
|
|
1264
|
-
<div class="help" style="margin: 0;">Gere relatórios sintéticos instantaneamente</div>
|
|
1265
|
-
</div>
|
|
1266
|
-
<div style="display:flex; gap: 8px; flex-wrap: wrap;">
|
|
1267
|
-
<button class="btn" style="min-width: 100px; padding: 6px 12px; font-weight: 500;" type="button" onclick="runReport('status')">Executivo</button>
|
|
1268
|
-
<button class="btn" style="min-width: 100px; padding: 6px 12px; font-weight: 500;" type="button" onclick="runReport('sm-weekly')">SM Semanal</button>
|
|
1269
|
-
<button class="btn" style="min-width: 100px; padding: 6px 12px; font-weight: 500; border-color: rgba(239, 68, 68, 0.4); color: #f87171;" type="button" onclick="runReport('blockers')">Bloqueios</button>
|
|
1270
|
-
<button class="btn" style="min-width: 100px; padding: 6px 12px; font-weight: 500;" type="button" onclick="runReport('daily')">Daily</button>
|
|
1271
|
-
</div>
|
|
1272
|
-
</div>
|
|
1273
|
-
</section>
|
|
1274
|
-
|
|
1275
|
-
<!-- Report Preview Panel — populated by runReport() via setOut() -->
|
|
1276
|
-
<section class="panel" id="reportPreviewPanel" style="display:none; margin-bottom: 16px;">
|
|
1277
|
-
<div class="panelHead" style="background: linear-gradient(90deg, var(--paper2), var(--paper)); border-left: 4px solid var(--accent);">
|
|
1278
|
-
<b style="color: var(--text); font-size: 14px;" id="reportPreviewTitle">Relatório Gerado</b>
|
|
1279
|
-
<div class="stack">
|
|
1280
|
-
<button class="btn small" type="button" onclick="document.getElementById('reportPreviewPanel').style.display='none'">Fechar</button>
|
|
1281
|
-
</div>
|
|
1282
|
-
</div>
|
|
1283
|
-
<div class="panelBody panelScroll" style="max-height: 520px; overflow-y: auto;">
|
|
1284
|
-
<div id="reportPreview" class="log md" style="font-family: var(--sans); padding: 8px 0;"></div>
|
|
1268
|
+
<div id="chatThread" style="flex:1; overflow-y:auto; overflow-x:hidden; padding:12px; display:flex; flex-direction:column; gap:8px; min-height:0;"></div>
|
|
1285
1269
|
</div>
|
|
1286
1270
|
</section>
|
|
1287
1271
|
|
|
1288
1272
|
<div class="centerHead">
|
|
1289
1273
|
<div>
|
|
1290
1274
|
<h1 style="margin:0">Seu dia em um painel</h1>
|
|
1291
|
-
<div class="subtitle">
|
|
1275
|
+
<div class="subtitle">Use o campo acima para capturar updates (<b>Salvar & Processar</b>) ou consultar o histórico (<b>Perguntar</b>). As respostas aparecem no chat ao lado.</div>
|
|
1292
1276
|
</div>
|
|
1293
1277
|
<div class="statusLine">
|
|
1294
1278
|
<span class="small" id="last"></span>
|
|
@@ -1297,23 +1281,43 @@ function buildHtml(safeDefault, appVersion) {
|
|
|
1297
1281
|
|
|
1298
1282
|
<div class="midGrid">
|
|
1299
1283
|
<!-- Hoje Panel gets more prominent focus -->
|
|
1300
|
-
<section class="panel midSpan">
|
|
1301
|
-
|
|
1302
|
-
|
|
1284
|
+
<section class="panel midSpan" style="display:flex; flex-direction:column; min-height:0;">
|
|
1285
|
+
<!-- Header with live counters -->
|
|
1286
|
+
<div class="panelHead" style="background: linear-gradient(90deg, var(--paper2), var(--paper)); border-left: 4px solid var(--accent); flex-shrink:0;">
|
|
1287
|
+
<div style="display:flex; align-items:center; gap:10px;">
|
|
1288
|
+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="color:var(--accent); flex-shrink:0;"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>
|
|
1289
|
+
<b style="color: var(--text); font-size: 14px;">Foco de Hoje</b>
|
|
1290
|
+
<div id="focusSummaryChips" style="display:flex; gap:5px; margin-left:4px;"></div>
|
|
1291
|
+
</div>
|
|
1303
1292
|
<div class="stack">
|
|
1304
|
-
<
|
|
1293
|
+
<div id="focusProgressWrap" style="display:none; align-items:center; gap:6px; font-size:11px; color:var(--muted);">
|
|
1294
|
+
<div style="width:80px; height:5px; background:var(--border); border-radius:3px; overflow:hidden;">
|
|
1295
|
+
<div id="focusProgressBar" style="height:100%; background:var(--accent); border-radius:3px; transition:width 0.4s; width:0%"></div>
|
|
1296
|
+
</div>
|
|
1297
|
+
<span id="focusProgressLabel"></span>
|
|
1298
|
+
</div>
|
|
1299
|
+
<button class="btn small" type="button" onclick="refreshToday()">
|
|
1300
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="display:inline;vertical-align:-2px;margin-right:4px"><polyline points="23 4 23 10 17 10"></polyline><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path></svg>
|
|
1301
|
+
Atualizar
|
|
1302
|
+
</button>
|
|
1305
1303
|
</div>
|
|
1306
1304
|
</div>
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
<div style="
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1305
|
+
|
|
1306
|
+
<!-- Scrollable swimlanes body -->
|
|
1307
|
+
<div class="panelBody" style="flex:1; overflow-y:auto; display:flex; flex-direction:column; gap:0; padding:0; min-height:0;">
|
|
1308
|
+
<div id="swimlaneContainer" style="display:flex; flex-direction: column; gap: 0; flex:1;"></div>
|
|
1309
|
+
</div>
|
|
1310
|
+
|
|
1311
|
+
<!-- Insights strip (collapsed by default, expands when content is available) -->
|
|
1312
|
+
<div id="blockersInsightsWrap" style="flex-shrink:0; border-top: 1px solid var(--border); display:none;">
|
|
1313
|
+
<div style="display:flex; justify-content:space-between; align-items:center; padding: 8px 16px 4px;">
|
|
1314
|
+
<div style="font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:0.5px; color:var(--muted);">
|
|
1315
|
+
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:inline;vertical-align:-1px;margin-right:4px"><path d="M12 2a10 10 0 1 0 0 20A10 10 0 0 0 12 2z"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>
|
|
1316
|
+
Insights de Bloqueios
|
|
1314
1317
|
</div>
|
|
1315
|
-
<
|
|
1318
|
+
<button class="btn small" type="button" onclick="refreshBlockersInsights()" style="font-size:10px; padding:2px 6px;">↻</button>
|
|
1316
1319
|
</div>
|
|
1320
|
+
<div id="blockersInsights" style="padding: 4px 16px 12px; font-size:12px; color:var(--muted);"></div>
|
|
1317
1321
|
</div>
|
|
1318
1322
|
</section>
|
|
1319
1323
|
|
|
@@ -1322,6 +1326,7 @@ function buildHtml(safeDefault, appVersion) {
|
|
|
1322
1326
|
<b>Relatórios Recentes</b>
|
|
1323
1327
|
<div class="stack">
|
|
1324
1328
|
<button class="btn small" type="button" onclick="refreshReports()">Atualizar</button>
|
|
1329
|
+
<button class="btn small" type="button" onclick="window.location.href='/reports'">Ver todos →</button>
|
|
1325
1330
|
</div>
|
|
1326
1331
|
</div>
|
|
1327
1332
|
<div class="panelBody panelScroll" style="max-height: 300px;">
|
|
@@ -1439,6 +1444,21 @@ function buildReportsHtml(safeDefault, appVersion) {
|
|
|
1439
1444
|
</div>
|
|
1440
1445
|
</section>
|
|
1441
1446
|
|
|
1447
|
+
<!-- Report Generation Bar -->
|
|
1448
|
+
<section class="reportsGenBar" style="display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin-bottom:16px; padding:16px; background:var(--paper2); border-radius:8px; border:1px solid var(--border);">
|
|
1449
|
+
<div style="flex:1; min-width:140px;">
|
|
1450
|
+
<div style="font-size:13px; font-weight:600; color:var(--text); margin-bottom:2px;">Gerar Novo Relatório</div>
|
|
1451
|
+
<div style="font-size:12px; color:var(--muted);">O relatório gerado aparecerá no topo da lista</div>
|
|
1452
|
+
</div>
|
|
1453
|
+
<div style="display:flex; gap:8px; flex-wrap:wrap; align-items:center;">
|
|
1454
|
+
<button class="btn" style="min-width:110px;" type="button" onclick="runReportPage('daily')">📅 Daily</button>
|
|
1455
|
+
<button class="btn" style="min-width:110px;" type="button" onclick="runReportPage('status')">📊 Executivo</button>
|
|
1456
|
+
<button class="btn" style="min-width:110px; border-color:rgba(239,68,68,0.4); color:#f87171;" type="button" onclick="runReportPage('blockers')">🚧 Bloqueios</button>
|
|
1457
|
+
<button class="btn" style="min-width:110px;" type="button" onclick="runReportPage('sm-weekly')">📋 SM Weekly</button>
|
|
1458
|
+
<span id="reportsGenStatus" style="font-size:12px; color:var(--muted); display:none;">⏳ Gerando...</span>
|
|
1459
|
+
</div>
|
|
1460
|
+
</section>
|
|
1461
|
+
|
|
1442
1462
|
<section class="reportsTools" style="display:flex; gap:12px; align-items:center;">
|
|
1443
1463
|
<div class="tabs" style="display:flex; gap:8px;" id="reportsTabs">
|
|
1444
1464
|
<button class="pill ok" id="tabChrono" onclick="setReportsTab('chrono')">Cronológico</button>
|
|
@@ -1829,12 +1849,9 @@ function buildCompanionHtml(safeDefault, appVersion) {
|
|
|
1829
1849
|
</div>
|
|
1830
1850
|
</section>
|
|
1831
1851
|
|
|
1832
|
-
<
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
<button class="btn" type="button" onclick="runReport('status')">Gerar Status</button>
|
|
1836
|
-
<button class="btn" type="button" onclick="runReport('sm-weekly')">Gerar SM Weekly</button>
|
|
1837
|
-
</section>
|
|
1852
|
+
<button class="btn small" type="button" onclick="window.location.href='/reports'" style="margin-bottom: 16px;">
|
|
1853
|
+
📊 Ver / Gerar Relatórios →
|
|
1854
|
+
</button>
|
|
1838
1855
|
|
|
1839
1856
|
<!-- BENTO GRID LAYOUT -->
|
|
1840
1857
|
<div style="display: grid; grid-template-columns: 1fr 1.5fr; gap: 24px; align-items: start;">
|
|
@@ -1914,12 +1931,6 @@ function buildCompanionHtml(safeDefault, appVersion) {
|
|
|
1914
1931
|
</div>
|
|
1915
1932
|
</section>
|
|
1916
1933
|
|
|
1917
|
-
<section class="panel">
|
|
1918
|
-
<div class="panelHead"><b>Saída de Relatório</b></div>
|
|
1919
|
-
<div class="panelBody">
|
|
1920
|
-
<div id="reportPreview" class="log md" style="font-family: var(--sans);"></div>
|
|
1921
|
-
</div>
|
|
1922
|
-
</section>
|
|
1923
1934
|
</div>
|
|
1924
1935
|
|
|
1925
1936
|
</div>
|
package/package.json
CHANGED