feat: auth system — CSS page transitions, API helpers, users/tokens pages
This commit is contained in:
parent
d0f9848717
commit
2d21d4d44d
1 changed files with 71 additions and 38 deletions
|
|
@ -133,7 +133,6 @@ async function deleteProject(projectId) {
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// BIN API CALLS
|
// BIN API CALLS
|
||||||
// Bins are mounted at /api/v1/bins with project_id as query param
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
async function getBins(projectId) {
|
async function getBins(projectId) {
|
||||||
|
|
@ -166,14 +165,8 @@ async function deleteBin(projectId, binId) {
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// CAPTURE API CALLS
|
// 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() {
|
async function getCaptureDevices() {
|
||||||
const result = await captureApi('/devices');
|
const result = await captureApi('/devices');
|
||||||
if (result.success && result.data) {
|
if (result.success && result.data) {
|
||||||
|
|
@ -189,23 +182,14 @@ async function getCaptureDevices() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get overall capture service status */
|
|
||||||
async function getCaptureStatus() {
|
async function getCaptureStatus() {
|
||||||
return captureApi('/status');
|
return captureApi('/status');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get current recording state (alias for getCaptureStatus) */
|
|
||||||
async function getRecordingStatus() {
|
async function getRecordingStatus() {
|
||||||
return captureApi('/status');
|
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) {
|
async function startRecording(deviceIndex, projectId, binId, clipName) {
|
||||||
const result = await captureApi('/start', {
|
const result = await captureApi('/start', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
@ -222,16 +206,10 @@ async function startRecording(deviceIndex, projectId, binId, clipName) {
|
||||||
return result;
|
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() {
|
async function stopRecording() {
|
||||||
let sessionId = _captureSessionId;
|
let sessionId = _captureSessionId;
|
||||||
|
|
||||||
if (!sessionId) {
|
if (!sessionId) {
|
||||||
// Try to recover session_id from live status
|
|
||||||
const statusResult = await captureApi('/status');
|
const statusResult = await captureApi('/status');
|
||||||
if (statusResult.success && statusResult.data && statusResult.data.sessionId) {
|
if (statusResult.success && statusResult.data && statusResult.data.sessionId) {
|
||||||
sessionId = statusResult.data.sessionId;
|
sessionId = statusResult.data.sessionId;
|
||||||
|
|
@ -249,14 +227,10 @@ async function stopRecording() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get recent captures — uses assets API ordered by created_at desc.
|
|
||||||
*/
|
|
||||||
async function getRecentCaptures(limit = 10) {
|
async function getRecentCaptures(limit = 10) {
|
||||||
return api(`/assets?limit=${limit}`);
|
return api(`/assets?limit=${limit}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Not available in current capture service — returns empty */
|
|
||||||
async function getRecordingTimecode() {
|
async function getRecordingTimecode() {
|
||||||
return { success: true, data: { timecode: null } };
|
return { success: true, data: { timecode: null } };
|
||||||
}
|
}
|
||||||
|
|
@ -318,13 +292,8 @@ function throttle(func, limit) {
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// UPLOAD API CALLS
|
// UPLOAD API CALLS
|
||||||
// Routes expect camelCase field names
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize a multipart upload.
|
|
||||||
* Returns { assetId, uploadId, key }
|
|
||||||
*/
|
|
||||||
async function initUpload(data) {
|
async function initUpload(data) {
|
||||||
const body = {
|
const body = {
|
||||||
filename: data.filename,
|
filename: data.filename,
|
||||||
|
|
@ -337,10 +306,6 @@ async function initUpload(data) {
|
||||||
return api('/upload/init', { method: 'POST', body: JSON.stringify(body) });
|
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) {
|
async function completeUpload(data) {
|
||||||
const body = {
|
const body = {
|
||||||
uploadId: data.upload_id || data.uploadId,
|
uploadId: data.upload_id || data.uploadId,
|
||||||
|
|
@ -354,7 +319,6 @@ async function completeUpload(data) {
|
||||||
return api('/upload/complete', { method: 'POST', body: JSON.stringify(body) });
|
return api('/upload/complete', { method: 'POST', body: JSON.stringify(body) });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Abort an ongoing multipart upload */
|
|
||||||
async function abortUpload(data) {
|
async function abortUpload(data) {
|
||||||
const body = {
|
const body = {
|
||||||
uploadId: data.upload_id || data.uploadId,
|
uploadId: data.upload_id || data.uploadId,
|
||||||
|
|
@ -364,7 +328,6 @@ async function abortUpload(data) {
|
||||||
return api('/upload/abort', { method: 'POST', body: JSON.stringify(body) });
|
return api('/upload/abort', { method: 'POST', body: JSON.stringify(body) });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Upload a file part (FormData, no JSON content-type) */
|
|
||||||
async function uploadPart(formData) {
|
async function uploadPart(formData) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/v1/upload/part', {
|
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) {
|
async function simpleUpload(formData) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/v1/upload/simple', {
|
const response = await fetch('/api/v1/upload/simple', {
|
||||||
|
|
@ -423,3 +385,74 @@ async function deleteRecorder(id) {
|
||||||
async function getRecorderStatus(id) {
|
async function getRecorderStatus(id) {
|
||||||
return api(`/recorders/${id}/status`);
|
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' });
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue