const { invoke } = window.__TAURI__.core;
const { listen } = window.__TAURI__.event;
let activeTable = null;
let currentPage = 0;
const PAGE_SIZE = 20;
async function init() {
await updateSystemStatus();
await loadTables();
setupEvents();
setInterval(updateSystemStatus, 5000);
}
async function updateSystemStatus() {
try {
const sidecar = await invoke('get_sidecar_status');
const sidecarEl = document.getElementById('sidecar-status');
sidecarEl.textContent = sidecar ? 'Ready' : 'Down';
sidecarEl.className = sidecar ? 'tag tag-green' : 'tag tag-orange';
document.getElementById('mcp-status').textContent = 'Online';
document.getElementById('mcp-status').className = 'tag tag-green';
} catch (e) {
console.error(e);
}
}
async function loadTables() {
try {
const tables = await invoke('get_table_list');
const list = document.getElementById('table-list');
list.innerHTML = '';
tables.forEach(name => {
const li = document.createElement('li');
li.className = 'table-item';
li.textContent = name;
li.onclick = () => selectTable(name);
list.appendChild(li);
});
} catch (e) {
console.error(e);
}
}
async function selectTable(name) {
activeTable = name;
currentPage = 0;
document.querySelectorAll('.table-item').forEach(el => {
el.classList.toggle('active', el.textContent === name);
});
document.getElementById('current-title').textContent = `Table: ${name}`;
document.getElementById('main-tabs').style.display = 'flex';
document.getElementById('view-empty').style.display = 'none';
switchTab('data');
await loadData();
await loadSchema();
}
async function loadData() {
if (!activeTable) return;
showLoading(true);
try {
const result = await invoke('get_table_data', {
tableName: activeTable,
limit: PAGE_SIZE,
offset: currentPage * PAGE_SIZE
});
renderDataTable(result.data, result.total);
} catch (e) {
alert(`Error: ${e}`);
} finally {
showLoading(false);
}
}
function renderDataTable(data, total) {
const head = document.getElementById('data-head');
const body = document.getElementById('data-body');
head.innerHTML = '';
body.innerHTML = '';
if (data.length === 0) {
body.innerHTML = '<tr><td colspan="100" style="text-align:center; color:var(--text-secondary); padding: 40px;">No records found.</td></tr>';
return;
}
const columns = Object.keys(data[0]);
const htr = document.createElement('tr');
columns.forEach(col => {
const th = document.createElement('th');
th.textContent = col;
htr.appendChild(th);
});
head.appendChild(htr);
data.forEach(row => {
const tr = document.createElement('tr');
columns.forEach(col => {
const td = document.createElement('td');
let val = row[col];
if (val === null) val = '-';
td.textContent = val;
tr.appendChild(td);
});
body.appendChild(tr);
});
const start = total === 0 ? 0 : currentPage * PAGE_SIZE + 1;
const end = Math.min((currentPage + 1) * PAGE_SIZE, total);
document.getElementById('pagination-info').textContent = `Showing ${start}-${end} of ${total} records`;
document.getElementById('prev-btn').disabled = currentPage === 0;
document.getElementById('next-btn').disabled = end >= total;
}
async function loadSchema() {
try {
const info = await invoke('get_table_schema', { tableName: activeTable });
const body = document.getElementById('schema-body');
body.innerHTML = '';
info.forEach(col => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td style="font-weight:700;">${col.name}</td>
<td><span class="tag tag-blue">${col.type}</span></td>
<td>${col.notnull === "0" ? 'Yes' : 'No'}</td>
<td>${col.pk !== "0" ? '🔑' : '-'}</td>
<td style="color:var(--text-secondary);">${col.dflt_value || 'NULL'}</td>
`;
body.appendChild(tr);
});
} catch (e) {
console.error(e);
}
}
window.switchTab = function (type) {
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.view').forEach(v => v.classList.remove('active'));
const tab = document.getElementById(`tab-${type}`);
if (tab) tab.classList.add('active');
const view = document.getElementById(`view-${type}`);
if (view) view.classList.add('active');
};
window.changePage = async function (delta) {
currentPage += delta;
await loadData();
};
window.executeVectorSearch = async function () {
const text = document.getElementById('vector-input').value;
const limit = parseInt(document.getElementById('vector-limit').value);
if (!text.trim()) return;
showLoading(true);
try {
const results = await invoke('vector_search_text', { text, limit });
const container = document.getElementById('vector-results');
container.innerHTML = '';
results.forEach(res => {
const div = document.createElement('div');
div.className = 'vector-result';
// Custom formatting for 'items' table if possible
div.innerHTML = `
<div class="vector-result-header">
<span style="font-weight:700; color:var(--text-secondary);">ID: ${res.id}</span>
<span class="score-badge">Similarity: ${(1 - (res.distance || 0)).toFixed(4)}</span>
</div>
<div class="content-preview">${res.content || 'N/A'}</div>
${res.path ? `<div style="font-size:0.75rem; color:var(--accent-color); margin-top:8px;">📁 ${res.path}</div>` : ''}
`;
container.appendChild(div);
});
if (results.length === 0) {
container.innerHTML = '<div class="empty-state">一致する結果が見つかりませんでした。</div>';
}
} catch (e) {
alert(`Search Failed: ${e}`);
} finally {
showLoading(false);
}
};
window.loadMcpConfig = async function () {
activeTable = null;
document.querySelectorAll('.table-item').forEach(el => el.classList.remove('active'));
document.getElementById('current-title').textContent = 'MCP Configuration';
document.getElementById('main-tabs').style.display = 'none';
document.getElementById('view-empty').style.display = 'none';
switchTab('mcp');
try {
const data = await invoke('get_mcp_info');
document.getElementById('mcp-json').textContent = JSON.stringify(data, null, 2);
} catch (e) {
console.error(e);
}
};
window.copyConfig = function () {
const text = document.getElementById('mcp-json').textContent;
navigator.clipboard.writeText(text).then(() => {
alert('Copied to clipboard!');
});
};
function showLoading(show) {
document.getElementById('loading-indicator').style.display = show ? 'block' : 'none';
}
function setupEvents() {
listen('mcp-db-update', () => {
if (activeTable === 'items') loadData();
});
}
// Global scope initialization
window.addEventListener('DOMContentLoaded', init);