feat: frontend optimization, refactoring

This commit is contained in:
2025-08-28 20:46:53 +02:00
parent 9486594199
commit c15654ef5a
4 changed files with 179 additions and 180 deletions

View File

@@ -2,23 +2,44 @@
class ApiClient {
constructor() {
this.baseUrl = 'http://localhost:3001'; // Backend server URL
this.baseUrl = (typeof window !== 'undefined' && window.API_BASE_URL) || 'http://localhost:3001'; // Backend server URL
}
async request(path, { method = 'GET', headers = {}, body = undefined, query = undefined, isForm = false } = {}) {
const url = new URL(`${this.baseUrl}${path}`);
if (query && typeof query === 'object') {
Object.entries(query).forEach(([k, v]) => {
if (v !== undefined && v !== null) url.searchParams.set(k, String(v));
});
}
const finalHeaders = { 'Accept': 'application/json', ...headers };
const options = { method, headers: finalHeaders };
if (body !== undefined) {
if (isForm) {
options.body = body;
} else {
options.headers['Content-Type'] = options.headers['Content-Type'] || 'application/json';
options.body = typeof body === 'string' ? body : JSON.stringify(body);
}
}
const response = await fetch(url.toString(), options);
let data;
const text = await response.text();
try {
data = text ? JSON.parse(text) : null;
} catch (_) {
data = text; // Non-JSON payload
}
if (!response.ok) {
const message = (data && data.message) || `HTTP ${response.status}: ${response.statusText}`;
throw new Error(message);
}
return data;
}
async getClusterMembers() {
try {
const response = await fetch(`${this.baseUrl}/api/cluster/members`, {
method: 'GET',
headers: {
'Accept': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
return await this.request('/api/cluster/members', { method: 'GET' });
} catch (error) {
throw new Error(`Request failed: ${error.message}`);
}
@@ -26,18 +47,7 @@ class ApiClient {
async getDiscoveryInfo() {
try {
const response = await fetch(`${this.baseUrl}/api/discovery/nodes`, {
method: 'GET',
headers: {
'Accept': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
return await this.request('/api/discovery/nodes', { method: 'GET' });
} catch (error) {
throw new Error(`Request failed: ${error.message}`);
}
@@ -45,22 +55,10 @@ class ApiClient {
async selectRandomPrimaryNode() {
try {
const response = await fetch(`${this.baseUrl}/api/discovery/random-primary`, {
return await this.request('/api/discovery/random-primary', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
timestamp: new Date().toISOString()
})
body: { timestamp: new Date().toISOString() }
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
throw new Error(`Request failed: ${error.message}`);
}
@@ -68,18 +66,7 @@ class ApiClient {
async getNodeStatus(ip) {
try {
const response = await fetch(`${this.baseUrl}/api/node/status/${encodeURIComponent(ip)}`, {
method: 'GET',
headers: {
'Accept': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
return await this.request(`/api/node/status/${encodeURIComponent(ip)}`, { method: 'GET' });
} catch (error) {
throw new Error(`Request failed: ${error.message}`);
}
@@ -87,21 +74,7 @@ class ApiClient {
async getTasksStatus(ip) {
try {
const url = ip
? `${this.baseUrl}/api/tasks/status?ip=${encodeURIComponent(ip)}`
: `${this.baseUrl}/api/tasks/status`;
const response = await fetch(url, {
method: 'GET',
headers: {
'Accept': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
return await this.request('/api/tasks/status', { method: 'GET', query: ip ? { ip } : undefined });
} catch (error) {
throw new Error(`Request failed: ${error.message}`);
}
@@ -109,21 +82,7 @@ class ApiClient {
async getCapabilities(ip) {
try {
const url = ip
? `${this.baseUrl}/api/capabilities?ip=${encodeURIComponent(ip)}`
: `${this.baseUrl}/api/capabilities`;
const response = await fetch(url, {
method: 'GET',
headers: {
'Accept': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
return await this.request('/api/capabilities', { method: 'GET', query: ip ? { ip } : undefined });
} catch (error) {
throw new Error(`Request failed: ${error.message}`);
}
@@ -131,19 +90,10 @@ class ApiClient {
async callCapability({ ip, method, uri, params }) {
try {
const response = await fetch(`${this.baseUrl}/api/proxy-call`, {
return await this.request('/api/proxy-call', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ ip, method, uri, params })
body: { ip, method, uri, params }
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.message || `HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
throw new Error(`Request failed: ${error.message}`);
}
@@ -153,18 +103,13 @@ class ApiClient {
try {
const formData = new FormData();
formData.append('file', file);
const response = await fetch(`${this.baseUrl}/api/node/update?ip=${encodeURIComponent(nodeIp)}`, {
return await this.request(`/api/node/update`, {
method: 'POST',
body: formData
query: { ip: nodeIp },
body: formData,
isForm: true,
headers: {},
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || `HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
throw new Error(`Upload failed: ${error.message}`);
}