Initialize work order management system with database schema, API handlers, web client, and Docker configuration.
This commit is contained in:
+84
@@ -0,0 +1,84 @@
|
||||
import { setToken } from './lib/api.mjs';
|
||||
import './components/wo-list.mjs';
|
||||
import './components/wo-form.mjs';
|
||||
|
||||
// ── Keycloak init ─────────────────────────────────────────────────────────────
|
||||
const keycloak = new Keycloak({
|
||||
url: window.KEYCLOAK_URL || 'http://localhost:8180',
|
||||
realm: window.KEYCLOAK_REALM || 'workorders',
|
||||
clientId: window.KEYCLOAK_CLIENT_ID || 'workorders-app',
|
||||
});
|
||||
|
||||
keycloak.init({
|
||||
onLoad: 'login-required',
|
||||
pkceMethod: 'S256',
|
||||
checkLoginIframe: false,
|
||||
})
|
||||
.then(authenticated => {
|
||||
if (!authenticated) { keycloak.login(); return; }
|
||||
setToken(keycloak.token);
|
||||
|
||||
// Refresh token before it expires
|
||||
setInterval(async () => {
|
||||
try { await keycloak.updateToken(60); setToken(keycloak.token); }
|
||||
catch { keycloak.login(); }
|
||||
}, 30_000);
|
||||
|
||||
window.addEventListener('auth:expired', () => keycloak.login());
|
||||
renderApp(keycloak);
|
||||
})
|
||||
.catch(() => document.getElementById('app').innerHTML =
|
||||
'<p style="color:red;padding:2rem">Failed to connect to authentication server.</p>');
|
||||
|
||||
// ── App shell ─────────────────────────────────────────────────────────────────
|
||||
function renderApp(kc) {
|
||||
const app = document.getElementById('app');
|
||||
const userName = kc.tokenParsed?.name || kc.tokenParsed?.preferred_username || 'User';
|
||||
|
||||
// Nav
|
||||
const nav = document.createElement('nav');
|
||||
nav.innerHTML = `
|
||||
<span class="brand">Work Orders</span>
|
||||
<span class="spacer"></span>
|
||||
<span class="user-info">${userName}</span>
|
||||
<button id="logout" style="background:transparent;border:1px solid rgba(255,255,255,.4);color:#fff;padding:.3rem .8rem;font-size:.85rem">Logout</button>`;
|
||||
document.body.insertBefore(nav, app);
|
||||
nav.querySelector('#logout').addEventListener('click', () => kc.logout());
|
||||
|
||||
showList();
|
||||
|
||||
app.addEventListener('wo:select', e => showDetail(e.detail.id));
|
||||
app.addEventListener('wo:cancel', () => showList());
|
||||
app.addEventListener('wo:saved', () => showList());
|
||||
|
||||
document.addEventListener('keydown', e => { if (e.key === 'Escape') showList(); });
|
||||
}
|
||||
|
||||
function showList() {
|
||||
const app = document.getElementById('app');
|
||||
app.innerHTML = `
|
||||
<div class="page-header">
|
||||
<h1>Work Orders</h1>
|
||||
<button id="new-wo">+ New Work Order</button>
|
||||
</div>
|
||||
<wo-list id="wo-list"></wo-list>`;
|
||||
app.querySelector('#new-wo').addEventListener('click', showCreate);
|
||||
}
|
||||
|
||||
function showCreate() {
|
||||
const app = document.getElementById('app');
|
||||
app.innerHTML = `
|
||||
<div class="page-header"><h1>New Work Order</h1></div>
|
||||
<div class="card"><wo-form></wo-form></div>`;
|
||||
}
|
||||
|
||||
function showDetail(id) {
|
||||
const app = document.getElementById('app');
|
||||
app.innerHTML = `
|
||||
<div class="page-header">
|
||||
<h1>Edit Work Order</h1>
|
||||
<button id="back" class="secondary">← Back</button>
|
||||
</div>
|
||||
<div class="card"><wo-form wo-id="${id}"></wo-form></div>`;
|
||||
app.querySelector('#back').addEventListener('click', showList);
|
||||
}
|
||||
Reference in New Issue
Block a user