Added a way to secure the UI. Plus various bug fixes and quality of life updates

This commit is contained in:
Jaret Burkett
2025-03-20 08:07:09 -06:00
parent bbfd6ef0fe
commit 3a6b24f4c8
47 changed files with 618 additions and 378 deletions

31
ui/src/utils/api.ts Normal file
View File

@@ -0,0 +1,31 @@
import axios from 'axios';
import { createGlobalState } from 'react-global-hooks';
export const isAuthorizedState = createGlobalState(false);
export const apiClient = axios.create();
// Add a request interceptor to add token from localStorage
apiClient.interceptors.request.use(config => {
const token = localStorage.getItem('AI_TOOLKIT_AUTH');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
});
// Add a response interceptor to handle 401 errors
apiClient.interceptors.response.use(
response => response, // Return successful responses as-is
error => {
// Check if the error is a 401 Unauthorized
if (error.response && error.response.status === 401) {
// Clear the auth token from localStorage
localStorage.removeItem('AI_TOOLKIT_AUTH');
isAuthorizedState.set(false);
}
// Reject the promise with the error so calling code can still catch it
return Promise.reject(error);
},
);

View File

@@ -2,3 +2,4 @@ export const objectCopy = <T>(obj: T): T => {
return JSON.parse(JSON.stringify(obj)) as T;
};
export const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

View File

@@ -79,10 +79,10 @@ export function useNestedState<T>(initialState: T): [T, (value: any, path?: stri
const setValue = React.useCallback((value: any, path?: string) => {
if (path === undefined) {
setState(value);
return
return;
}
setState(prevState => setNestedValue(prevState, value, path));
}, []);
return [state, setValue];
}
}

View File

@@ -1,10 +1,12 @@
import { JobConfig } from '@/types';
import { Job } from '@prisma/client';
import { apiClient } from '@/utils/api';
export const startJob = (jobID: string) => {
return new Promise<void>((resolve, reject) => {
fetch(`/api/jobs/${jobID}/start`)
.then(res => res.json())
apiClient
.get(`/api/jobs/${jobID}/start`)
.then(res => res.data)
.then(data => {
console.log('Job started:', data);
resolve();
@@ -18,8 +20,9 @@ export const startJob = (jobID: string) => {
export const stopJob = (jobID: string) => {
return new Promise<void>((resolve, reject) => {
fetch(`/api/jobs/${jobID}/stop`)
.then(res => res.json())
apiClient
.get(`/api/jobs/${jobID}/stop`)
.then(res => res.data)
.then(data => {
console.log('Job stopped:', data);
resolve();
@@ -33,8 +36,9 @@ export const stopJob = (jobID: string) => {
export const deleteJob = (jobID: string) => {
return new Promise<void>((resolve, reject) => {
fetch(`/api/jobs/${jobID}/delete`)
.then(res => res.json())
apiClient
.get(`/api/jobs/${jobID}/delete`)
.then(res => res.data)
.then(data => {
console.log('Job deleted:', data);
resolve();
@@ -67,9 +71,9 @@ export const getAvaliableJobActions = (job: Job) => {
export const getNumberOfSamples = (job: Job) => {
const jobConfig = getJobConfig(job);
return jobConfig.config.process[0].sample?.prompts?.length || 0;
}
};
export const getTotalSteps = (job: Job) => {
const jobConfig = getJobConfig(job);
return jobConfig.config.process[0].train.steps;
}
};