177 lines
4.0 KiB
JavaScript
177 lines
4.0 KiB
JavaScript
import { api } from "./api/client.js";
|
|
import { renderAppShell } from "./components/shell.js";
|
|
import { renderLoginPage } from "./pages/login.js";
|
|
import "./styles/main.css";
|
|
|
|
const state = {
|
|
user: null,
|
|
error: "",
|
|
tables: [],
|
|
activeTable: "",
|
|
activeTab: "data",
|
|
page: "overview",
|
|
rows: { rows: [], total: 0 },
|
|
tableDetails: { columns: [], foreignKeys: [] },
|
|
users: [],
|
|
roles: [],
|
|
auditLogs: [],
|
|
postgresLogs: [],
|
|
sqlDraft: "",
|
|
sqlResult: null,
|
|
search: ""
|
|
};
|
|
|
|
const app = document.querySelector("#app");
|
|
|
|
bootstrap();
|
|
|
|
async function bootstrap() {
|
|
try {
|
|
const { user } = await api.me();
|
|
state.user = user;
|
|
|
|
if (user) {
|
|
await hydrateDashboard();
|
|
}
|
|
} catch {
|
|
state.user = null;
|
|
}
|
|
|
|
render();
|
|
}
|
|
|
|
async function hydrateDashboard() {
|
|
const [tablesPayload, usersPayload, rolesPayload, auditPayload, logsPayload] = await Promise.all([
|
|
api.tables(),
|
|
api.users(),
|
|
api.roles(),
|
|
api.audit(),
|
|
api.postgresLogs()
|
|
]);
|
|
|
|
state.tables = tablesPayload.tables;
|
|
state.users = usersPayload.users;
|
|
state.roles = rolesPayload.roles;
|
|
state.auditLogs = auditPayload.logs;
|
|
state.postgresLogs = logsPayload.logs;
|
|
|
|
if (!state.activeTable && state.tables[0]) {
|
|
state.activeTable = state.tables[0].table_name;
|
|
}
|
|
|
|
if (state.activeTable) {
|
|
await Promise.all([loadRows(), loadTableDetails()]);
|
|
}
|
|
}
|
|
|
|
async function loadRows() {
|
|
if (!state.activeTable) {
|
|
return;
|
|
}
|
|
|
|
state.rows = await api.rows(state.activeTable, {
|
|
page: 1,
|
|
pageSize: 25,
|
|
search: state.search
|
|
});
|
|
}
|
|
|
|
async function loadTableDetails() {
|
|
if (!state.activeTable) {
|
|
return;
|
|
}
|
|
|
|
state.tableDetails = await api.tableDetails(state.activeTable);
|
|
}
|
|
|
|
function render() {
|
|
app.innerHTML = state.user ? renderAppShell(state) : renderLoginPage(state);
|
|
bindEvents();
|
|
}
|
|
|
|
function bindEvents() {
|
|
const loginForm = document.querySelector("#loginForm");
|
|
if (loginForm) {
|
|
loginForm.addEventListener("submit", handleLogin);
|
|
}
|
|
|
|
const logoutButton = document.querySelector("#logoutButton");
|
|
if (logoutButton) {
|
|
logoutButton.addEventListener("click", handleLogout);
|
|
}
|
|
|
|
document.querySelectorAll("[data-page]").forEach((element) => {
|
|
element.addEventListener("click", async (event) => {
|
|
state.page = event.currentTarget.dataset.page;
|
|
render();
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll("[data-tab]").forEach((element) => {
|
|
element.addEventListener("click", async (event) => {
|
|
state.activeTab = event.currentTarget.dataset.tab;
|
|
render();
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll("[data-table]").forEach((element) => {
|
|
element.addEventListener("click", async (event) => {
|
|
state.activeTable = event.currentTarget.dataset.table;
|
|
state.page = "overview";
|
|
state.sqlDraft = `select * from ${state.activeTable} limit 20;`;
|
|
await Promise.all([loadRows(), loadTableDetails()]);
|
|
render();
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll("[data-action]").forEach((element) => {
|
|
element.addEventListener("click", handleAction);
|
|
});
|
|
}
|
|
|
|
async function handleLogin(event) {
|
|
event.preventDefault();
|
|
const formData = new FormData(event.currentTarget);
|
|
state.error = "";
|
|
|
|
try {
|
|
const payload = await api.login({
|
|
username: formData.get("username"),
|
|
password: formData.get("password")
|
|
});
|
|
state.user = payload.user;
|
|
await hydrateDashboard();
|
|
} catch (error) {
|
|
state.error = error.message;
|
|
}
|
|
|
|
render();
|
|
}
|
|
|
|
async function handleLogout() {
|
|
await api.logout();
|
|
state.user = null;
|
|
state.error = "";
|
|
render();
|
|
}
|
|
|
|
async function handleAction(event) {
|
|
const action = event.currentTarget.dataset.action;
|
|
|
|
if (action === "refresh") {
|
|
await hydrateDashboard();
|
|
}
|
|
|
|
if (action === "search") {
|
|
state.search = document.querySelector("#tableSearchInput")?.value || "";
|
|
await loadRows();
|
|
}
|
|
|
|
if (action === "run-sql") {
|
|
state.sqlDraft = document.querySelector("#sqlEditor")?.value || "";
|
|
state.sqlResult = await api.executeSql(state.sqlDraft);
|
|
}
|
|
|
|
render();
|
|
}
|