@cccarv82/freya 3.3.0 → 3.4.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.css +41 -28
- package/cli/web-ui.js +214 -42
- package/cli/web.js +683 -33
- package/package.json +1 -1
package/cli/web-ui.css
CHANGED
|
@@ -1803,43 +1803,56 @@ body:not([data-page="kanban"]) .kanban-col-body {
|
|
|
1803
1803
|
min-width: 180px;
|
|
1804
1804
|
}
|
|
1805
1805
|
|
|
1806
|
-
/* Kanban
|
|
1807
|
-
.kanban-
|
|
1806
|
+
/* Blocker Kanban Board */
|
|
1807
|
+
.blocker-kanban-board {
|
|
1808
|
+
display: grid;
|
|
1809
|
+
grid-template-columns: repeat(3, 1fr);
|
|
1810
|
+
gap: 12px;
|
|
1811
|
+
min-height: 120px;
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
@media (max-width: 900px) {
|
|
1815
|
+
.blocker-kanban-board { grid-template-columns: 1fr; }
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
.blocker-kanban-col {
|
|
1808
1819
|
display: flex;
|
|
1809
|
-
flex-
|
|
1810
|
-
|
|
1820
|
+
flex-direction: column;
|
|
1821
|
+
background: var(--bg);
|
|
1822
|
+
border: 1px solid var(--line2);
|
|
1823
|
+
min-height: 80px;
|
|
1811
1824
|
}
|
|
1812
1825
|
|
|
1813
|
-
.kanban-
|
|
1826
|
+
.blocker-kanban-col-body {
|
|
1827
|
+
flex: 1;
|
|
1828
|
+
padding: 8px;
|
|
1814
1829
|
display: flex;
|
|
1815
|
-
|
|
1830
|
+
flex-direction: column;
|
|
1816
1831
|
gap: 8px;
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
flex: 1 1 300px;
|
|
1822
|
-
max-width: 500px;
|
|
1832
|
+
overflow-y: auto;
|
|
1833
|
+
max-height: 300px;
|
|
1834
|
+
min-height: 50px;
|
|
1835
|
+
transition: background 0.15s;
|
|
1823
1836
|
}
|
|
1824
1837
|
|
|
1825
|
-
.kanban-
|
|
1826
|
-
|
|
1827
|
-
font-weight: 800;
|
|
1828
|
-
letter-spacing: 0.5px;
|
|
1829
|
-
padding: 2px 6px;
|
|
1830
|
-
border: 1px solid;
|
|
1831
|
-
flex-shrink: 0;
|
|
1838
|
+
.blocker-kanban-col-body.drag-over {
|
|
1839
|
+
background: rgba(239, 68, 68, 0.06);
|
|
1832
1840
|
}
|
|
1833
1841
|
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1842
|
+
/* Blocker column header colors */
|
|
1843
|
+
.kanban-col-head.blocker-open { border-bottom-color: #ef4444; }
|
|
1844
|
+
.kanban-col-head.blocker-open .kanban-col-title { color: #ef4444; }
|
|
1845
|
+
.kanban-col-head.blocker-open .kanban-col-count { background: #ef444422; color: #ef4444; }
|
|
1846
|
+
.kanban-col-head.blocker-mitigating { border-bottom-color: #f59e0b; }
|
|
1847
|
+
.kanban-col-head.blocker-mitigating .kanban-col-title { color: #f59e0b; }
|
|
1848
|
+
.kanban-col-head.blocker-mitigating .kanban-col-count { background: #f59e0b22; color: #f59e0b; }
|
|
1849
|
+
.kanban-col-head.blocker-resolved { border-bottom-color: #22c55e; }
|
|
1850
|
+
.kanban-col-head.blocker-resolved .kanban-col-title { color: #22c55e; }
|
|
1851
|
+
.kanban-col-head.blocker-resolved .kanban-col-count { background: #22c55e22; color: #22c55e; }
|
|
1852
|
+
|
|
1853
|
+
/* Blocker card in kanban (reuses .kanban-card) */
|
|
1854
|
+
.kanban-card.blocker-card {
|
|
1855
|
+
border-left: 3px solid #ef4444;
|
|
1843
1856
|
}
|
|
1844
1857
|
|
|
1845
1858
|
/* ── Quick-Add Modal ── */
|
package/cli/web-ui.js
CHANGED
|
@@ -3232,7 +3232,7 @@
|
|
|
3232
3232
|
// Drag events
|
|
3233
3233
|
if (cat !== 'COMPLETED') {
|
|
3234
3234
|
card.addEventListener('dragstart', function(e) {
|
|
3235
|
-
e.dataTransfer.setData('text/
|
|
3235
|
+
e.dataTransfer.setData('text/task-id', t.id);
|
|
3236
3236
|
e.dataTransfer.effectAllowed = 'move';
|
|
3237
3237
|
card.classList.add('dragging');
|
|
3238
3238
|
});
|
|
@@ -3252,34 +3252,10 @@
|
|
|
3252
3252
|
};
|
|
3253
3253
|
}
|
|
3254
3254
|
|
|
3255
|
-
// Edit button -
|
|
3255
|
+
// Edit button - open full edit modal
|
|
3256
3256
|
var editBtn = card.querySelector('.edit-btn');
|
|
3257
3257
|
if (editBtn) {
|
|
3258
|
-
editBtn.onclick =
|
|
3259
|
-
var newCat = prompt('Categoria (DO_NOW|SCHEDULE|DELEGATE):', cat);
|
|
3260
|
-
if (!newCat) return;
|
|
3261
|
-
var newSlug = prompt('Projeto (slug):', t.projectSlug || '');
|
|
3262
|
-
if (newSlug === null) return;
|
|
3263
|
-
var currentDueBR = t.dueDate ? fmtDateBR(t.dueDate) : '';
|
|
3264
|
-
var newDueBR = prompt('Due date (dd/mm/aaaa):', currentDueBR);
|
|
3265
|
-
if (newDueBR === null) return;
|
|
3266
|
-
// Convert dd/mm/aaaa back to YYYY-MM-DD for API
|
|
3267
|
-
var newDue = '';
|
|
3268
|
-
if (newDueBR && newDueBR.indexOf('/') > -1) {
|
|
3269
|
-
var dp = newDueBR.split('/');
|
|
3270
|
-
if (dp.length === 3) newDue = dp[2] + '-' + dp[1] + '-' + dp[0];
|
|
3271
|
-
} else {
|
|
3272
|
-
newDue = newDueBR; // fallback: accept YYYY-MM-DD too
|
|
3273
|
-
}
|
|
3274
|
-
try {
|
|
3275
|
-
await api('/api/tasks/update', {
|
|
3276
|
-
dir: dirOrDefault(), id: t.id,
|
|
3277
|
-
patch: { category: newCat, projectSlug: newSlug, dueDate: newDue || null }
|
|
3278
|
-
});
|
|
3279
|
-
showToast('ok', 'Atualizada');
|
|
3280
|
-
await loadKanban();
|
|
3281
|
-
} catch { showToast('err', 'Falhou'); }
|
|
3282
|
-
};
|
|
3258
|
+
editBtn.onclick = function() { openTaskEdit(t); };
|
|
3283
3259
|
}
|
|
3284
3260
|
}
|
|
3285
3261
|
|
|
@@ -3299,7 +3275,7 @@
|
|
|
3299
3275
|
el.addEventListener('drop', async function(e) {
|
|
3300
3276
|
e.preventDefault();
|
|
3301
3277
|
el.classList.remove('drag-over');
|
|
3302
|
-
var taskId = e.dataTransfer.getData('text/
|
|
3278
|
+
var taskId = e.dataTransfer.getData('text/task-id');
|
|
3303
3279
|
if (!taskId) return;
|
|
3304
3280
|
try {
|
|
3305
3281
|
await api('/api/tasks/update', {
|
|
@@ -3316,33 +3292,229 @@
|
|
|
3316
3292
|
|
|
3317
3293
|
function renderKanbanBlockers() {
|
|
3318
3294
|
var wrap = $('kanbanBlockers');
|
|
3319
|
-
|
|
3320
|
-
if (!wrap || !list) return;
|
|
3295
|
+
if (!wrap) return;
|
|
3321
3296
|
|
|
3322
3297
|
var sel = $('kanbanFilterProject');
|
|
3323
3298
|
var filter = sel ? sel.value : '';
|
|
3324
|
-
var blockers = _kanbanData.blockers;
|
|
3299
|
+
var blockers = _kanbanData.blockers || [];
|
|
3325
3300
|
if (filter) blockers = blockers.filter(function(b) { return b.projectSlug === filter; });
|
|
3326
3301
|
|
|
3327
3302
|
if (blockers.length === 0) { wrap.style.display = 'none'; return; }
|
|
3328
3303
|
wrap.style.display = 'block';
|
|
3329
|
-
list.innerHTML = '';
|
|
3330
3304
|
|
|
3305
|
+
// Sort into columns
|
|
3306
|
+
var cols = { OPEN: [], MITIGATING: [], RESOLVED: [] };
|
|
3331
3307
|
blockers.forEach(function(b) {
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3308
|
+
if (cols[b.status]) cols[b.status].push(b);
|
|
3309
|
+
});
|
|
3310
|
+
|
|
3311
|
+
var idMap = { OPEN: 'colBlockerOpen', MITIGATING: 'colBlockerMitigating', RESOLVED: 'colBlockerResolved' };
|
|
3312
|
+
var countMap = { OPEN: 'countBlockerOpen', MITIGATING: 'countBlockerMitigating', RESOLVED: 'countBlockerResolved' };
|
|
3313
|
+
|
|
3314
|
+
['OPEN', 'MITIGATING', 'RESOLVED'].forEach(function(status) {
|
|
3315
|
+
var el = $(idMap[status]);
|
|
3316
|
+
var countEl = $(countMap[status]);
|
|
3317
|
+
if (!el) return;
|
|
3318
|
+
el.innerHTML = '';
|
|
3319
|
+
if (countEl) countEl.textContent = cols[status].length;
|
|
3320
|
+
|
|
3321
|
+
cols[status].forEach(function(b) {
|
|
3322
|
+
var card = document.createElement('div');
|
|
3323
|
+
card.className = 'kanban-card blocker-card';
|
|
3324
|
+
card.setAttribute('data-blocker-id', b.id);
|
|
3325
|
+
if (status !== 'RESOLVED') card.draggable = true;
|
|
3326
|
+
|
|
3327
|
+
var color = sevColor(b.severity);
|
|
3328
|
+
var html = '<div class="kanban-card-header">'
|
|
3329
|
+
+ '<span class="kanban-priority-dot" style="background:' + color + ';" title="' + escapeHtml(b.severity) + '"></span>'
|
|
3330
|
+
+ '<span class="kanban-card-desc">' + escapeHtml(b.title || '') + '</span>'
|
|
3331
|
+
+ '</div>';
|
|
3332
|
+
html += '<div class="kanban-card-meta">';
|
|
3333
|
+
if (b.projectSlug) html += '<span class="kanban-tag">' + escapeHtml(b.projectSlug) + '</span>';
|
|
3334
|
+
if (b.owner) html += '<span class="kanban-tag" style="background:var(--chip);">' + escapeHtml(b.owner) + '</span>';
|
|
3335
|
+
html += '</div>';
|
|
3336
|
+
if (status !== 'RESOLVED') {
|
|
3337
|
+
html += '<div class="kanban-card-actions">'
|
|
3338
|
+
+ '<button class="edit-btn" title="Editar">'
|
|
3339
|
+
+ '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>'
|
|
3340
|
+
+ '</button></div>';
|
|
3341
|
+
}
|
|
3342
|
+
card.innerHTML = html;
|
|
3343
|
+
|
|
3344
|
+
// Click → detail panel (only if not dragging)
|
|
3345
|
+
var _bDragged = false;
|
|
3346
|
+
card.addEventListener('mousedown', function() { _bDragged = false; });
|
|
3347
|
+
card.addEventListener('mousemove', function() { _bDragged = true; });
|
|
3348
|
+
card.addEventListener('click', function(e) {
|
|
3349
|
+
if (_bDragged) return;
|
|
3350
|
+
if (e.target.closest('.kanban-card-actions')) return;
|
|
3351
|
+
showDetailPanel(b, 'blocker');
|
|
3352
|
+
});
|
|
3353
|
+
|
|
3354
|
+
// Drag events
|
|
3355
|
+
if (status !== 'RESOLVED') {
|
|
3356
|
+
card.addEventListener('dragstart', function(e) {
|
|
3357
|
+
e.dataTransfer.setData('text/blocker-id', b.id);
|
|
3358
|
+
e.dataTransfer.effectAllowed = 'move';
|
|
3359
|
+
card.classList.add('dragging');
|
|
3360
|
+
});
|
|
3361
|
+
card.addEventListener('dragend', function() {
|
|
3362
|
+
card.classList.remove('dragging');
|
|
3363
|
+
});
|
|
3364
|
+
}
|
|
3365
|
+
|
|
3366
|
+
// Edit button
|
|
3367
|
+
var editBtn = card.querySelector('.edit-btn');
|
|
3368
|
+
if (editBtn) {
|
|
3369
|
+
editBtn.onclick = function(e) { e.stopPropagation(); openBlockerEdit(b); };
|
|
3370
|
+
}
|
|
3371
|
+
|
|
3372
|
+
el.appendChild(card);
|
|
3373
|
+
});
|
|
3374
|
+
|
|
3375
|
+
// Drop zone
|
|
3376
|
+
el.addEventListener('dragover', function(e) {
|
|
3377
|
+
e.preventDefault();
|
|
3378
|
+
e.dataTransfer.dropEffect = 'move';
|
|
3379
|
+
el.classList.add('drag-over');
|
|
3380
|
+
});
|
|
3381
|
+
el.addEventListener('dragleave', function() {
|
|
3382
|
+
el.classList.remove('drag-over');
|
|
3383
|
+
});
|
|
3384
|
+
el.addEventListener('drop', async function(e) {
|
|
3385
|
+
e.preventDefault();
|
|
3386
|
+
el.classList.remove('drag-over');
|
|
3387
|
+
var blockerId = e.dataTransfer.getData('text/blocker-id');
|
|
3388
|
+
if (!blockerId) return;
|
|
3389
|
+
try {
|
|
3390
|
+
await api('/api/blockers/update', {
|
|
3391
|
+
dir: dirOrDefault(), id: blockerId,
|
|
3392
|
+
patch: { status: status }
|
|
3393
|
+
});
|
|
3394
|
+
showToast('ok', 'Blocker → ' + status);
|
|
3395
|
+
await loadKanban();
|
|
3396
|
+
} catch { showToast('err', 'Falhou'); }
|
|
3397
|
+
});
|
|
3342
3398
|
});
|
|
3343
3399
|
}
|
|
3344
3400
|
|
|
3401
|
+
// === Task Edit Modal ===
|
|
3402
|
+
function openTaskEdit(t) {
|
|
3403
|
+
var overlay = $('taskEditOverlay');
|
|
3404
|
+
if (!overlay) return;
|
|
3405
|
+
$('teTaskId').value = t.id;
|
|
3406
|
+
$('teDesc').value = t.description || '';
|
|
3407
|
+
$('teCat').value = t.category || 'DO_NOW';
|
|
3408
|
+
$('tePriority').value = t.priority || '';
|
|
3409
|
+
$('teSlug').value = t.projectSlug || '';
|
|
3410
|
+
$('teDue').value = t.dueDate ? fmtDateBR(t.dueDate) : '';
|
|
3411
|
+
var stream = $('teStream');
|
|
3412
|
+
if (stream) stream.value = t.streamSlug || '';
|
|
3413
|
+
overlay.style.display = 'flex';
|
|
3414
|
+
// Wire date picker sync
|
|
3415
|
+
var picker = $('teDuePicker');
|
|
3416
|
+
var txt = $('teDue');
|
|
3417
|
+
if (picker && txt) {
|
|
3418
|
+
picker.onchange = function() {
|
|
3419
|
+
if (!picker.value) return;
|
|
3420
|
+
var p = picker.value.split('-');
|
|
3421
|
+
if (p.length === 3) txt.value = p[2] + '/' + p[1] + '/' + p[0];
|
|
3422
|
+
};
|
|
3423
|
+
}
|
|
3424
|
+
$('teDesc').focus();
|
|
3425
|
+
}
|
|
3426
|
+
|
|
3427
|
+
function closeTaskEdit() {
|
|
3428
|
+
var overlay = $('taskEditOverlay');
|
|
3429
|
+
if (overlay) overlay.style.display = 'none';
|
|
3430
|
+
}
|
|
3431
|
+
|
|
3432
|
+
async function submitTaskEdit() {
|
|
3433
|
+
var id = $('teTaskId').value;
|
|
3434
|
+
if (!id) return;
|
|
3435
|
+
var desc = ($('teDesc').value || '').trim();
|
|
3436
|
+
var cat = $('teCat').value;
|
|
3437
|
+
var priority = $('tePriority').value;
|
|
3438
|
+
var slug = ($('teSlug').value || '').trim();
|
|
3439
|
+
var dueBR = ($('teDue').value || '').trim();
|
|
3440
|
+
var stream = ($('teStream') ? $('teStream').value : '').trim();
|
|
3441
|
+
|
|
3442
|
+
// Convert dd/mm/aaaa → YYYY-MM-DD
|
|
3443
|
+
var due = null;
|
|
3444
|
+
if (dueBR && dueBR.indexOf('/') > -1) {
|
|
3445
|
+
var dp = dueBR.split('/');
|
|
3446
|
+
if (dp.length === 3) due = dp[2] + '-' + dp[1] + '-' + dp[0];
|
|
3447
|
+
} else if (dueBR) {
|
|
3448
|
+
due = dueBR;
|
|
3449
|
+
}
|
|
3450
|
+
|
|
3451
|
+
try {
|
|
3452
|
+
await api('/api/tasks/update', {
|
|
3453
|
+
dir: dirOrDefault(), id: id,
|
|
3454
|
+
patch: { description: desc, category: cat, priority: priority, projectSlug: slug, dueDate: due, streamSlug: stream }
|
|
3455
|
+
});
|
|
3456
|
+
closeTaskEdit();
|
|
3457
|
+
showToast('ok', 'Task atualizada');
|
|
3458
|
+
await loadKanban();
|
|
3459
|
+
} catch { showToast('err', 'Falhou'); }
|
|
3460
|
+
}
|
|
3461
|
+
|
|
3462
|
+
// === Blocker Edit Modal ===
|
|
3463
|
+
function openBlockerEdit(b) {
|
|
3464
|
+
var overlay = $('blockerEditOverlay');
|
|
3465
|
+
if (!overlay) return;
|
|
3466
|
+
$('beBlockerId').value = b.id;
|
|
3467
|
+
$('beTitle').value = b.title || '';
|
|
3468
|
+
$('beSeverity').value = b.severity || 'MEDIUM';
|
|
3469
|
+
$('beStatus').value = b.status || 'OPEN';
|
|
3470
|
+
$('beSlug').value = b.projectSlug || '';
|
|
3471
|
+
$('beOwner').value = b.owner || '';
|
|
3472
|
+
$('beNextAction').value = b.nextAction || '';
|
|
3473
|
+
overlay.style.display = 'flex';
|
|
3474
|
+
$('beTitle').focus();
|
|
3475
|
+
}
|
|
3476
|
+
|
|
3477
|
+
function closeBlockerEdit() {
|
|
3478
|
+
var overlay = $('blockerEditOverlay');
|
|
3479
|
+
if (overlay) overlay.style.display = 'none';
|
|
3480
|
+
}
|
|
3481
|
+
|
|
3482
|
+
async function submitBlockerEdit() {
|
|
3483
|
+
var id = $('beBlockerId').value;
|
|
3484
|
+
if (!id) return;
|
|
3485
|
+
var title = ($('beTitle').value || '').trim();
|
|
3486
|
+
var severity = $('beSeverity').value;
|
|
3487
|
+
var status = $('beStatus').value;
|
|
3488
|
+
var slug = ($('beSlug').value || '').trim();
|
|
3489
|
+
var owner = ($('beOwner').value || '').trim();
|
|
3490
|
+
var nextAction = ($('beNextAction').value || '').trim();
|
|
3491
|
+
|
|
3492
|
+
try {
|
|
3493
|
+
await api('/api/blockers/update', {
|
|
3494
|
+
dir: dirOrDefault(), id: id,
|
|
3495
|
+
patch: { title: title, severity: severity, status: status, projectSlug: slug, owner: owner, nextAction: nextAction }
|
|
3496
|
+
});
|
|
3497
|
+
closeBlockerEdit();
|
|
3498
|
+
showToast('ok', 'Blocker atualizado');
|
|
3499
|
+
await loadKanban();
|
|
3500
|
+
} catch { showToast('err', 'Falhou'); }
|
|
3501
|
+
}
|
|
3502
|
+
|
|
3503
|
+
// Close modals on Escape
|
|
3504
|
+
document.addEventListener('keydown', function(e) {
|
|
3505
|
+
if (e.key === 'Escape') {
|
|
3506
|
+
if ($('taskEditOverlay') && $('taskEditOverlay').style.display !== 'none') closeTaskEdit();
|
|
3507
|
+
if ($('blockerEditOverlay') && $('blockerEditOverlay').style.display !== 'none') closeBlockerEdit();
|
|
3508
|
+
}
|
|
3509
|
+
});
|
|
3510
|
+
|
|
3345
3511
|
window.loadKanban = loadKanban;
|
|
3346
3512
|
window.filterKanban = filterKanban;
|
|
3347
3513
|
window.loadDelta = loadDelta;
|
|
3514
|
+
window.openTaskEdit = openTaskEdit;
|
|
3515
|
+
window.closeTaskEdit = closeTaskEdit;
|
|
3516
|
+
window.submitTaskEdit = submitTaskEdit;
|
|
3517
|
+
window.openBlockerEdit = openBlockerEdit;
|
|
3518
|
+
window.closeBlockerEdit = closeBlockerEdit;
|
|
3519
|
+
window.submitBlockerEdit = submitBlockerEdit;
|
|
3348
3520
|
})();
|
package/cli/web.js
CHANGED
|
@@ -1110,6 +1110,79 @@ function buildDocsHtml(safeDefault, appVersion) {
|
|
|
1110
1110
|
</div>
|
|
1111
1111
|
</div>
|
|
1112
1112
|
|
|
1113
|
+
<!-- Task Edit Modal -->
|
|
1114
|
+
<div id="taskEditOverlay" class="qa-overlay" style="display:none;">
|
|
1115
|
+
<div class="qa-modal" style="width:520px;">
|
|
1116
|
+
<div class="qa-header">
|
|
1117
|
+
<span style="font-weight:700; font-size:14px;">Editar Task</span>
|
|
1118
|
+
<button class="btn small" type="button" onclick="window.closeTaskEdit()" style="padding:2px 8px;">×</button>
|
|
1119
|
+
</div>
|
|
1120
|
+
<input type="hidden" id="teTaskId" />
|
|
1121
|
+
<textarea id="teDesc" class="qa-input" placeholder="Descri\u00e7\u00e3o da task..." rows="3"></textarea>
|
|
1122
|
+
<div class="qa-row">
|
|
1123
|
+
<select id="teCat" class="qa-select">
|
|
1124
|
+
<option value="DO_NOW">DO_NOW</option>
|
|
1125
|
+
<option value="SCHEDULE">SCHEDULE</option>
|
|
1126
|
+
<option value="DELEGATE">DELEGATE</option>
|
|
1127
|
+
</select>
|
|
1128
|
+
<select id="tePriority" class="qa-select">
|
|
1129
|
+
<option value="">Prioridade</option>
|
|
1130
|
+
<option value="critical">Cr\u00edtica</option>
|
|
1131
|
+
<option value="high">Alta</option>
|
|
1132
|
+
<option value="medium">M\u00e9dia</option>
|
|
1133
|
+
<option value="low">Baixa</option>
|
|
1134
|
+
</select>
|
|
1135
|
+
</div>
|
|
1136
|
+
<div class="qa-row">
|
|
1137
|
+
<input id="teSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
|
|
1138
|
+
<div class="qa-date-wrap">
|
|
1139
|
+
<input id="teDue" type="text" class="qa-input qa-date-text" placeholder="dd/mm/aaaa" maxlength="10" />
|
|
1140
|
+
<input id="teDuePicker" type="date" class="qa-date-hidden" tabindex="-1" />
|
|
1141
|
+
<button type="button" class="qa-date-btn" onclick="var p=document.getElementById('teDuePicker'); p.showPicker ? p.showPicker() : p.click();" title="Abrir calendario">📅</button>
|
|
1142
|
+
</div>
|
|
1143
|
+
</div>
|
|
1144
|
+
<div class="qa-row">
|
|
1145
|
+
<input id="teStream" class="qa-input" placeholder="Stream / frente (opcional)" style="flex:1;" />
|
|
1146
|
+
</div>
|
|
1147
|
+
<div class="qa-row" style="justify-content:flex-end;">
|
|
1148
|
+
<button class="btn small" type="button" onclick="window.closeTaskEdit()">Cancelar</button>
|
|
1149
|
+
<button class="btn primary small" type="button" onclick="window.submitTaskEdit()">Salvar</button>
|
|
1150
|
+
</div>
|
|
1151
|
+
</div>
|
|
1152
|
+
</div>
|
|
1153
|
+
<!-- Blocker Edit Modal -->
|
|
1154
|
+
<div id="blockerEditOverlay" class="qa-overlay" style="display:none;">
|
|
1155
|
+
<div class="qa-modal" style="width:520px;">
|
|
1156
|
+
<div class="qa-header">
|
|
1157
|
+
<span style="font-weight:700; font-size:14px;">Editar Blocker</span>
|
|
1158
|
+
<button class="btn small" type="button" onclick="window.closeBlockerEdit()" style="padding:2px 8px;">×</button>
|
|
1159
|
+
</div>
|
|
1160
|
+
<input type="hidden" id="beBlockerId" />
|
|
1161
|
+
<textarea id="beTitle" class="qa-input" placeholder="T\u00edtulo do blocker..." rows="2"></textarea>
|
|
1162
|
+
<div class="qa-row">
|
|
1163
|
+
<select id="beSeverity" class="qa-select">
|
|
1164
|
+
<option value="CRITICAL">Critical</option>
|
|
1165
|
+
<option value="HIGH">High</option>
|
|
1166
|
+
<option value="MEDIUM">Medium</option>
|
|
1167
|
+
<option value="LOW">Low</option>
|
|
1168
|
+
</select>
|
|
1169
|
+
<select id="beStatus" class="qa-select">
|
|
1170
|
+
<option value="OPEN">Open</option>
|
|
1171
|
+
<option value="MITIGATING">Mitigating</option>
|
|
1172
|
+
<option value="RESOLVED">Resolved</option>
|
|
1173
|
+
</select>
|
|
1174
|
+
</div>
|
|
1175
|
+
<div class="qa-row">
|
|
1176
|
+
<input id="beSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
|
|
1177
|
+
<input id="beOwner" class="qa-input" placeholder="Respons\u00e1vel" style="flex:1;" />
|
|
1178
|
+
</div>
|
|
1179
|
+
<textarea id="beNextAction" class="qa-input" placeholder="Pr\u00f3xima a\u00e7\u00e3o..." rows="2"></textarea>
|
|
1180
|
+
<div class="qa-row" style="justify-content:flex-end;">
|
|
1181
|
+
<button class="btn small" type="button" onclick="window.closeBlockerEdit()">Cancelar</button>
|
|
1182
|
+
<button class="btn primary small" type="button" onclick="window.submitBlockerEdit()">Salvar</button>
|
|
1183
|
+
</div>
|
|
1184
|
+
</div>
|
|
1185
|
+
</div>
|
|
1113
1186
|
<script>
|
|
1114
1187
|
window.__FREYA_DEFAULT_DIR = "${safeDefault}";
|
|
1115
1188
|
</script>
|
|
@@ -1289,13 +1362,35 @@ function buildHtml(safeDefault, appVersion) {
|
|
|
1289
1362
|
</div>
|
|
1290
1363
|
</div>
|
|
1291
1364
|
|
|
1292
|
-
<!--
|
|
1365
|
+
<!-- Blocker Kanban Board -->
|
|
1293
1366
|
<div id="kanbanBlockers" style="margin-top:20px; display:none;">
|
|
1294
1367
|
<div style="font-size:13px; font-weight:700; color:var(--text); margin-bottom:8px; display:flex; align-items:center; gap:6px;">
|
|
1295
1368
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
|
|
1296
|
-
Blockers
|
|
1369
|
+
Blockers
|
|
1370
|
+
</div>
|
|
1371
|
+
<div id="blockerKanbanBoard" class="blocker-kanban-board">
|
|
1372
|
+
<div class="blocker-kanban-col" data-blocker-status="OPEN">
|
|
1373
|
+
<div class="kanban-col-head blocker-open">
|
|
1374
|
+
<span class="kanban-col-title">OPEN</span>
|
|
1375
|
+
<span class="kanban-col-count" id="countBlockerOpen">0</span>
|
|
1376
|
+
</div>
|
|
1377
|
+
<div class="blocker-kanban-col-body" id="colBlockerOpen"></div>
|
|
1378
|
+
</div>
|
|
1379
|
+
<div class="blocker-kanban-col" data-blocker-status="MITIGATING">
|
|
1380
|
+
<div class="kanban-col-head blocker-mitigating">
|
|
1381
|
+
<span class="kanban-col-title">MITIGATING</span>
|
|
1382
|
+
<span class="kanban-col-count" id="countBlockerMitigating">0</span>
|
|
1383
|
+
</div>
|
|
1384
|
+
<div class="blocker-kanban-col-body" id="colBlockerMitigating"></div>
|
|
1385
|
+
</div>
|
|
1386
|
+
<div class="blocker-kanban-col" data-blocker-status="RESOLVED">
|
|
1387
|
+
<div class="kanban-col-head blocker-resolved">
|
|
1388
|
+
<span class="kanban-col-title">RESOLVED (7d)</span>
|
|
1389
|
+
<span class="kanban-col-count" id="countBlockerResolved">0</span>
|
|
1390
|
+
</div>
|
|
1391
|
+
<div class="blocker-kanban-col-body" id="colBlockerResolved"></div>
|
|
1392
|
+
</div>
|
|
1297
1393
|
</div>
|
|
1298
|
-
<div id="kanbanBlockersList" class="kanban-blockers-list"></div>
|
|
1299
1394
|
</div>
|
|
1300
1395
|
|
|
1301
1396
|
<!-- Insights de bloqueios -->
|
|
@@ -1353,6 +1448,79 @@ function buildHtml(safeDefault, appVersion) {
|
|
|
1353
1448
|
</div>
|
|
1354
1449
|
</div>
|
|
1355
1450
|
|
|
1451
|
+
<!-- Task Edit Modal -->
|
|
1452
|
+
<div id="taskEditOverlay" class="qa-overlay" style="display:none;">
|
|
1453
|
+
<div class="qa-modal" style="width:520px;">
|
|
1454
|
+
<div class="qa-header">
|
|
1455
|
+
<span style="font-weight:700; font-size:14px;">Editar Task</span>
|
|
1456
|
+
<button class="btn small" type="button" onclick="window.closeTaskEdit()" style="padding:2px 8px;">×</button>
|
|
1457
|
+
</div>
|
|
1458
|
+
<input type="hidden" id="teTaskId" />
|
|
1459
|
+
<textarea id="teDesc" class="qa-input" placeholder="Descri\u00e7\u00e3o da task..." rows="3"></textarea>
|
|
1460
|
+
<div class="qa-row">
|
|
1461
|
+
<select id="teCat" class="qa-select">
|
|
1462
|
+
<option value="DO_NOW">DO_NOW</option>
|
|
1463
|
+
<option value="SCHEDULE">SCHEDULE</option>
|
|
1464
|
+
<option value="DELEGATE">DELEGATE</option>
|
|
1465
|
+
</select>
|
|
1466
|
+
<select id="tePriority" class="qa-select">
|
|
1467
|
+
<option value="">Prioridade</option>
|
|
1468
|
+
<option value="critical">Cr\u00edtica</option>
|
|
1469
|
+
<option value="high">Alta</option>
|
|
1470
|
+
<option value="medium">M\u00e9dia</option>
|
|
1471
|
+
<option value="low">Baixa</option>
|
|
1472
|
+
</select>
|
|
1473
|
+
</div>
|
|
1474
|
+
<div class="qa-row">
|
|
1475
|
+
<input id="teSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
|
|
1476
|
+
<div class="qa-date-wrap">
|
|
1477
|
+
<input id="teDue" type="text" class="qa-input qa-date-text" placeholder="dd/mm/aaaa" maxlength="10" />
|
|
1478
|
+
<input id="teDuePicker" type="date" class="qa-date-hidden" tabindex="-1" />
|
|
1479
|
+
<button type="button" class="qa-date-btn" onclick="var p=document.getElementById('teDuePicker'); p.showPicker ? p.showPicker() : p.click();" title="Abrir calendario">📅</button>
|
|
1480
|
+
</div>
|
|
1481
|
+
</div>
|
|
1482
|
+
<div class="qa-row">
|
|
1483
|
+
<input id="teStream" class="qa-input" placeholder="Stream / frente (opcional)" style="flex:1;" />
|
|
1484
|
+
</div>
|
|
1485
|
+
<div class="qa-row" style="justify-content:flex-end;">
|
|
1486
|
+
<button class="btn small" type="button" onclick="window.closeTaskEdit()">Cancelar</button>
|
|
1487
|
+
<button class="btn primary small" type="button" onclick="window.submitTaskEdit()">Salvar</button>
|
|
1488
|
+
</div>
|
|
1489
|
+
</div>
|
|
1490
|
+
</div>
|
|
1491
|
+
<!-- Blocker Edit Modal -->
|
|
1492
|
+
<div id="blockerEditOverlay" class="qa-overlay" style="display:none;">
|
|
1493
|
+
<div class="qa-modal" style="width:520px;">
|
|
1494
|
+
<div class="qa-header">
|
|
1495
|
+
<span style="font-weight:700; font-size:14px;">Editar Blocker</span>
|
|
1496
|
+
<button class="btn small" type="button" onclick="window.closeBlockerEdit()" style="padding:2px 8px;">×</button>
|
|
1497
|
+
</div>
|
|
1498
|
+
<input type="hidden" id="beBlockerId" />
|
|
1499
|
+
<textarea id="beTitle" class="qa-input" placeholder="T\u00edtulo do blocker..." rows="2"></textarea>
|
|
1500
|
+
<div class="qa-row">
|
|
1501
|
+
<select id="beSeverity" class="qa-select">
|
|
1502
|
+
<option value="CRITICAL">Critical</option>
|
|
1503
|
+
<option value="HIGH">High</option>
|
|
1504
|
+
<option value="MEDIUM">Medium</option>
|
|
1505
|
+
<option value="LOW">Low</option>
|
|
1506
|
+
</select>
|
|
1507
|
+
<select id="beStatus" class="qa-select">
|
|
1508
|
+
<option value="OPEN">Open</option>
|
|
1509
|
+
<option value="MITIGATING">Mitigating</option>
|
|
1510
|
+
<option value="RESOLVED">Resolved</option>
|
|
1511
|
+
</select>
|
|
1512
|
+
</div>
|
|
1513
|
+
<div class="qa-row">
|
|
1514
|
+
<input id="beSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
|
|
1515
|
+
<input id="beOwner" class="qa-input" placeholder="Respons\u00e1vel" style="flex:1;" />
|
|
1516
|
+
</div>
|
|
1517
|
+
<textarea id="beNextAction" class="qa-input" placeholder="Pr\u00f3xima a\u00e7\u00e3o..." rows="2"></textarea>
|
|
1518
|
+
<div class="qa-row" style="justify-content:flex-end;">
|
|
1519
|
+
<button class="btn small" type="button" onclick="window.closeBlockerEdit()">Cancelar</button>
|
|
1520
|
+
<button class="btn primary small" type="button" onclick="window.submitBlockerEdit()">Salvar</button>
|
|
1521
|
+
</div>
|
|
1522
|
+
</div>
|
|
1523
|
+
</div>
|
|
1356
1524
|
<script>
|
|
1357
1525
|
window.__FREYA_DEFAULT_DIR = "${safeDefault}";
|
|
1358
1526
|
</script>
|
|
@@ -1469,6 +1637,79 @@ function buildReportsHtml(safeDefault, appVersion) {
|
|
|
1469
1637
|
</div>
|
|
1470
1638
|
</div>
|
|
1471
1639
|
|
|
1640
|
+
<!-- Task Edit Modal -->
|
|
1641
|
+
<div id="taskEditOverlay" class="qa-overlay" style="display:none;">
|
|
1642
|
+
<div class="qa-modal" style="width:520px;">
|
|
1643
|
+
<div class="qa-header">
|
|
1644
|
+
<span style="font-weight:700; font-size:14px;">Editar Task</span>
|
|
1645
|
+
<button class="btn small" type="button" onclick="window.closeTaskEdit()" style="padding:2px 8px;">×</button>
|
|
1646
|
+
</div>
|
|
1647
|
+
<input type="hidden" id="teTaskId" />
|
|
1648
|
+
<textarea id="teDesc" class="qa-input" placeholder="Descri\u00e7\u00e3o da task..." rows="3"></textarea>
|
|
1649
|
+
<div class="qa-row">
|
|
1650
|
+
<select id="teCat" class="qa-select">
|
|
1651
|
+
<option value="DO_NOW">DO_NOW</option>
|
|
1652
|
+
<option value="SCHEDULE">SCHEDULE</option>
|
|
1653
|
+
<option value="DELEGATE">DELEGATE</option>
|
|
1654
|
+
</select>
|
|
1655
|
+
<select id="tePriority" class="qa-select">
|
|
1656
|
+
<option value="">Prioridade</option>
|
|
1657
|
+
<option value="critical">Cr\u00edtica</option>
|
|
1658
|
+
<option value="high">Alta</option>
|
|
1659
|
+
<option value="medium">M\u00e9dia</option>
|
|
1660
|
+
<option value="low">Baixa</option>
|
|
1661
|
+
</select>
|
|
1662
|
+
</div>
|
|
1663
|
+
<div class="qa-row">
|
|
1664
|
+
<input id="teSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
|
|
1665
|
+
<div class="qa-date-wrap">
|
|
1666
|
+
<input id="teDue" type="text" class="qa-input qa-date-text" placeholder="dd/mm/aaaa" maxlength="10" />
|
|
1667
|
+
<input id="teDuePicker" type="date" class="qa-date-hidden" tabindex="-1" />
|
|
1668
|
+
<button type="button" class="qa-date-btn" onclick="var p=document.getElementById('teDuePicker'); p.showPicker ? p.showPicker() : p.click();" title="Abrir calendario">📅</button>
|
|
1669
|
+
</div>
|
|
1670
|
+
</div>
|
|
1671
|
+
<div class="qa-row">
|
|
1672
|
+
<input id="teStream" class="qa-input" placeholder="Stream / frente (opcional)" style="flex:1;" />
|
|
1673
|
+
</div>
|
|
1674
|
+
<div class="qa-row" style="justify-content:flex-end;">
|
|
1675
|
+
<button class="btn small" type="button" onclick="window.closeTaskEdit()">Cancelar</button>
|
|
1676
|
+
<button class="btn primary small" type="button" onclick="window.submitTaskEdit()">Salvar</button>
|
|
1677
|
+
</div>
|
|
1678
|
+
</div>
|
|
1679
|
+
</div>
|
|
1680
|
+
<!-- Blocker Edit Modal -->
|
|
1681
|
+
<div id="blockerEditOverlay" class="qa-overlay" style="display:none;">
|
|
1682
|
+
<div class="qa-modal" style="width:520px;">
|
|
1683
|
+
<div class="qa-header">
|
|
1684
|
+
<span style="font-weight:700; font-size:14px;">Editar Blocker</span>
|
|
1685
|
+
<button class="btn small" type="button" onclick="window.closeBlockerEdit()" style="padding:2px 8px;">×</button>
|
|
1686
|
+
</div>
|
|
1687
|
+
<input type="hidden" id="beBlockerId" />
|
|
1688
|
+
<textarea id="beTitle" class="qa-input" placeholder="T\u00edtulo do blocker..." rows="2"></textarea>
|
|
1689
|
+
<div class="qa-row">
|
|
1690
|
+
<select id="beSeverity" class="qa-select">
|
|
1691
|
+
<option value="CRITICAL">Critical</option>
|
|
1692
|
+
<option value="HIGH">High</option>
|
|
1693
|
+
<option value="MEDIUM">Medium</option>
|
|
1694
|
+
<option value="LOW">Low</option>
|
|
1695
|
+
</select>
|
|
1696
|
+
<select id="beStatus" class="qa-select">
|
|
1697
|
+
<option value="OPEN">Open</option>
|
|
1698
|
+
<option value="MITIGATING">Mitigating</option>
|
|
1699
|
+
<option value="RESOLVED">Resolved</option>
|
|
1700
|
+
</select>
|
|
1701
|
+
</div>
|
|
1702
|
+
<div class="qa-row">
|
|
1703
|
+
<input id="beSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
|
|
1704
|
+
<input id="beOwner" class="qa-input" placeholder="Respons\u00e1vel" style="flex:1;" />
|
|
1705
|
+
</div>
|
|
1706
|
+
<textarea id="beNextAction" class="qa-input" placeholder="Pr\u00f3xima a\u00e7\u00e3o..." rows="2"></textarea>
|
|
1707
|
+
<div class="qa-row" style="justify-content:flex-end;">
|
|
1708
|
+
<button class="btn small" type="button" onclick="window.closeBlockerEdit()">Cancelar</button>
|
|
1709
|
+
<button class="btn primary small" type="button" onclick="window.submitBlockerEdit()">Salvar</button>
|
|
1710
|
+
</div>
|
|
1711
|
+
</div>
|
|
1712
|
+
</div>
|
|
1472
1713
|
<script>
|
|
1473
1714
|
window.__FREYA_DEFAULT_DIR = "${safeDefault}";
|
|
1474
1715
|
</script>
|
|
@@ -1565,6 +1806,79 @@ function buildProjectsHtml(safeDefault, appVersion) {
|
|
|
1565
1806
|
</div>
|
|
1566
1807
|
</div>
|
|
1567
1808
|
|
|
1809
|
+
<!-- Task Edit Modal -->
|
|
1810
|
+
<div id="taskEditOverlay" class="qa-overlay" style="display:none;">
|
|
1811
|
+
<div class="qa-modal" style="width:520px;">
|
|
1812
|
+
<div class="qa-header">
|
|
1813
|
+
<span style="font-weight:700; font-size:14px;">Editar Task</span>
|
|
1814
|
+
<button class="btn small" type="button" onclick="window.closeTaskEdit()" style="padding:2px 8px;">×</button>
|
|
1815
|
+
</div>
|
|
1816
|
+
<input type="hidden" id="teTaskId" />
|
|
1817
|
+
<textarea id="teDesc" class="qa-input" placeholder="Descri\u00e7\u00e3o da task..." rows="3"></textarea>
|
|
1818
|
+
<div class="qa-row">
|
|
1819
|
+
<select id="teCat" class="qa-select">
|
|
1820
|
+
<option value="DO_NOW">DO_NOW</option>
|
|
1821
|
+
<option value="SCHEDULE">SCHEDULE</option>
|
|
1822
|
+
<option value="DELEGATE">DELEGATE</option>
|
|
1823
|
+
</select>
|
|
1824
|
+
<select id="tePriority" class="qa-select">
|
|
1825
|
+
<option value="">Prioridade</option>
|
|
1826
|
+
<option value="critical">Cr\u00edtica</option>
|
|
1827
|
+
<option value="high">Alta</option>
|
|
1828
|
+
<option value="medium">M\u00e9dia</option>
|
|
1829
|
+
<option value="low">Baixa</option>
|
|
1830
|
+
</select>
|
|
1831
|
+
</div>
|
|
1832
|
+
<div class="qa-row">
|
|
1833
|
+
<input id="teSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
|
|
1834
|
+
<div class="qa-date-wrap">
|
|
1835
|
+
<input id="teDue" type="text" class="qa-input qa-date-text" placeholder="dd/mm/aaaa" maxlength="10" />
|
|
1836
|
+
<input id="teDuePicker" type="date" class="qa-date-hidden" tabindex="-1" />
|
|
1837
|
+
<button type="button" class="qa-date-btn" onclick="var p=document.getElementById('teDuePicker'); p.showPicker ? p.showPicker() : p.click();" title="Abrir calendario">📅</button>
|
|
1838
|
+
</div>
|
|
1839
|
+
</div>
|
|
1840
|
+
<div class="qa-row">
|
|
1841
|
+
<input id="teStream" class="qa-input" placeholder="Stream / frente (opcional)" style="flex:1;" />
|
|
1842
|
+
</div>
|
|
1843
|
+
<div class="qa-row" style="justify-content:flex-end;">
|
|
1844
|
+
<button class="btn small" type="button" onclick="window.closeTaskEdit()">Cancelar</button>
|
|
1845
|
+
<button class="btn primary small" type="button" onclick="window.submitTaskEdit()">Salvar</button>
|
|
1846
|
+
</div>
|
|
1847
|
+
</div>
|
|
1848
|
+
</div>
|
|
1849
|
+
<!-- Blocker Edit Modal -->
|
|
1850
|
+
<div id="blockerEditOverlay" class="qa-overlay" style="display:none;">
|
|
1851
|
+
<div class="qa-modal" style="width:520px;">
|
|
1852
|
+
<div class="qa-header">
|
|
1853
|
+
<span style="font-weight:700; font-size:14px;">Editar Blocker</span>
|
|
1854
|
+
<button class="btn small" type="button" onclick="window.closeBlockerEdit()" style="padding:2px 8px;">×</button>
|
|
1855
|
+
</div>
|
|
1856
|
+
<input type="hidden" id="beBlockerId" />
|
|
1857
|
+
<textarea id="beTitle" class="qa-input" placeholder="T\u00edtulo do blocker..." rows="2"></textarea>
|
|
1858
|
+
<div class="qa-row">
|
|
1859
|
+
<select id="beSeverity" class="qa-select">
|
|
1860
|
+
<option value="CRITICAL">Critical</option>
|
|
1861
|
+
<option value="HIGH">High</option>
|
|
1862
|
+
<option value="MEDIUM">Medium</option>
|
|
1863
|
+
<option value="LOW">Low</option>
|
|
1864
|
+
</select>
|
|
1865
|
+
<select id="beStatus" class="qa-select">
|
|
1866
|
+
<option value="OPEN">Open</option>
|
|
1867
|
+
<option value="MITIGATING">Mitigating</option>
|
|
1868
|
+
<option value="RESOLVED">Resolved</option>
|
|
1869
|
+
</select>
|
|
1870
|
+
</div>
|
|
1871
|
+
<div class="qa-row">
|
|
1872
|
+
<input id="beSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
|
|
1873
|
+
<input id="beOwner" class="qa-input" placeholder="Respons\u00e1vel" style="flex:1;" />
|
|
1874
|
+
</div>
|
|
1875
|
+
<textarea id="beNextAction" class="qa-input" placeholder="Pr\u00f3xima a\u00e7\u00e3o..." rows="2"></textarea>
|
|
1876
|
+
<div class="qa-row" style="justify-content:flex-end;">
|
|
1877
|
+
<button class="btn small" type="button" onclick="window.closeBlockerEdit()">Cancelar</button>
|
|
1878
|
+
<button class="btn primary small" type="button" onclick="window.submitBlockerEdit()">Salvar</button>
|
|
1879
|
+
</div>
|
|
1880
|
+
</div>
|
|
1881
|
+
</div>
|
|
1568
1882
|
<script>
|
|
1569
1883
|
window.__FREYA_DEFAULT_DIR = "${safeDefault}";
|
|
1570
1884
|
</script>
|
|
@@ -1771,6 +2085,79 @@ function buildGraphHtml(safeDefault, appVersion) {
|
|
|
1771
2085
|
</div>
|
|
1772
2086
|
</div>
|
|
1773
2087
|
|
|
2088
|
+
<!-- Task Edit Modal -->
|
|
2089
|
+
<div id="taskEditOverlay" class="qa-overlay" style="display:none;">
|
|
2090
|
+
<div class="qa-modal" style="width:520px;">
|
|
2091
|
+
<div class="qa-header">
|
|
2092
|
+
<span style="font-weight:700; font-size:14px;">Editar Task</span>
|
|
2093
|
+
<button class="btn small" type="button" onclick="window.closeTaskEdit()" style="padding:2px 8px;">×</button>
|
|
2094
|
+
</div>
|
|
2095
|
+
<input type="hidden" id="teTaskId" />
|
|
2096
|
+
<textarea id="teDesc" class="qa-input" placeholder="Descri\u00e7\u00e3o da task..." rows="3"></textarea>
|
|
2097
|
+
<div class="qa-row">
|
|
2098
|
+
<select id="teCat" class="qa-select">
|
|
2099
|
+
<option value="DO_NOW">DO_NOW</option>
|
|
2100
|
+
<option value="SCHEDULE">SCHEDULE</option>
|
|
2101
|
+
<option value="DELEGATE">DELEGATE</option>
|
|
2102
|
+
</select>
|
|
2103
|
+
<select id="tePriority" class="qa-select">
|
|
2104
|
+
<option value="">Prioridade</option>
|
|
2105
|
+
<option value="critical">Cr\u00edtica</option>
|
|
2106
|
+
<option value="high">Alta</option>
|
|
2107
|
+
<option value="medium">M\u00e9dia</option>
|
|
2108
|
+
<option value="low">Baixa</option>
|
|
2109
|
+
</select>
|
|
2110
|
+
</div>
|
|
2111
|
+
<div class="qa-row">
|
|
2112
|
+
<input id="teSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
|
|
2113
|
+
<div class="qa-date-wrap">
|
|
2114
|
+
<input id="teDue" type="text" class="qa-input qa-date-text" placeholder="dd/mm/aaaa" maxlength="10" />
|
|
2115
|
+
<input id="teDuePicker" type="date" class="qa-date-hidden" tabindex="-1" />
|
|
2116
|
+
<button type="button" class="qa-date-btn" onclick="var p=document.getElementById('teDuePicker'); p.showPicker ? p.showPicker() : p.click();" title="Abrir calendario">📅</button>
|
|
2117
|
+
</div>
|
|
2118
|
+
</div>
|
|
2119
|
+
<div class="qa-row">
|
|
2120
|
+
<input id="teStream" class="qa-input" placeholder="Stream / frente (opcional)" style="flex:1;" />
|
|
2121
|
+
</div>
|
|
2122
|
+
<div class="qa-row" style="justify-content:flex-end;">
|
|
2123
|
+
<button class="btn small" type="button" onclick="window.closeTaskEdit()">Cancelar</button>
|
|
2124
|
+
<button class="btn primary small" type="button" onclick="window.submitTaskEdit()">Salvar</button>
|
|
2125
|
+
</div>
|
|
2126
|
+
</div>
|
|
2127
|
+
</div>
|
|
2128
|
+
<!-- Blocker Edit Modal -->
|
|
2129
|
+
<div id="blockerEditOverlay" class="qa-overlay" style="display:none;">
|
|
2130
|
+
<div class="qa-modal" style="width:520px;">
|
|
2131
|
+
<div class="qa-header">
|
|
2132
|
+
<span style="font-weight:700; font-size:14px;">Editar Blocker</span>
|
|
2133
|
+
<button class="btn small" type="button" onclick="window.closeBlockerEdit()" style="padding:2px 8px;">×</button>
|
|
2134
|
+
</div>
|
|
2135
|
+
<input type="hidden" id="beBlockerId" />
|
|
2136
|
+
<textarea id="beTitle" class="qa-input" placeholder="T\u00edtulo do blocker..." rows="2"></textarea>
|
|
2137
|
+
<div class="qa-row">
|
|
2138
|
+
<select id="beSeverity" class="qa-select">
|
|
2139
|
+
<option value="CRITICAL">Critical</option>
|
|
2140
|
+
<option value="HIGH">High</option>
|
|
2141
|
+
<option value="MEDIUM">Medium</option>
|
|
2142
|
+
<option value="LOW">Low</option>
|
|
2143
|
+
</select>
|
|
2144
|
+
<select id="beStatus" class="qa-select">
|
|
2145
|
+
<option value="OPEN">Open</option>
|
|
2146
|
+
<option value="MITIGATING">Mitigating</option>
|
|
2147
|
+
<option value="RESOLVED">Resolved</option>
|
|
2148
|
+
</select>
|
|
2149
|
+
</div>
|
|
2150
|
+
<div class="qa-row">
|
|
2151
|
+
<input id="beSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
|
|
2152
|
+
<input id="beOwner" class="qa-input" placeholder="Respons\u00e1vel" style="flex:1;" />
|
|
2153
|
+
</div>
|
|
2154
|
+
<textarea id="beNextAction" class="qa-input" placeholder="Pr\u00f3xima a\u00e7\u00e3o..." rows="2"></textarea>
|
|
2155
|
+
<div class="qa-row" style="justify-content:flex-end;">
|
|
2156
|
+
<button class="btn small" type="button" onclick="window.closeBlockerEdit()">Cancelar</button>
|
|
2157
|
+
<button class="btn primary small" type="button" onclick="window.submitBlockerEdit()">Salvar</button>
|
|
2158
|
+
</div>
|
|
2159
|
+
</div>
|
|
2160
|
+
</div>
|
|
1774
2161
|
<script>
|
|
1775
2162
|
window.__FREYA_DEFAULT_DIR = "${safeDefault}";
|
|
1776
2163
|
</script>
|
|
@@ -1907,6 +2294,79 @@ function buildCompanionHtml(safeDefault, appVersion) {
|
|
|
1907
2294
|
</div>
|
|
1908
2295
|
</div>
|
|
1909
2296
|
|
|
2297
|
+
<!-- Task Edit Modal -->
|
|
2298
|
+
<div id="taskEditOverlay" class="qa-overlay" style="display:none;">
|
|
2299
|
+
<div class="qa-modal" style="width:520px;">
|
|
2300
|
+
<div class="qa-header">
|
|
2301
|
+
<span style="font-weight:700; font-size:14px;">Editar Task</span>
|
|
2302
|
+
<button class="btn small" type="button" onclick="window.closeTaskEdit()" style="padding:2px 8px;">×</button>
|
|
2303
|
+
</div>
|
|
2304
|
+
<input type="hidden" id="teTaskId" />
|
|
2305
|
+
<textarea id="teDesc" class="qa-input" placeholder="Descri\u00e7\u00e3o da task..." rows="3"></textarea>
|
|
2306
|
+
<div class="qa-row">
|
|
2307
|
+
<select id="teCat" class="qa-select">
|
|
2308
|
+
<option value="DO_NOW">DO_NOW</option>
|
|
2309
|
+
<option value="SCHEDULE">SCHEDULE</option>
|
|
2310
|
+
<option value="DELEGATE">DELEGATE</option>
|
|
2311
|
+
</select>
|
|
2312
|
+
<select id="tePriority" class="qa-select">
|
|
2313
|
+
<option value="">Prioridade</option>
|
|
2314
|
+
<option value="critical">Cr\u00edtica</option>
|
|
2315
|
+
<option value="high">Alta</option>
|
|
2316
|
+
<option value="medium">M\u00e9dia</option>
|
|
2317
|
+
<option value="low">Baixa</option>
|
|
2318
|
+
</select>
|
|
2319
|
+
</div>
|
|
2320
|
+
<div class="qa-row">
|
|
2321
|
+
<input id="teSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
|
|
2322
|
+
<div class="qa-date-wrap">
|
|
2323
|
+
<input id="teDue" type="text" class="qa-input qa-date-text" placeholder="dd/mm/aaaa" maxlength="10" />
|
|
2324
|
+
<input id="teDuePicker" type="date" class="qa-date-hidden" tabindex="-1" />
|
|
2325
|
+
<button type="button" class="qa-date-btn" onclick="var p=document.getElementById('teDuePicker'); p.showPicker ? p.showPicker() : p.click();" title="Abrir calendario">📅</button>
|
|
2326
|
+
</div>
|
|
2327
|
+
</div>
|
|
2328
|
+
<div class="qa-row">
|
|
2329
|
+
<input id="teStream" class="qa-input" placeholder="Stream / frente (opcional)" style="flex:1;" />
|
|
2330
|
+
</div>
|
|
2331
|
+
<div class="qa-row" style="justify-content:flex-end;">
|
|
2332
|
+
<button class="btn small" type="button" onclick="window.closeTaskEdit()">Cancelar</button>
|
|
2333
|
+
<button class="btn primary small" type="button" onclick="window.submitTaskEdit()">Salvar</button>
|
|
2334
|
+
</div>
|
|
2335
|
+
</div>
|
|
2336
|
+
</div>
|
|
2337
|
+
<!-- Blocker Edit Modal -->
|
|
2338
|
+
<div id="blockerEditOverlay" class="qa-overlay" style="display:none;">
|
|
2339
|
+
<div class="qa-modal" style="width:520px;">
|
|
2340
|
+
<div class="qa-header">
|
|
2341
|
+
<span style="font-weight:700; font-size:14px;">Editar Blocker</span>
|
|
2342
|
+
<button class="btn small" type="button" onclick="window.closeBlockerEdit()" style="padding:2px 8px;">×</button>
|
|
2343
|
+
</div>
|
|
2344
|
+
<input type="hidden" id="beBlockerId" />
|
|
2345
|
+
<textarea id="beTitle" class="qa-input" placeholder="T\u00edtulo do blocker..." rows="2"></textarea>
|
|
2346
|
+
<div class="qa-row">
|
|
2347
|
+
<select id="beSeverity" class="qa-select">
|
|
2348
|
+
<option value="CRITICAL">Critical</option>
|
|
2349
|
+
<option value="HIGH">High</option>
|
|
2350
|
+
<option value="MEDIUM">Medium</option>
|
|
2351
|
+
<option value="LOW">Low</option>
|
|
2352
|
+
</select>
|
|
2353
|
+
<select id="beStatus" class="qa-select">
|
|
2354
|
+
<option value="OPEN">Open</option>
|
|
2355
|
+
<option value="MITIGATING">Mitigating</option>
|
|
2356
|
+
<option value="RESOLVED">Resolved</option>
|
|
2357
|
+
</select>
|
|
2358
|
+
</div>
|
|
2359
|
+
<div class="qa-row">
|
|
2360
|
+
<input id="beSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
|
|
2361
|
+
<input id="beOwner" class="qa-input" placeholder="Respons\u00e1vel" style="flex:1;" />
|
|
2362
|
+
</div>
|
|
2363
|
+
<textarea id="beNextAction" class="qa-input" placeholder="Pr\u00f3xima a\u00e7\u00e3o..." rows="2"></textarea>
|
|
2364
|
+
<div class="qa-row" style="justify-content:flex-end;">
|
|
2365
|
+
<button class="btn small" type="button" onclick="window.closeBlockerEdit()">Cancelar</button>
|
|
2366
|
+
<button class="btn primary small" type="button" onclick="window.submitBlockerEdit()">Salvar</button>
|
|
2367
|
+
</div>
|
|
2368
|
+
</div>
|
|
2369
|
+
</div>
|
|
1910
2370
|
<script>
|
|
1911
2371
|
window.__FREYA_DEFAULT_DIR = "${safeDefault}";
|
|
1912
2372
|
</script>
|
|
@@ -3322,20 +3782,21 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
3322
3782
|
]
|
|
3323
3783
|
};
|
|
3324
3784
|
|
|
3325
|
-
|
|
3785
|
+
// Build the system instructions (small, always fits in -p)
|
|
3786
|
+
const sysInstructions = `Você é o planner do sistema F.R.E.Y.A.\n\nContexto: vamos receber um input bruto do usuário e propor ações estruturadas.\nRegras: siga os arquivos de regras abaixo.\nSaída: retorne APENAS JSON válido no formato: ${JSON.stringify(schema)}\n\nRestrições:\n- NÃO use code fences (\`\`\`)\n- NÃO inclua texto extra antes/depois do JSON\n- NÃO use quebras de linha dentro de strings (transforme em uma frase única)${planImageContext}`;
|
|
3326
3787
|
|
|
3327
3788
|
// Prefer COPILOT_CMD if provided, otherwise try 'copilot'
|
|
3328
3789
|
const cmd = process.env.COPILOT_CMD || 'copilot';
|
|
3329
3790
|
|
|
3330
|
-
// Best-effort: if Copilot CLI isn't available, return 200 with an explanatory plan
|
|
3331
|
-
// so the UI can show actionable next steps instead of hard-failing.
|
|
3332
3791
|
// BUG-48: pass FREYA_WORKSPACE_DIR so the Copilot subprocess uses correct DB
|
|
3333
3792
|
const agentEnv = { FREYA_WORKSPACE_DIR: workspaceDir };
|
|
3334
3793
|
|
|
3335
|
-
// ENAMETOOLONG fix: when
|
|
3336
|
-
//
|
|
3337
|
-
|
|
3338
|
-
const
|
|
3794
|
+
// ENAMETOOLONG fix: when user text is large, write it to a temp file
|
|
3795
|
+
// and reference it in the prompt. System instructions stay in -p (small).
|
|
3796
|
+
// The user text is the large part; rules are moderate (~10KB).
|
|
3797
|
+
const fullPrompt = `${sysInstructions}\n\nREGRAS:${rulesText}\n\nINPUT DO USUÁRIO:\n${text}\n`;
|
|
3798
|
+
const SAFE_ARG_LEN = 24000; // ~24KB safe for Windows CreateProcess
|
|
3799
|
+
const needsFile = fullPrompt.length > SAFE_ARG_LEN;
|
|
3339
3800
|
let tmpFile = null;
|
|
3340
3801
|
|
|
3341
3802
|
try {
|
|
@@ -3343,13 +3804,27 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
3343
3804
|
const baseArgs = ['-s', '--no-color', '--stream', 'off'];
|
|
3344
3805
|
if (planImageDir) baseArgs.push('--add-dir', planImageDir);
|
|
3345
3806
|
|
|
3346
|
-
if (
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3807
|
+
if (needsFile) {
|
|
3808
|
+
// Write ONLY the user text to a temp file; keep instructions in -p
|
|
3809
|
+
tmpFile = path.join(os.tmpdir(), `freya-input-${Date.now()}.txt`);
|
|
3810
|
+
fs.writeFileSync(tmpFile, text, 'utf8');
|
|
3811
|
+
// -p contains: system instructions + rules + reference to the file
|
|
3812
|
+
const filePrompt = `${sysInstructions}\n\nREGRAS:${rulesText}\n\nINPUT DO USUÁRIO:\nO texto do usuário é MUITO GRANDE e foi salvo no arquivo abaixo. Você DEVE ler o conteúdo completo deste arquivo usando suas ferramentas de leitura de arquivo e processar TODO o conteúdo como input do usuário.\nARQUIVO: ${tmpFile}\n\nIMPORTANTE: NÃO descreva o arquivo. LEIA o conteúdo e processe-o gerando as ações JSON conforme as regras acima.\n`;
|
|
3813
|
+
// If even the filePrompt (instructions + rules + file ref) is too large,
|
|
3814
|
+
// also write rules to a separate file
|
|
3815
|
+
if (filePrompt.length > SAFE_ARG_LEN) {
|
|
3816
|
+
const rulesTmpFile = path.join(os.tmpdir(), `freya-rules-${Date.now()}.txt`);
|
|
3817
|
+
fs.writeFileSync(rulesTmpFile, rulesText, 'utf8');
|
|
3818
|
+
const minPrompt = `${sysInstructions}\n\nREGRAS: Leia as regras do arquivo: ${rulesTmpFile}\n\nINPUT DO USUÁRIO:\nO texto do usuário é MUITO GRANDE e foi salvo no arquivo abaixo. Você DEVE ler o conteúdo completo deste arquivo e processar TODO o conteúdo como input do usuário.\nARQUIVO: ${tmpFile}\n\nIMPORTANTE: NÃO descreva os arquivos. LEIA os conteúdos e processe-os gerando as ações JSON conforme as regras.\n`;
|
|
3819
|
+
baseArgs.push('--add-dir', os.tmpdir());
|
|
3820
|
+
r = await run(cmd, [...baseArgs, '-p', minPrompt, '--allow-all-tools'], workspaceDir, agentEnv);
|
|
3821
|
+
try { fs.unlinkSync(rulesTmpFile); } catch (_) { /* ignore */ }
|
|
3822
|
+
} else {
|
|
3823
|
+
baseArgs.push('--add-dir', os.tmpdir());
|
|
3824
|
+
r = await run(cmd, [...baseArgs, '-p', filePrompt, '--allow-all-tools'], workspaceDir, agentEnv);
|
|
3825
|
+
}
|
|
3351
3826
|
} else {
|
|
3352
|
-
r = await run(cmd, [...baseArgs, '-p',
|
|
3827
|
+
r = await run(cmd, [...baseArgs, '-p', fullPrompt, '--allow-all-tools'], workspaceDir, agentEnv);
|
|
3353
3828
|
}
|
|
3354
3829
|
const out = (r.stdout + r.stderr).trim();
|
|
3355
3830
|
if (r.code !== 0) {
|
|
@@ -3820,7 +4295,8 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
3820
4295
|
}
|
|
3821
4296
|
}
|
|
3822
4297
|
|
|
3823
|
-
|
|
4298
|
+
// System instructions (small, always fits in -p)
|
|
4299
|
+
const oracleSysInstr = `Você é o agente Oracle do sistema F.R.E.Y.A.\n\nSiga estritamente os arquivos de regras abaixo.\nResponda de forma analítica e consultiva.\n${ragContext}${imageContext}`;
|
|
3824
4300
|
|
|
3825
4301
|
const cmd = process.env.COPILOT_CMD || 'copilot';
|
|
3826
4302
|
|
|
@@ -3835,21 +4311,21 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
3835
4311
|
copilotArgs.push('--add-dir', path.dirname(absImg));
|
|
3836
4312
|
}
|
|
3837
4313
|
}
|
|
3838
|
-
copilotArgs.push('--allow-all-tools', '-p', prompt);
|
|
3839
4314
|
|
|
3840
|
-
// ENAMETOOLONG fix:
|
|
4315
|
+
// ENAMETOOLONG fix: when prompt is large, write user query to temp file
|
|
4316
|
+
const fullOraclePrompt = `${oracleSysInstr}\n\nREGRAS:${rulesText}\n\nCONSULTA DO USUÁRIO:\n${query}\n`;
|
|
3841
4317
|
const SAFE_ARG_LEN = 24000;
|
|
3842
4318
|
let oracleTmpFile = null;
|
|
3843
4319
|
let r;
|
|
3844
|
-
if (
|
|
3845
|
-
oracleTmpFile = path.join(os.tmpdir(), `freya-oracle-${Date.now()}.txt`);
|
|
3846
|
-
fs.writeFileSync(oracleTmpFile,
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
r = await run(cmd, copilotArgs, workspaceDir, oracleEnv, prompt);
|
|
4320
|
+
if (fullOraclePrompt.length > SAFE_ARG_LEN) {
|
|
4321
|
+
oracleTmpFile = path.join(os.tmpdir(), `freya-oracle-input-${Date.now()}.txt`);
|
|
4322
|
+
fs.writeFileSync(oracleTmpFile, query, 'utf8');
|
|
4323
|
+
const filePrompt = `${oracleSysInstr}\n\nREGRAS:${rulesText}\n\nCONSULTA DO USUÁRIO:\nA consulta do usuário é grande e foi salva no arquivo abaixo. LEIA o conteúdo completo do arquivo e responda com base nele.\nARQUIVO: ${oracleTmpFile}\n\nIMPORTANTE: NÃO descreva o arquivo. LEIA e RESPONDA à consulta.\n`;
|
|
4324
|
+
copilotArgs.push('--add-dir', os.tmpdir());
|
|
4325
|
+
copilotArgs.push('--allow-all-tools', '-p', filePrompt);
|
|
4326
|
+
r = await run(cmd, copilotArgs, workspaceDir, oracleEnv);
|
|
3852
4327
|
} else {
|
|
4328
|
+
copilotArgs.push('--allow-all-tools', '-p', fullOraclePrompt);
|
|
3853
4329
|
r = await run(cmd, copilotArgs, workspaceDir, oracleEnv);
|
|
3854
4330
|
}
|
|
3855
4331
|
if (oracleTmpFile) { try { fs.unlinkSync(oracleTmpFile); } catch (_) { /* ignore */ } }
|
|
@@ -4064,11 +4540,14 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
4064
4540
|
queryUpdates.push('description = ?');
|
|
4065
4541
|
params.push(patch.description.trim());
|
|
4066
4542
|
}
|
|
4067
|
-
|
|
4543
|
+
// Handle all metadata fields in one read-modify-write
|
|
4544
|
+
const hasMetaPatch = typeof patch.priority === 'string' || typeof patch.streamSlug === 'string';
|
|
4545
|
+
if (hasMetaPatch) {
|
|
4068
4546
|
const row = dl.db.prepare('SELECT metadata FROM tasks WHERE id = ?').get(id);
|
|
4069
4547
|
let meta = {};
|
|
4070
4548
|
try { meta = row && row.metadata ? JSON.parse(row.metadata) : {}; } catch { meta = {}; }
|
|
4071
|
-
meta.priority = patch.priority.trim().toLowerCase();
|
|
4549
|
+
if (typeof patch.priority === 'string') meta.priority = patch.priority.trim().toLowerCase() || undefined;
|
|
4550
|
+
if (typeof patch.streamSlug === 'string') meta.streamSlug = patch.streamSlug.trim() || undefined;
|
|
4072
4551
|
queryUpdates.push('metadata = ?');
|
|
4073
4552
|
params.push(JSON.stringify(meta));
|
|
4074
4553
|
}
|
|
@@ -4327,12 +4806,15 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
4327
4806
|
};
|
|
4328
4807
|
});
|
|
4329
4808
|
|
|
4809
|
+
const sevenDaysAgo = new Date(Date.now() - 7 * 86400000).toISOString();
|
|
4330
4810
|
const openBlockers = dl.db.prepare(`
|
|
4331
4811
|
SELECT * FROM blockers WHERE status IN ('OPEN', 'MITIGATING')
|
|
4812
|
+
OR (status = 'RESOLVED' AND resolved_at >= ?)
|
|
4332
4813
|
ORDER BY
|
|
4814
|
+
CASE status WHEN 'OPEN' THEN 0 WHEN 'MITIGATING' THEN 1 WHEN 'RESOLVED' THEN 2 ELSE 9 END ASC,
|
|
4333
4815
|
CASE severity WHEN 'CRITICAL' THEN 0 WHEN 'HIGH' THEN 1 WHEN 'MEDIUM' THEN 2 WHEN 'LOW' THEN 3 ELSE 9 END ASC,
|
|
4334
4816
|
created_at ASC
|
|
4335
|
-
`).all().map(b => {
|
|
4817
|
+
`).all(sevenDaysAgo).map(b => {
|
|
4336
4818
|
let meta = {};
|
|
4337
4819
|
try { meta = b.metadata ? JSON.parse(b.metadata) : {}; } catch { meta = {}; }
|
|
4338
4820
|
return {
|
|
@@ -4589,6 +5071,79 @@ function buildSettingsHtml(safeDefault, appVersion) {
|
|
|
4589
5071
|
</div>
|
|
4590
5072
|
</div>
|
|
4591
5073
|
|
|
5074
|
+
<!-- Task Edit Modal -->
|
|
5075
|
+
<div id="taskEditOverlay" class="qa-overlay" style="display:none;">
|
|
5076
|
+
<div class="qa-modal" style="width:520px;">
|
|
5077
|
+
<div class="qa-header">
|
|
5078
|
+
<span style="font-weight:700; font-size:14px;">Editar Task</span>
|
|
5079
|
+
<button class="btn small" type="button" onclick="window.closeTaskEdit()" style="padding:2px 8px;">×</button>
|
|
5080
|
+
</div>
|
|
5081
|
+
<input type="hidden" id="teTaskId" />
|
|
5082
|
+
<textarea id="teDesc" class="qa-input" placeholder="Descri\u00e7\u00e3o da task..." rows="3"></textarea>
|
|
5083
|
+
<div class="qa-row">
|
|
5084
|
+
<select id="teCat" class="qa-select">
|
|
5085
|
+
<option value="DO_NOW">DO_NOW</option>
|
|
5086
|
+
<option value="SCHEDULE">SCHEDULE</option>
|
|
5087
|
+
<option value="DELEGATE">DELEGATE</option>
|
|
5088
|
+
</select>
|
|
5089
|
+
<select id="tePriority" class="qa-select">
|
|
5090
|
+
<option value="">Prioridade</option>
|
|
5091
|
+
<option value="critical">Cr\u00edtica</option>
|
|
5092
|
+
<option value="high">Alta</option>
|
|
5093
|
+
<option value="medium">M\u00e9dia</option>
|
|
5094
|
+
<option value="low">Baixa</option>
|
|
5095
|
+
</select>
|
|
5096
|
+
</div>
|
|
5097
|
+
<div class="qa-row">
|
|
5098
|
+
<input id="teSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
|
|
5099
|
+
<div class="qa-date-wrap">
|
|
5100
|
+
<input id="teDue" type="text" class="qa-input qa-date-text" placeholder="dd/mm/aaaa" maxlength="10" />
|
|
5101
|
+
<input id="teDuePicker" type="date" class="qa-date-hidden" tabindex="-1" />
|
|
5102
|
+
<button type="button" class="qa-date-btn" onclick="var p=document.getElementById('teDuePicker'); p.showPicker ? p.showPicker() : p.click();" title="Abrir calendario">📅</button>
|
|
5103
|
+
</div>
|
|
5104
|
+
</div>
|
|
5105
|
+
<div class="qa-row">
|
|
5106
|
+
<input id="teStream" class="qa-input" placeholder="Stream / frente (opcional)" style="flex:1;" />
|
|
5107
|
+
</div>
|
|
5108
|
+
<div class="qa-row" style="justify-content:flex-end;">
|
|
5109
|
+
<button class="btn small" type="button" onclick="window.closeTaskEdit()">Cancelar</button>
|
|
5110
|
+
<button class="btn primary small" type="button" onclick="window.submitTaskEdit()">Salvar</button>
|
|
5111
|
+
</div>
|
|
5112
|
+
</div>
|
|
5113
|
+
</div>
|
|
5114
|
+
<!-- Blocker Edit Modal -->
|
|
5115
|
+
<div id="blockerEditOverlay" class="qa-overlay" style="display:none;">
|
|
5116
|
+
<div class="qa-modal" style="width:520px;">
|
|
5117
|
+
<div class="qa-header">
|
|
5118
|
+
<span style="font-weight:700; font-size:14px;">Editar Blocker</span>
|
|
5119
|
+
<button class="btn small" type="button" onclick="window.closeBlockerEdit()" style="padding:2px 8px;">×</button>
|
|
5120
|
+
</div>
|
|
5121
|
+
<input type="hidden" id="beBlockerId" />
|
|
5122
|
+
<textarea id="beTitle" class="qa-input" placeholder="T\u00edtulo do blocker..." rows="2"></textarea>
|
|
5123
|
+
<div class="qa-row">
|
|
5124
|
+
<select id="beSeverity" class="qa-select">
|
|
5125
|
+
<option value="CRITICAL">Critical</option>
|
|
5126
|
+
<option value="HIGH">High</option>
|
|
5127
|
+
<option value="MEDIUM">Medium</option>
|
|
5128
|
+
<option value="LOW">Low</option>
|
|
5129
|
+
</select>
|
|
5130
|
+
<select id="beStatus" class="qa-select">
|
|
5131
|
+
<option value="OPEN">Open</option>
|
|
5132
|
+
<option value="MITIGATING">Mitigating</option>
|
|
5133
|
+
<option value="RESOLVED">Resolved</option>
|
|
5134
|
+
</select>
|
|
5135
|
+
</div>
|
|
5136
|
+
<div class="qa-row">
|
|
5137
|
+
<input id="beSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
|
|
5138
|
+
<input id="beOwner" class="qa-input" placeholder="Respons\u00e1vel" style="flex:1;" />
|
|
5139
|
+
</div>
|
|
5140
|
+
<textarea id="beNextAction" class="qa-input" placeholder="Pr\u00f3xima a\u00e7\u00e3o..." rows="2"></textarea>
|
|
5141
|
+
<div class="qa-row" style="justify-content:flex-end;">
|
|
5142
|
+
<button class="btn small" type="button" onclick="window.closeBlockerEdit()">Cancelar</button>
|
|
5143
|
+
<button class="btn primary small" type="button" onclick="window.submitBlockerEdit()">Salvar</button>
|
|
5144
|
+
</div>
|
|
5145
|
+
</div>
|
|
5146
|
+
</div>
|
|
4592
5147
|
<script>
|
|
4593
5148
|
window.__FREYA_DEFAULT_DIR = "${safeDefault}";
|
|
4594
5149
|
</script>
|
|
@@ -4712,13 +5267,35 @@ function buildKanbanHtml(safeDefault, appVersion) {
|
|
|
4712
5267
|
</div>
|
|
4713
5268
|
</div>
|
|
4714
5269
|
|
|
4715
|
-
<!--
|
|
5270
|
+
<!-- Blocker Kanban Board -->
|
|
4716
5271
|
<div id="kanbanBlockers" style="margin-top:20px; display:none;">
|
|
4717
5272
|
<div style="font-size:13px; font-weight:700; color:var(--text); margin-bottom:8px; display:flex; align-items:center; gap:6px;">
|
|
4718
5273
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
|
|
4719
|
-
Blockers
|
|
5274
|
+
Blockers
|
|
5275
|
+
</div>
|
|
5276
|
+
<div id="blockerKanbanBoard" class="blocker-kanban-board">
|
|
5277
|
+
<div class="blocker-kanban-col" data-blocker-status="OPEN">
|
|
5278
|
+
<div class="kanban-col-head blocker-open">
|
|
5279
|
+
<span class="kanban-col-title">OPEN</span>
|
|
5280
|
+
<span class="kanban-col-count" id="countBlockerOpen">0</span>
|
|
5281
|
+
</div>
|
|
5282
|
+
<div class="blocker-kanban-col-body" id="colBlockerOpen"></div>
|
|
5283
|
+
</div>
|
|
5284
|
+
<div class="blocker-kanban-col" data-blocker-status="MITIGATING">
|
|
5285
|
+
<div class="kanban-col-head blocker-mitigating">
|
|
5286
|
+
<span class="kanban-col-title">MITIGATING</span>
|
|
5287
|
+
<span class="kanban-col-count" id="countBlockerMitigating">0</span>
|
|
5288
|
+
</div>
|
|
5289
|
+
<div class="blocker-kanban-col-body" id="colBlockerMitigating"></div>
|
|
5290
|
+
</div>
|
|
5291
|
+
<div class="blocker-kanban-col" data-blocker-status="RESOLVED">
|
|
5292
|
+
<div class="kanban-col-head blocker-resolved">
|
|
5293
|
+
<span class="kanban-col-title">RESOLVED (7d)</span>
|
|
5294
|
+
<span class="kanban-col-count" id="countBlockerResolved">0</span>
|
|
5295
|
+
</div>
|
|
5296
|
+
<div class="blocker-kanban-col-body" id="colBlockerResolved"></div>
|
|
5297
|
+
</div>
|
|
4720
5298
|
</div>
|
|
4721
|
-
<div id="kanbanBlockersList" class="kanban-blockers-list"></div>
|
|
4722
5299
|
</div>
|
|
4723
5300
|
</div>
|
|
4724
5301
|
</main>
|
|
@@ -4763,6 +5340,79 @@ function buildKanbanHtml(safeDefault, appVersion) {
|
|
|
4763
5340
|
</div>
|
|
4764
5341
|
</div>
|
|
4765
5342
|
|
|
5343
|
+
<!-- Task Edit Modal -->
|
|
5344
|
+
<div id="taskEditOverlay" class="qa-overlay" style="display:none;">
|
|
5345
|
+
<div class="qa-modal" style="width:520px;">
|
|
5346
|
+
<div class="qa-header">
|
|
5347
|
+
<span style="font-weight:700; font-size:14px;">Editar Task</span>
|
|
5348
|
+
<button class="btn small" type="button" onclick="window.closeTaskEdit()" style="padding:2px 8px;">×</button>
|
|
5349
|
+
</div>
|
|
5350
|
+
<input type="hidden" id="teTaskId" />
|
|
5351
|
+
<textarea id="teDesc" class="qa-input" placeholder="Descri\u00e7\u00e3o da task..." rows="3"></textarea>
|
|
5352
|
+
<div class="qa-row">
|
|
5353
|
+
<select id="teCat" class="qa-select">
|
|
5354
|
+
<option value="DO_NOW">DO_NOW</option>
|
|
5355
|
+
<option value="SCHEDULE">SCHEDULE</option>
|
|
5356
|
+
<option value="DELEGATE">DELEGATE</option>
|
|
5357
|
+
</select>
|
|
5358
|
+
<select id="tePriority" class="qa-select">
|
|
5359
|
+
<option value="">Prioridade</option>
|
|
5360
|
+
<option value="critical">Cr\u00edtica</option>
|
|
5361
|
+
<option value="high">Alta</option>
|
|
5362
|
+
<option value="medium">M\u00e9dia</option>
|
|
5363
|
+
<option value="low">Baixa</option>
|
|
5364
|
+
</select>
|
|
5365
|
+
</div>
|
|
5366
|
+
<div class="qa-row">
|
|
5367
|
+
<input id="teSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
|
|
5368
|
+
<div class="qa-date-wrap">
|
|
5369
|
+
<input id="teDue" type="text" class="qa-input qa-date-text" placeholder="dd/mm/aaaa" maxlength="10" />
|
|
5370
|
+
<input id="teDuePicker" type="date" class="qa-date-hidden" tabindex="-1" />
|
|
5371
|
+
<button type="button" class="qa-date-btn" onclick="var p=document.getElementById('teDuePicker'); p.showPicker ? p.showPicker() : p.click();" title="Abrir calendario">📅</button>
|
|
5372
|
+
</div>
|
|
5373
|
+
</div>
|
|
5374
|
+
<div class="qa-row">
|
|
5375
|
+
<input id="teStream" class="qa-input" placeholder="Stream / frente (opcional)" style="flex:1;" />
|
|
5376
|
+
</div>
|
|
5377
|
+
<div class="qa-row" style="justify-content:flex-end;">
|
|
5378
|
+
<button class="btn small" type="button" onclick="window.closeTaskEdit()">Cancelar</button>
|
|
5379
|
+
<button class="btn primary small" type="button" onclick="window.submitTaskEdit()">Salvar</button>
|
|
5380
|
+
</div>
|
|
5381
|
+
</div>
|
|
5382
|
+
</div>
|
|
5383
|
+
<!-- Blocker Edit Modal -->
|
|
5384
|
+
<div id="blockerEditOverlay" class="qa-overlay" style="display:none;">
|
|
5385
|
+
<div class="qa-modal" style="width:520px;">
|
|
5386
|
+
<div class="qa-header">
|
|
5387
|
+
<span style="font-weight:700; font-size:14px;">Editar Blocker</span>
|
|
5388
|
+
<button class="btn small" type="button" onclick="window.closeBlockerEdit()" style="padding:2px 8px;">×</button>
|
|
5389
|
+
</div>
|
|
5390
|
+
<input type="hidden" id="beBlockerId" />
|
|
5391
|
+
<textarea id="beTitle" class="qa-input" placeholder="T\u00edtulo do blocker..." rows="2"></textarea>
|
|
5392
|
+
<div class="qa-row">
|
|
5393
|
+
<select id="beSeverity" class="qa-select">
|
|
5394
|
+
<option value="CRITICAL">Critical</option>
|
|
5395
|
+
<option value="HIGH">High</option>
|
|
5396
|
+
<option value="MEDIUM">Medium</option>
|
|
5397
|
+
<option value="LOW">Low</option>
|
|
5398
|
+
</select>
|
|
5399
|
+
<select id="beStatus" class="qa-select">
|
|
5400
|
+
<option value="OPEN">Open</option>
|
|
5401
|
+
<option value="MITIGATING">Mitigating</option>
|
|
5402
|
+
<option value="RESOLVED">Resolved</option>
|
|
5403
|
+
</select>
|
|
5404
|
+
</div>
|
|
5405
|
+
<div class="qa-row">
|
|
5406
|
+
<input id="beSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
|
|
5407
|
+
<input id="beOwner" class="qa-input" placeholder="Respons\u00e1vel" style="flex:1;" />
|
|
5408
|
+
</div>
|
|
5409
|
+
<textarea id="beNextAction" class="qa-input" placeholder="Pr\u00f3xima a\u00e7\u00e3o..." rows="2"></textarea>
|
|
5410
|
+
<div class="qa-row" style="justify-content:flex-end;">
|
|
5411
|
+
<button class="btn small" type="button" onclick="window.closeBlockerEdit()">Cancelar</button>
|
|
5412
|
+
<button class="btn primary small" type="button" onclick="window.submitBlockerEdit()">Salvar</button>
|
|
5413
|
+
</div>
|
|
5414
|
+
</div>
|
|
5415
|
+
</div>
|
|
4766
5416
|
<script>
|
|
4767
5417
|
window.__FREYA_DEFAULT_DIR = "${safeDefault}";
|
|
4768
5418
|
</script>
|
package/package.json
CHANGED