diff --git a/cmd/agent/executor_agent_service.go b/cmd/agent/executor_agent_service.go index ede9681..f15b681 100644 --- a/cmd/agent/executor_agent_service.go +++ b/cmd/agent/executor_agent_service.go @@ -248,6 +248,7 @@ func (e *ExecutorAgentService) processAction(action actions.Action) { tracker.Failed() return } + tracker.Running() // Get executor executor := e.GetExecutor(target.AccountID) @@ -275,6 +276,7 @@ func (e *ExecutorAgentService) processScanAction(action actions.Action, tracker tracker.Failed() return } + tracker.Running() target := action.GetTarget() diff --git a/console/src/api/data-contracts.ts b/console/src/api/data-contracts.ts index 6d8268f..39c6544 100644 --- a/console/src/api/data-contracts.ts +++ b/console/src/api/data-contracts.ts @@ -79,7 +79,7 @@ export interface ActionResponseApi { } export interface ActionTargetApi { - accountName?: string; + accountId?: string; clusterId?: string; instances?: string[]; region?: string; diff --git a/console/src/app/Contexts/UserContext.tsx b/console/src/app/Contexts/UserContext.tsx index a3c2cff..f7d1118 100644 --- a/console/src/app/Contexts/UserContext.tsx +++ b/console/src/app/Contexts/UserContext.tsx @@ -18,10 +18,8 @@ export const UserProvider: React.FC<{ children: React.ReactNode }> = ({ children fetch(window.location.href) .then(response => { const email = response.headers.get('gap-auth'); - if (email) { - setUserEmail(email); - console.log('User email:', email); - } + setUserEmail(email || 'clusteriq@dev'); + console.log('User email:', email || 'clusteriq@dev (fallback)'); }) .catch(error => console.error('Error fetching headers:', error)); }, []); diff --git a/console/src/app/Overview/hooks/useDashboardData.ts b/console/src/app/Overview/hooks/useDashboardData.ts index e13b544..3ca6535 100644 --- a/console/src/app/Overview/hooks/useDashboardData.ts +++ b/console/src/app/Overview/hooks/useDashboardData.ts @@ -1,27 +1,19 @@ -import { useState, useEffect } from 'react'; +import { useQuery } from '@tanstack/react-query'; import { api, OverviewSummaryApi } from '@api'; export const useDashboardData = () => { - const [inventoryData, setInventoryData] = useState(); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); + const { data, isLoading, error } = useQuery({ + queryKey: ['overview'], + queryFn: async ({ signal }) => { + const { data } = await api.overview.overviewList({ signal }); + return data; + }, + refetchInterval: 5_000, + }); - useEffect(() => { - const inventoryOverview = async () => { - try { - setLoading(true); - setError(null); - const { data } = await api.overview.overviewList(); - setInventoryData(data); - } catch { - setError('Failed to fetch inventory data'); - console.error('Failed to fetch inventory data.'); - } finally { - setLoading(false); - } - }; - inventoryOverview(); - }, []); - - return { inventoryData, loading, error }; + return { + inventoryData: data, + loading: isLoading, + error: error ? 'Failed to fetch inventory data' : null, + }; }; diff --git a/console/src/app/Overview/hooks/useEventsData.ts b/console/src/app/Overview/hooks/useEventsData.ts index ee0a548..b713bc0 100644 --- a/console/src/app/Overview/hooks/useEventsData.ts +++ b/console/src/app/Overview/hooks/useEventsData.ts @@ -1,30 +1,19 @@ -import { useState, useEffect } from 'react'; +import { useQuery } from '@tanstack/react-query'; import { api, SystemEventResponseApi } from '@api'; export const useEventsData = () => { - const [events, setEvents] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); + const { data, isLoading, error } = useQuery({ + queryKey: ['recentEvents'], + queryFn: async ({ signal }) => { + const { data } = await api.events.eventsList({ page: 1, page_size: 10 }, { signal }); + return data.items || []; + }, + refetchInterval: 5_000, + }); - useEffect(() => { - const fetchEvents = async () => { - try { - setLoading(true); - setError(null); - console.log('Fetching recent events...'); - const { data } = await api.events.eventsList({ page: 1, page_size: 10 }); - console.log('Events data received:', data); - setEvents(data.items || []); - } catch (err) { - setError('Failed to fetch events'); - console.error('Error fetching events:', err); - } finally { - setLoading(false); - } - }; - - fetchEvents(); - }, []); - - return { events, loading, error }; + return { + events: data || [], + loading: isLoading, + error: error ? 'Failed to fetch events' : null, + }; }; diff --git a/console/src/app/hooks/useAccounts.ts b/console/src/app/hooks/useAccounts.ts index b30a8e0..adf7ecb 100644 --- a/console/src/app/hooks/useAccounts.ts +++ b/console/src/app/hooks/useAccounts.ts @@ -8,5 +8,6 @@ export function useAccounts() { const { data } = await api.accounts.accountsList({ page: 1, page_size: 10000 }, { signal }); return data.items || []; }, + refetchInterval: 10_000, }); } diff --git a/console/src/app/hooks/useClusters.ts b/console/src/app/hooks/useClusters.ts index b330e52..23b153e 100644 --- a/console/src/app/hooks/useClusters.ts +++ b/console/src/app/hooks/useClusters.ts @@ -8,5 +8,6 @@ export function useClusters() { const { data } = await api.clusters.clustersList({ page: 1, page_size: 100000 }, { signal }); return data.items || []; }, + refetchInterval: 10_000, }); } diff --git a/console/src/app/hooks/useEvents.ts b/console/src/app/hooks/useEvents.ts index 15aa36f..9c96146 100644 --- a/console/src/app/hooks/useEvents.ts +++ b/console/src/app/hooks/useEvents.ts @@ -8,5 +8,6 @@ export function useEvents() { const { data } = await api.events.eventsList({}, { signal }); return data.items || []; }, + refetchInterval: 5_000, }); } diff --git a/console/src/app/hooks/useInstances.ts b/console/src/app/hooks/useInstances.ts index f474b82..010e814 100644 --- a/console/src/app/hooks/useInstances.ts +++ b/console/src/app/hooks/useInstances.ts @@ -8,5 +8,6 @@ export function useInstances() { const { data } = await api.instances.instancesList({ page: 1, page_size: 100000 }, { signal }); return data.items || []; }, + refetchInterval: 10_000, }); } diff --git a/console/src/app/hooks/useScheduleActions.ts b/console/src/app/hooks/useScheduleActions.ts index 98a9549..6797784 100644 --- a/console/src/app/hooks/useScheduleActions.ts +++ b/console/src/app/hooks/useScheduleActions.ts @@ -10,6 +10,7 @@ export function useScheduleActions() { const { data } = await api.schedule.scheduleList({ page: 1, page_size: 10000 }, { signal }); return data.items || []; }, + refetchInterval: 5_000, }); } diff --git a/internal/events/event_service/event_service.go b/internal/events/event_service/event_service.go index 093c8eb..49a4913 100644 --- a/internal/events/event_service/event_service.go +++ b/internal/events/event_service/event_service.go @@ -16,6 +16,7 @@ const ( ResultSuccess = "Success" ResultFailed = "Failed" ResultPending = "Pending" + ResultRunning = "Running" ) // Event severity levels @@ -104,6 +105,14 @@ type EventTracker struct { logger *zap.Logger } +// Running marks the tracked event as in progress. +// Uses context.Background() as event updates happen asynchronously. +func (t *EventTracker) Running() { + if err := t.service.UpdateEventStatus(context.Background(), t.eventID, ResultRunning); err != nil { + t.logger.Error("Failed to update event status", zap.Error(err)) + } +} + // Success marks the tracked event status as success. // Uses context.Background() as event updates happen asynchronously. func (t *EventTracker) Success() { diff --git a/internal/events/event_service/event_service_test.go b/internal/events/event_service/event_service_test.go index 4e33068..0321fe1 100644 --- a/internal/events/event_service/event_service_test.go +++ b/internal/events/event_service/event_service_test.go @@ -255,14 +255,46 @@ func testStartTracking_LogEventError(t *testing.T) { assert.Nil(t, tracker) } -// TestEventTracker verifies EventTracker updates status to Success/Failed and handles repo errors. +// TestEventTracker verifies EventTracker updates status to Running/Success/Failed and handles repo errors. func TestEventTracker(t *testing.T) { + t.Run("Tracker Running update ok", func(t *testing.T) { testEventTracker_Running_OK(t) }) + t.Run("Tracker Running update error", func(t *testing.T) { testEventTracker_Running_Error(t) }) t.Run("Tracker Success update ok", func(t *testing.T) { testEventTracker_Success_OK(t) }) t.Run("Tracker Success update error", func(t *testing.T) { testEventTracker_Success_Error(t) }) t.Run("Tracker Failed update ok", func(t *testing.T) { testEventTracker_Failed_OK(t) }) t.Run("Tracker Failed update error", func(t *testing.T) { testEventTracker_Failed_Error(t) }) } +func testEventTracker_Running_OK(t *testing.T) { + repo := &mockEventRepo{ + updateEventStatusFn: func(ctx context.Context, eventID int64, result string) error { + return nil + }, + } + + svc := &EventService{repo: repo, logger: zap.NewNop()} + tracker := &EventTracker{eventID: 1, service: svc, logger: zap.NewNop()} + + assert.NotPanics(t, func() { tracker.Running() }) + assert.Equal(t, 1, repo.updateEventStatusCalls) + assert.Equal(t, ResultRunning, repo.lastUpdateStatusResult) +} + +func testEventTracker_Running_Error(t *testing.T) { + repo := &mockEventRepo{ + updateEventStatusFn: func(ctx context.Context, eventID int64, result string) error { + return errTest + }, + } + + svc := &EventService{repo: repo, logger: zap.NewNop()} + tracker := &EventTracker{eventID: 1, service: svc, logger: zap.NewNop()} + + assert.NotPanics(t, func() { tracker.Running() }) + assert.Equal(t, 1, repo.updateEventStatusCalls) + assert.Equal(t, ResultRunning, repo.lastUpdateStatusResult) +} + func testEventTracker_Success_OK(t *testing.T) { repo := &mockEventRepo{ updateEventStatusFn: func(ctx context.Context, eventID int64, result string) error { diff --git a/internal/models/dto/scheduled_action_dto.go b/internal/models/dto/scheduled_action_dto.go index 723847f..4fd3be3 100644 --- a/internal/models/dto/scheduled_action_dto.go +++ b/internal/models/dto/scheduled_action_dto.go @@ -4,10 +4,10 @@ import "time" // ActionTarget represents the target resource information for an action. type ActionTarget struct { - AccountName string `json:"accountName"` - Region string `json:"region"` - ClusterID string `json:"clusterId"` - Instances []string `json:"instances"` + AccountID string `json:"accountId"` + Region string `json:"region"` + ClusterID string `json:"clusterId"` + Instances []string `json:"instances"` } // @name ActionTarget // ScheduledAction represents the data transfer object for a scheduled action.