Refactor API and store logic for sensor and room management

- Add sensor name to SensorInfo interface - Update API client to
conditionally include auth headers - Add saveToken endpoint to authApi -
Refactor roomsApi to use getRoomNames endpoint - Change sensorsApi to
use /api/v1/sensors/get - Improve token handling and JWT decoding in
auth store - Refactor room loading to use API client in energy store -
Add helper to transform API sensor data - Update SensorManagementView to
load sensors from API and fix filtering
This commit is contained in:
rafaeldpsilva
2025-09-25 14:48:48 +01:00
parent 6510468768
commit 326746b5ef
7 changed files with 445 additions and 369 deletions

View File

@@ -76,6 +76,7 @@ export interface SensorReading {
}
export interface SensorInfo {
name: string
sensor_id: string
sensor_type: SensorType
room?: string
@@ -211,13 +212,49 @@ class ApiClient {
this.baseUrl = baseUrl
}
private getAuthHeaders(): Record<string, string> {
private shouldIncludeAuth(endpoint: string): boolean {
// Endpoints that do NOT require authentication
const publicEndpoints = [
'/health',
'/api/v1/tokens/generate',
'/api/v1/tokens/validate',
'/api/v1/ingestion/',
]
// Special case: token save, revoke operations might need auth depending on backend implementation
// For now, let's include auth for them to be safe
return !publicEndpoints.some((publicPath) => endpoint.startsWith(publicPath))
}
private getAuthHeaders(endpoint: string): Record<string, string> {
// Only include auth headers for endpoints that require authentication
if (!this.shouldIncludeAuth(endpoint)) {
return {}
}
// Dynamically get auth headers to avoid circular imports
try {
// Try to get from window first (for when store is exposed)
const authStore = (window as any).__AUTH_STORE__
if (authStore && typeof authStore.getAuthHeader === 'function') {
return authStore.getAuthHeader()
}
// Fallback: try to access the auth store directly
// This requires the auth store to be initialized
const token = localStorage.getItem('dashboard_auth_token')
if (token) {
// Check if token is still valid
const expiry = localStorage.getItem('dashboard_token_expiry')
if (expiry) {
const expiryTime = new Date(expiry).getTime()
const currentTime = new Date().getTime()
if (currentTime < expiryTime) {
return { Authorization: `Bearer ${token}` }
}
}
}
} catch (error) {
console.warn('Could not get auth headers:', error)
}
@@ -227,7 +264,7 @@ class ApiClient {
private async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
const url = `${this.baseUrl}${endpoint}`
const authHeaders = this.getAuthHeaders()
const authHeaders = this.getAuthHeaders(endpoint)
const config: RequestInit = {
headers: {
'Content-Type': 'application/json',
@@ -270,7 +307,7 @@ class ApiClient {
})
}
const authHeaders = this.getAuthHeaders()
const authHeaders = this.getAuthHeaders(endpoint)
const response = await fetch(url.toString(), {
method: 'GET',
headers: {

View File

@@ -1,18 +1,16 @@
/**
* Authentication API Service
* Handles JWT token generation and validation
*/
import { apiClient } from './api'
export interface TokenRequest {
name: string
list_of_resources: string[]
data_aggregation?: boolean
time_aggregation?: boolean
embargo?: number
exp_hours?: number
}
export interface TokenResponse {
token: string
expires_at: string
resources: string[]
}
export interface TokenValidation {
@@ -26,6 +24,10 @@ export const authApi = {
return apiClient.post<TokenResponse>('/api/v1/tokens/generate', request)
},
async saveToken(token: string): Promise<{ token: string; datetime: string; active: boolean }> {
return apiClient.post<{ token: string; datetime: string; active: boolean }>('/api/v1/tokens/save', { token })
},
async validateToken(token: string): Promise<TokenValidation> {
return apiClient.post<TokenValidation>('/api/v1/tokens/validate', { token })
},

View File

@@ -1,20 +1,14 @@
/**
* Rooms API Service
* Handles room-related API calls
*/
import { apiClient, type RoomInfo, type RoomData } from './api'
export const roomsApi = {
/**
* Get list of all rooms with sensor counts and latest metrics
*/
async getRoomNames(): Promise<{ rooms: string[] }> {
return apiClient.get<{ rooms: string[] }>('/api/v1/rooms/names')
},
async getRooms(): Promise<RoomInfo[]> {
return apiClient.get<RoomInfo[]>('/api/v1/rooms')
},
/**
* Get historical data for a specific room
*/
async getRoomData(
roomName: string,
params?: {

View File

@@ -14,7 +14,7 @@ export const sensorsApi = {
sensor_type?: SensorType
status?: SensorStatus
}): Promise<SensorInfo[]> {
return apiClient.get<SensorInfo[]>('/api/v1/sensors', params)
return apiClient.get<SensorInfo[]>('/api/v1/sensors/get', params)
},
async getSensor(sensorId: string): Promise<SensorInfo> {