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:
@@ -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: {
|
||||
|
||||
@@ -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 })
|
||||
},
|
||||
|
||||
@@ -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?: {
|
||||
|
||||
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user