auth+cli
This commit is contained in:
parent
314cbd37c7
commit
07522043b4
16 changed files with 870 additions and 38 deletions
30
web/app.js
30
web/app.js
|
|
@ -1,5 +1,7 @@
|
|||
const API_BASE = '/web-api';
|
||||
|
||||
async function api(path, options = {}) {
|
||||
const res = await fetch(path, {
|
||||
const res = await fetch(`${API_BASE}${path}`, {
|
||||
headers: { 'Content-Type': 'application/json', ...(options.headers || {}) },
|
||||
...options
|
||||
});
|
||||
|
|
@ -10,7 +12,7 @@ async function api(path, options = {}) {
|
|||
const state = { projects: [], workspaces: [] };
|
||||
|
||||
async function init() {
|
||||
const me = await api('/api/me');
|
||||
const me = await api('/me');
|
||||
document.getElementById('me').textContent = `${me.username} (${me.email || 'no email'})`;
|
||||
|
||||
document.getElementById('workspaceForm').addEventListener('submit', createWorkspace);
|
||||
|
|
@ -22,7 +24,7 @@ async function init() {
|
|||
}
|
||||
|
||||
async function refreshWorkspaces() {
|
||||
state.workspaces = await api('/api/workspaces');
|
||||
state.workspaces = await api('/workspaces');
|
||||
const select = document.getElementById('workspaceSelect');
|
||||
if (state.workspaces.length === 0) {
|
||||
select.innerHTML = '<option value="">Create a workspace first</option>';
|
||||
|
|
@ -34,7 +36,7 @@ async function refreshWorkspaces() {
|
|||
}
|
||||
|
||||
async function refreshProjects() {
|
||||
state.projects = await api('/api/projects');
|
||||
state.projects = await api('/projects');
|
||||
renderProjects();
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +82,7 @@ function renderProjects() {
|
|||
div.querySelector('[data-add]').addEventListener('click', async () => {
|
||||
const key = div.querySelector('[data-k]').value.trim();
|
||||
const value = div.querySelector('[data-v]').value;
|
||||
await api(`/api/projects/${p.id}/env`, {
|
||||
await api(`/projects/${p.id}/env`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ key, value })
|
||||
});
|
||||
|
|
@ -88,7 +90,7 @@ function renderProjects() {
|
|||
});
|
||||
|
||||
div.querySelector('[data-regen]').addEventListener('click', async () => {
|
||||
await api(`/api/projects/${p.id}/service`, { method: 'POST' });
|
||||
await api(`/projects/${p.id}/service`, { method: 'POST' });
|
||||
alert('Service regenerated and systemctl --user reload attempted.');
|
||||
});
|
||||
div.querySelector('[data-status]').addEventListener('click', async () => {
|
||||
|
|
@ -98,7 +100,7 @@ function renderProjects() {
|
|||
await loadLogs(div, p.id);
|
||||
});
|
||||
div.querySelector('[data-reprovision]').addEventListener('click', async () => {
|
||||
await api(`/api/projects/${p.id}/reprovision`, { method: 'POST' });
|
||||
await api(`/projects/${p.id}/reprovision`, { method: 'POST' });
|
||||
await refreshProjects();
|
||||
});
|
||||
|
||||
|
|
@ -109,7 +111,7 @@ function renderProjects() {
|
|||
}
|
||||
|
||||
async function loadEnvList(projectNode, projectID) {
|
||||
const envs = await api(`/api/projects/${projectID}/env`);
|
||||
const envs = await api(`/projects/${projectID}/env`);
|
||||
const envRoot = projectNode.querySelector('[data-env]');
|
||||
if (envs.length === 0) {
|
||||
envRoot.innerHTML = 'No env vars';
|
||||
|
|
@ -122,7 +124,7 @@ async function loadEnvList(projectNode, projectID) {
|
|||
envRoot.querySelectorAll('[data-del]').forEach((btn) => {
|
||||
btn.addEventListener('click', async () => {
|
||||
const key = btn.getAttribute('data-del');
|
||||
await api(`/api/projects/${projectID}/env?key=${encodeURIComponent(key)}`, { method: 'DELETE' });
|
||||
await api(`/projects/${projectID}/env?key=${encodeURIComponent(key)}`, { method: 'DELETE' });
|
||||
await loadEnvList(projectNode, projectID);
|
||||
});
|
||||
});
|
||||
|
|
@ -132,7 +134,7 @@ async function loadStatus(projectNode, projectID) {
|
|||
const out = projectNode.querySelector('[data-status-out]');
|
||||
out.textContent = 'status: loading...';
|
||||
try {
|
||||
const s = await api(`/api/projects/${projectID}/status`);
|
||||
const s = await api(`/projects/${projectID}/status`);
|
||||
out.textContent = `status: ${s.active_state}/${s.sub_state} pid=${s.main_pid} result=${s.result || 'n/a'} exit=${s.exec_status}`;
|
||||
} catch (err) {
|
||||
out.textContent = `status error: ${err.message}`;
|
||||
|
|
@ -143,7 +145,7 @@ async function loadLogs(projectNode, projectID) {
|
|||
const out = projectNode.querySelector('[data-logs-out]');
|
||||
out.textContent = 'loading logs...';
|
||||
try {
|
||||
const res = await api(`/api/projects/${projectID}/logs?lines=100`);
|
||||
const res = await api(`/projects/${projectID}/logs?lines=100`);
|
||||
out.textContent = res.logs || '(no logs)';
|
||||
} catch (err) {
|
||||
out.textContent = `logs error: ${err.message}`;
|
||||
|
|
@ -163,7 +165,7 @@ async function createProject(e) {
|
|||
const msg = document.getElementById('createMsg');
|
||||
msg.textContent = 'Creating project...';
|
||||
try {
|
||||
await api('/api/projects', {
|
||||
await api('/projects', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
|
@ -186,7 +188,7 @@ async function createWorkspace(e) {
|
|||
const msg = document.getElementById('workspaceMsg');
|
||||
msg.textContent = 'Creating workspace...';
|
||||
try {
|
||||
await api('/api/workspaces', {
|
||||
await api('/workspaces', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
|
@ -202,7 +204,7 @@ async function loadCaddyConfig() {
|
|||
const out = document.getElementById('caddyConfigOut');
|
||||
out.textContent = 'Loading Caddy config...';
|
||||
try {
|
||||
const cfg = await api('/api/caddy/config');
|
||||
const cfg = await api('/caddy/config');
|
||||
out.textContent = cfg.content || JSON.stringify(cfg, null, 2);
|
||||
} catch (err) {
|
||||
out.textContent = `Error: ${err.message}`;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue