Spaces:
Sleeping
Sleeping
Upload index.html
Browse files- static/index.html +162 -19
static/index.html
CHANGED
|
@@ -1449,36 +1449,42 @@ async function uploadDatabase() {
|
|
| 1449 |
customDbFilename = data.filename;
|
| 1450 |
firstCustomTable = data.tables[0]?.table_name || 'table';
|
| 1451 |
|
| 1452 |
-
// Store compatible tasks
|
| 1453 |
-
|
| 1454 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1455 |
window.usingUploadedDbForTasks = true;
|
| 1456 |
|
| 1457 |
// Enable task selection for uploaded DB
|
| 1458 |
mode = 'task'; // Stay in task mode, not custom mode
|
| 1459 |
|
| 1460 |
-
// Update UI
|
| 1461 |
-
|
|
|
|
| 1462 |
document.getElementById('upload-status').style.color = 'var(--success)';
|
| 1463 |
document.getElementById('back-to-tasks-btn').style.display = 'inline-flex';
|
| 1464 |
|
| 1465 |
// Update schema panel with health data
|
| 1466 |
renderSchema(data.tables, data.health_audits);
|
| 1467 |
|
| 1468 |
-
// Show task selection
|
| 1469 |
-
|
| 1470 |
|
| 1471 |
// Ensure task selector is enabled
|
| 1472 |
updateUIForMode();
|
| 1473 |
|
| 1474 |
-
toast('Database uploaded! ' +
|
| 1475 |
} else {
|
| 1476 |
// No compatible tasks - go to custom exploration mode
|
| 1477 |
mode = 'custom';
|
| 1478 |
window.uploadedCompatibleTasks = [];
|
|
|
|
| 1479 |
window.usingUploadedDbForTasks = false;
|
| 1480 |
|
| 1481 |
-
document.getElementById('upload-status').innerHTML = '✓ ' + data.filename + ' loaded (' + data.tables.length + ' tables) - <em>
|
| 1482 |
document.getElementById('upload-status').style.color = 'var(--text-secondary)';
|
| 1483 |
document.getElementById('back-to-tasks-btn').style.display = 'inline-flex';
|
| 1484 |
|
|
@@ -1487,7 +1493,7 @@ async function uploadDatabase() {
|
|
| 1487 |
document.getElementById('query-sql').placeholder = 'SELECT * FROM ' + firstCustomTable + ' LIMIT 10';
|
| 1488 |
updateUIForMode();
|
| 1489 |
|
| 1490 |
-
toast('Database uploaded for exploration
|
| 1491 |
}
|
| 1492 |
} else {
|
| 1493 |
document.getElementById('upload-error').style.display = 'block';
|
|
@@ -1503,8 +1509,8 @@ async function uploadDatabase() {
|
|
| 1503 |
setLoading('upload', false);
|
| 1504 |
}
|
| 1505 |
|
| 1506 |
-
function
|
| 1507 |
-
// Create or update task selector
|
| 1508 |
let selector = document.getElementById('uploaded-db-task-selector');
|
| 1509 |
if (!selector) {
|
| 1510 |
selector = document.createElement('div');
|
|
@@ -1519,23 +1525,160 @@ function showUploadedDbTaskSelector(compatibleTasks) {
|
|
| 1519 |
'type_repair': 'Type Repair',
|
| 1520 |
'dedup_bug': 'Duplicate Bug',
|
| 1521 |
'fk_integrity': 'FK Integrity',
|
| 1522 |
-
'schema_drift': 'Schema Drift'
|
|
|
|
| 1523 |
};
|
| 1524 |
|
| 1525 |
-
let html = '<div style="font-size: 14px; color: #2E7D32; margin-bottom: 8px;"><strong>
|
| 1526 |
-
html += '<div style="display: flex; gap: 8px; flex-wrap: wrap;">';
|
| 1527 |
|
| 1528 |
-
|
| 1529 |
-
|
| 1530 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1531 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1532 |
html += '</div>';
|
| 1533 |
-
html += '<div style="margin-top: 8px; font-size: 11px; color: #558B2F;">These tasks will analyze your uploaded database</div>';
|
| 1534 |
|
| 1535 |
selector.innerHTML = html;
|
| 1536 |
selector.style.display = 'block';
|
| 1537 |
}
|
| 1538 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1539 |
function selectUploadedDbTask(taskId) {
|
| 1540 |
// Update task selector to match
|
| 1541 |
document.getElementById('task-select').value = taskId;
|
|
|
|
| 1449 |
customDbFilename = data.filename;
|
| 1450 |
firstCustomTable = data.tables[0]?.table_name || 'table';
|
| 1451 |
|
| 1452 |
+
// Store compatible tasks and semantic suggestions
|
| 1453 |
+
const hasLegacyTasks = data.compatible_tasks && data.compatible_tasks.length > 0;
|
| 1454 |
+
const hasSemanticTasks = data.semantic_tasks && data.semantic_tasks.length > 0;
|
| 1455 |
+
|
| 1456 |
+
if (hasLegacyTasks || hasSemanticTasks) {
|
| 1457 |
+
window.uploadedCompatibleTasks = data.compatible_tasks || [];
|
| 1458 |
+
window.uploadedSemanticTasks = data.semantic_tasks || [];
|
| 1459 |
window.usingUploadedDbForTasks = true;
|
| 1460 |
|
| 1461 |
// Enable task selection for uploaded DB
|
| 1462 |
mode = 'task'; // Stay in task mode, not custom mode
|
| 1463 |
|
| 1464 |
+
// Update UI with smart message
|
| 1465 |
+
const totalTasks = (data.compatible_tasks?.length || 0) + (data.semantic_tasks?.length || 0);
|
| 1466 |
+
document.getElementById('upload-status').innerHTML = '✓ ' + data.filename + ' loaded (' + data.tables.length + ' tables) - <strong>' + totalTasks + ' smart task suggestions</strong>';
|
| 1467 |
document.getElementById('upload-status').style.color = 'var(--success)';
|
| 1468 |
document.getElementById('back-to-tasks-btn').style.display = 'inline-flex';
|
| 1469 |
|
| 1470 |
// Update schema panel with health data
|
| 1471 |
renderSchema(data.tables, data.health_audits);
|
| 1472 |
|
| 1473 |
+
// Show smart task selection
|
| 1474 |
+
showSmartTaskSelector(data.compatible_tasks, data.semantic_tasks, data.fingerprints);
|
| 1475 |
|
| 1476 |
// Ensure task selector is enabled
|
| 1477 |
updateUIForMode();
|
| 1478 |
|
| 1479 |
+
toast('Database uploaded! ' + totalTasks + ' smart task suggestions available', 'success');
|
| 1480 |
} else {
|
| 1481 |
// No compatible tasks - go to custom exploration mode
|
| 1482 |
mode = 'custom';
|
| 1483 |
window.uploadedCompatibleTasks = [];
|
| 1484 |
+
window.uploadedSemanticTasks = [];
|
| 1485 |
window.usingUploadedDbForTasks = false;
|
| 1486 |
|
| 1487 |
+
document.getElementById('upload-status').innerHTML = '✓ ' + data.filename + ' loaded (' + data.tables.length + ' tables) - <em>Use Custom Mode to explore</em>';
|
| 1488 |
document.getElementById('upload-status').style.color = 'var(--text-secondary)';
|
| 1489 |
document.getElementById('back-to-tasks-btn').style.display = 'inline-flex';
|
| 1490 |
|
|
|
|
| 1493 |
document.getElementById('query-sql').placeholder = 'SELECT * FROM ' + firstCustomTable + ' LIMIT 10';
|
| 1494 |
updateUIForMode();
|
| 1495 |
|
| 1496 |
+
toast('Database uploaded for exploration (Custom Mode)', 'success');
|
| 1497 |
}
|
| 1498 |
} else {
|
| 1499 |
document.getElementById('upload-error').style.display = 'block';
|
|
|
|
| 1509 |
setLoading('upload', false);
|
| 1510 |
}
|
| 1511 |
|
| 1512 |
+
function showSmartTaskSelector(legacyTasks, semanticTasks, fingerprints) {
|
| 1513 |
+
// Create or update smart task selector
|
| 1514 |
let selector = document.getElementById('uploaded-db-task-selector');
|
| 1515 |
if (!selector) {
|
| 1516 |
selector = document.createElement('div');
|
|
|
|
| 1525 |
'type_repair': 'Type Repair',
|
| 1526 |
'dedup_bug': 'Duplicate Bug',
|
| 1527 |
'fk_integrity': 'FK Integrity',
|
| 1528 |
+
'schema_drift': 'Schema Drift',
|
| 1529 |
+
'job_market_audit': 'Job Market Audit'
|
| 1530 |
};
|
| 1531 |
|
| 1532 |
+
let html = '<div style="font-size: 14px; color: #2E7D32; margin-bottom: 8px;"><strong>🧠 Smart Task Suggestions:</strong></div>';
|
|
|
|
| 1533 |
|
| 1534 |
+
// Show semantic tasks first (they're smarter)
|
| 1535 |
+
if (semanticTasks && semanticTasks.length > 0) {
|
| 1536 |
+
html += '<div style="margin-bottom: 12px;">';
|
| 1537 |
+
html += '<div style="font-size: 12px; color: #558B2F; margin-bottom: 6px;">Based on your data analysis:</div>';
|
| 1538 |
+
|
| 1539 |
+
semanticTasks.forEach(task => {
|
| 1540 |
+
const confidence = Math.round(task.confidence * 100);
|
| 1541 |
+
const tableName = task.table_name;
|
| 1542 |
+
const fingerprint = fingerprints[tableName];
|
| 1543 |
+
const nullCount = fingerprint?.null_counts ? Object.values(fingerprint.null_counts).reduce((a, b) => a + b, 0) : 0;
|
| 1544 |
+
|
| 1545 |
+
html += '<div style="margin-bottom: 8px; padding: 8px; background: white; border-radius: 4px; border: 1px solid #C8E6C9;">';
|
| 1546 |
+
html += '<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">';
|
| 1547 |
+
html += '<span style="font-weight: 500; color: #2E7D32;">' + taskLabels[task.task_id] + '</span>';
|
| 1548 |
+
html += '<span style="font-size: 11px; background: #4CAF50; color: white; padding: 2px 6px; border-radius: 10px;">' + confidence + '% match</span>';
|
| 1549 |
+
html += '</div>';
|
| 1550 |
+
html += '<div style="font-size: 11px; color: #666; margin-bottom: 6px;">' + task.reason + '</div>';
|
| 1551 |
+
|
| 1552 |
+
if (task.requires_alias) {
|
| 1553 |
+
const suggestedAlias = task.suggested_alias || 'users';
|
| 1554 |
+
html += '<div style="display: flex; gap: 6px; align-items: center;">';
|
| 1555 |
+
html += '<button class="btn btn-primary" onclick="setTableAliasAndRunTask(\'' + tableName + '\', \'\' + suggestedAlias + '\', \'\' + task.task_id + '\')" style="font-size: 11px; padding: 4px 8px;">Run with Alias</button>';
|
| 1556 |
+
html += '<span style="font-size: 10px; color: #888;">Will treat \"' + tableName + '\" as \"' + suggestedAlias + '\"</span>';
|
| 1557 |
+
html += '</div>';
|
| 1558 |
+
} else {
|
| 1559 |
+
html += '<button class="btn btn-primary" onclick="selectUploadedDbTask(\'' + task.task_id + '\')" style="font-size: 11px; padding: 4px 8px;">Run Task</button>';
|
| 1560 |
+
}
|
| 1561 |
+
|
| 1562 |
+
html += '</div>';
|
| 1563 |
+
});
|
| 1564 |
+
|
| 1565 |
+
html += '</div>';
|
| 1566 |
+
}
|
| 1567 |
+
|
| 1568 |
+
// Show legacy tasks if any
|
| 1569 |
+
if (legacyTasks && legacyTasks.length > 0) {
|
| 1570 |
+
html += '<div style="margin-bottom: 12px;">';
|
| 1571 |
+
html += '<div style="font-size: 12px; color: #558B2F; margin-bottom: 6px;">Classic tasks (exact name match):</div>';
|
| 1572 |
+
html += '<div style="display: flex; gap: 8px; flex-wrap: wrap;">';
|
| 1573 |
+
|
| 1574 |
+
legacyTasks.forEach(taskId => {
|
| 1575 |
+
html += '<button class="btn btn-secondary" onclick="selectUploadedDbTask(\'' + taskId + '\')" style="font-size: 12px; padding: 6px 12px;">' + taskLabels[taskId] + '</button>';
|
| 1576 |
+
});
|
| 1577 |
+
|
| 1578 |
+
html += '</div></div>';
|
| 1579 |
+
}
|
| 1580 |
|
| 1581 |
+
// Add manual alias option
|
| 1582 |
+
html += '<div style="margin-top: 12px; padding: 8px; background: #FFF3E0; border-radius: 4px;">';
|
| 1583 |
+
html += '<div style="font-size: 11px; color: #E65100; margin-bottom: 6px;"><strong>Manual Override:</strong></div>';
|
| 1584 |
+
html += '<div style="font-size: 10px; color: #666; margin-bottom: 4px;">Treat any table as a specific task type:</div>';
|
| 1585 |
+
html += '<button onclick="showManualAliasDialog()" style="font-size: 10px; padding: 4px 8px; background: #FF9800; color: white; border: none; border-radius: 4px; cursor: pointer;">Set Table Alias</button>';
|
| 1586 |
html += '</div>';
|
|
|
|
| 1587 |
|
| 1588 |
selector.innerHTML = html;
|
| 1589 |
selector.style.display = 'block';
|
| 1590 |
}
|
| 1591 |
|
| 1592 |
+
function showUploadedDbTaskSelector(compatibleTasks) {
|
| 1593 |
+
// Legacy function - kept for compatibility
|
| 1594 |
+
showSmartTaskSelector(compatibleTasks, [], {});
|
| 1595 |
+
}
|
| 1596 |
+
|
| 1597 |
+
function setTableAliasAndRunTask(actualTable, aliasAs, taskId) {
|
| 1598 |
+
// Set the alias first
|
| 1599 |
+
api('POST', '/set-table-alias', {
|
| 1600 |
+
actual_table: actualTable,
|
| 1601 |
+
alias_as: aliasAs
|
| 1602 |
+
}).then(response => {
|
| 1603 |
+
if (response.ok) {
|
| 1604 |
+
toast(response.data.message, 'success');
|
| 1605 |
+
// Then select the task
|
| 1606 |
+
selectUploadedDbTask(taskId);
|
| 1607 |
+
} else {
|
| 1608 |
+
toast('Failed to set table alias', 'error');
|
| 1609 |
+
}
|
| 1610 |
+
});
|
| 1611 |
+
}
|
| 1612 |
+
|
| 1613 |
+
function showManualAliasDialog() {
|
| 1614 |
+
const tables = window.customDbSchema || [];
|
| 1615 |
+
if (tables.length === 0) {
|
| 1616 |
+
toast('No tables available', 'error');
|
| 1617 |
+
return;
|
| 1618 |
+
}
|
| 1619 |
+
|
| 1620 |
+
const tableNames = tables.map(t => t.table_name);
|
| 1621 |
+
const taskOptions = ['users', 'transactions', 'order_items', 'invoices', 'customers', 'events_v1', 'events_v2'];
|
| 1622 |
+
|
| 1623 |
+
let html = '<div style="padding: 16px;">';
|
| 1624 |
+
html += '<h3 style="margin-top: 0;">Set Table Alias</h3>';
|
| 1625 |
+
html += '<p style="color: #666; font-size: 14px;">Treat a table as if it has a different name for RL tasks</p>';
|
| 1626 |
+
|
| 1627 |
+
html += '<div style="margin-bottom: 12px;">';
|
| 1628 |
+
html += '<label style="display: block; margin-bottom: 4px; font-weight: 500;">Actual Table:</label>';
|
| 1629 |
+
html += '<select id="alias-table-select" style="width: 100%; padding: 6px; border: 1px solid #ddd; border-radius: 4px;">';
|
| 1630 |
+
tableNames.forEach(name => {
|
| 1631 |
+
html += '<option value="' + escapeHtml(name) + '">' + escapeHtml(name) + '</option>';
|
| 1632 |
+
});
|
| 1633 |
+
html += '</select>';
|
| 1634 |
+
html += '</div>';
|
| 1635 |
+
|
| 1636 |
+
html += '<div style="margin-bottom: 12px;">';
|
| 1637 |
+
html += '<label style="display: block; margin-bottom: 4px; font-weight: 500;">Treat as:</label>';
|
| 1638 |
+
html += '<select id="alias-as-select" style="width: 100%; padding: 6px; border: 1px solid #ddd; border-radius: 4px;">';
|
| 1639 |
+
taskOptions.forEach(name => {
|
| 1640 |
+
html += '<option value="' + name + '">' + name + '</option>';
|
| 1641 |
+
});
|
| 1642 |
+
html += '</select>';
|
| 1643 |
+
html += '</div>';
|
| 1644 |
+
|
| 1645 |
+
html += '<div style="display: flex; gap: 8px; justify-content: flex-end;">';
|
| 1646 |
+
html += '<button onclick="closeManualAliasDialog()" style="padding: 6px 12px; border: 1px solid #ddd; background: white; border-radius: 4px; cursor: pointer;">Cancel</button>';
|
| 1647 |
+
html += '<button onclick="applyManualAlias()" style="padding: 6px 12px; background: #2196F3; color: white; border: none; border-radius: 4px; cursor: pointer;">Apply</button>';
|
| 1648 |
+
html += '</div>';
|
| 1649 |
+
|
| 1650 |
+
html += '</div>';
|
| 1651 |
+
|
| 1652 |
+
// Create modal
|
| 1653 |
+
const modal = document.createElement('div');
|
| 1654 |
+
modal.id = 'alias-modal';
|
| 1655 |
+
modal.style.cssText = 'position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 1000;';
|
| 1656 |
+
modal.innerHTML = html;
|
| 1657 |
+
document.body.appendChild(modal);
|
| 1658 |
+
}
|
| 1659 |
+
|
| 1660 |
+
function closeManualAliasDialog() {
|
| 1661 |
+
const modal = document.getElementById('alias-modal');
|
| 1662 |
+
if (modal) modal.remove();
|
| 1663 |
+
}
|
| 1664 |
+
|
| 1665 |
+
function applyManualAlias() {
|
| 1666 |
+
const actualTable = document.getElementById('alias-table-select').value;
|
| 1667 |
+
const aliasAs = document.getElementById('alias-as-select').value;
|
| 1668 |
+
|
| 1669 |
+
api('POST', '/set-table-alias', {
|
| 1670 |
+
actual_table: actualTable,
|
| 1671 |
+
alias_as: aliasAs
|
| 1672 |
+
}).then(response => {
|
| 1673 |
+
if (response.ok) {
|
| 1674 |
+
toast(response.data.message, 'success');
|
| 1675 |
+
closeManualAliasDialog();
|
| 1676 |
+
} else {
|
| 1677 |
+
toast('Failed to set table alias', 'error');
|
| 1678 |
+
}
|
| 1679 |
+
});
|
| 1680 |
+
}
|
| 1681 |
+
|
| 1682 |
function selectUploadedDbTask(taskId) {
|
| 1683 |
// Update task selector to match
|
| 1684 |
document.getElementById('task-select').value = taskId;
|