From 2d21d4d44d8ec00bde3dea2c383e9f991d4ad178 Mon Sep 17 00:00:00 2001 From: ZGaetano Date: Mon, 18 May 2026 12:58:24 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20auth=20system=20=E2=80=94=20CSS=20page?= =?UTF-8?q?=20transitions,=20API=20helpers,=20users/tokens=20pages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- services/web-ui/public/js/api.js | 109 ++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 38 deletions(-) diff --git a/services/web-ui/public/js/api.js b/services/web-ui/public/js/api.js index 619c09f..d3a14df 100644 --- a/services/web-ui/public/js/api.js +++ b/services/web-ui/public/js/api.js @@ -133,7 +133,6 @@ async function deleteProject(projectId) { // ============================================================ // BIN API CALLS -// Bins are mounted at /api/v1/bins with project_id as query param // ============================================================ async function getBins(projectId) { @@ -166,14 +165,8 @@ async function deleteBin(projectId, binId) { // ============================================================ // CAPTURE API CALLS -// Routes: GET /capture/devices, GET /capture/status, -// POST /capture/start, POST /capture/stop // ============================================================ -/** - * Get list of available capture devices. - * Normalises capture service response ({index, name}) to {id, name, interface}. - */ async function getCaptureDevices() { const result = await captureApi('/devices'); if (result.success && result.data) { @@ -189,23 +182,14 @@ async function getCaptureDevices() { return result; } -/** Get overall capture service status */ async function getCaptureStatus() { return captureApi('/status'); } -/** Get current recording state (alias for getCaptureStatus) */ async function getRecordingStatus() { return captureApi('/status'); } -/** - * Start recording. - * @param {number} deviceIndex - Device index from getCaptureDevices - * @param {string} projectId - * @param {string|null} binId - * @param {string} clipName - */ async function startRecording(deviceIndex, projectId, binId, clipName) { const result = await captureApi('/start', { method: 'POST', @@ -222,16 +206,10 @@ async function startRecording(deviceIndex, projectId, binId, clipName) { return result; } -/** - * Stop the active recording. - * Uses the session ID stored from the most recent startRecording call, - * falling back to the current status if no local state exists. - */ async function stopRecording() { let sessionId = _captureSessionId; if (!sessionId) { - // Try to recover session_id from live status const statusResult = await captureApi('/status'); if (statusResult.success && statusResult.data && statusResult.data.sessionId) { sessionId = statusResult.data.sessionId; @@ -249,14 +227,10 @@ async function stopRecording() { return result; } -/** - * Get recent captures — uses assets API ordered by created_at desc. - */ async function getRecentCaptures(limit = 10) { return api(`/assets?limit=${limit}`); } -/** Not available in current capture service — returns empty */ async function getRecordingTimecode() { return { success: true, data: { timecode: null } }; } @@ -318,13 +292,8 @@ function throttle(func, limit) { // ============================================================ // UPLOAD API CALLS -// Routes expect camelCase field names // ============================================================ -/** - * Initialize a multipart upload. - * Returns { assetId, uploadId, key } - */ async function initUpload(data) { const body = { filename: data.filename, @@ -337,10 +306,6 @@ async function initUpload(data) { return api('/upload/init', { method: 'POST', body: JSON.stringify(body) }); } -/** - * Complete a multipart upload. - * @param {object} data - { uploadId, key, assetId, parts: [{partNumber, ETag}] } - */ async function completeUpload(data) { const body = { uploadId: data.upload_id || data.uploadId, @@ -354,7 +319,6 @@ async function completeUpload(data) { return api('/upload/complete', { method: 'POST', body: JSON.stringify(body) }); } -/** Abort an ongoing multipart upload */ async function abortUpload(data) { const body = { uploadId: data.upload_id || data.uploadId, @@ -364,7 +328,6 @@ async function abortUpload(data) { return api('/upload/abort', { method: 'POST', body: JSON.stringify(body) }); } -/** Upload a file part (FormData, no JSON content-type) */ async function uploadPart(formData) { try { const response = await fetch('/api/v1/upload/part', { @@ -380,7 +343,6 @@ async function uploadPart(formData) { } } -/** Simple upload for small files (under 50MB) */ async function simpleUpload(formData) { try { const response = await fetch('/api/v1/upload/simple', { @@ -423,3 +385,74 @@ async function deleteRecorder(id) { async function getRecorderStatus(id) { return api(`/recorders/${id}/status`); } + +// ============================================================ +// USERS API CALLS (admin) +// ============================================================ + +async function getUsers() { + return api('/users'); +} + +async function createUser(data) { + return api('/users', { method: 'POST', body: JSON.stringify(data) }); +} + +async function updateUser(id, data) { + return api(`/users/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); +} + +async function deleteUser(id) { + return api(`/users/${id}`, { method: 'DELETE' }); +} + +// ============================================================ +// GROUPS API CALLS (admin) +// ============================================================ + +async function getGroups() { + return api('/groups'); +} + +async function createGroup(data) { + return api('/groups', { method: 'POST', body: JSON.stringify(data) }); +} + +async function updateGroup(id, data) { + return api(`/groups/${id}`, { method: 'PATCH', body: JSON.stringify(data) }); +} + +async function deleteGroup(id) { + return api(`/groups/${id}`, { method: 'DELETE' }); +} + +async function getGroupMembers(id) { + return api(`/groups/${id}/members`); +} + +async function addGroupMember(groupId, userId) { + return api(`/groups/${groupId}/members`, { + method: 'POST', + body: JSON.stringify({ user_id: userId }), + }); +} + +async function removeGroupMember(groupId, userId) { + return api(`/groups/${groupId}/members/${userId}`, { method: 'DELETE' }); +} + +// ============================================================ +// TOKENS API CALLS +// ============================================================ + +async function getTokens() { + return api('/tokens'); +} + +async function createToken(data) { + return api('/tokens', { method: 'POST', body: JSON.stringify(data) }); +} + +async function revokeToken(id) { + return api(`/tokens/${id}`, { method: 'DELETE' }); +}