feat(ui): add learning status hook and enhance AI indicator visibility
New useLearningStatus hook: - Polls /api/ai/intelligence/learning every 60 seconds - Provides resourceCount(), metricCount(), learningState() - Convenience accessors: isActive(), isLearning(), isWaiting() Enhanced AIStatusIndicator: - Now shows when ANY baselines exist (not just when Patrol enabled) - Tooltip shows 'X resources baselined' for transparency - Healthy state 45 resources baselined'shows ' - Works even without Pro license since baselines are FREE This makes the AI presence visible from the moment Pulse starts learning, providing immediate value feedback to all users.
This commit is contained in:
parent
783537e1d2
commit
420e4960dc
2 changed files with 82 additions and 3 deletions
|
|
@ -9,8 +9,10 @@ import { createResource, Show, createMemo, onCleanup } from 'solid-js';
|
|||
import { useNavigate } from '@solidjs/router';
|
||||
import { getPatrolStatus, type PatrolStatus } from '../../api/patrol';
|
||||
import { useAllAnomalies } from '@/hooks/useAnomalies';
|
||||
import { useLearningStatus } from '@/hooks/useLearningStatus';
|
||||
import './AIStatusIndicator.css';
|
||||
|
||||
|
||||
export function AIStatusIndicator() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
|
@ -29,10 +31,14 @@ export function AIStatusIndicator() {
|
|||
// Get anomaly data (also polls every 30 seconds via the hook)
|
||||
const anomalyData = useAllAnomalies();
|
||||
|
||||
// Get learning status (polls every 60 seconds)
|
||||
const learningStatus = useLearningStatus();
|
||||
|
||||
// Refetch patrol status every 30 seconds with proper cleanup
|
||||
const intervalId = setInterval(() => refetch(), 30000);
|
||||
onCleanup(() => clearInterval(intervalId));
|
||||
|
||||
|
||||
// Count anomalies by severity
|
||||
const anomalyCounts = createMemo(() => {
|
||||
const anomalies = anomalyData.anomalies();
|
||||
|
|
@ -96,8 +102,21 @@ export function AIStatusIndicator() {
|
|||
parts.push(`Anomalies: ${anomalyParts.join(', ')}`);
|
||||
}
|
||||
|
||||
// Learning status - show when healthy to indicate AI is working
|
||||
const resourceCount = learningStatus.resourceCount();
|
||||
if (parts.length === 0 && resourceCount > 0) {
|
||||
// Show learning progress when healthy
|
||||
return `AI: All healthy • ${resourceCount} resources baselined`;
|
||||
}
|
||||
|
||||
if (parts.length === 0) {
|
||||
if (!s?.enabled) return 'AI Patrol disabled';
|
||||
if (!s?.enabled) {
|
||||
// Show baseline info even when patrol disabled
|
||||
if (resourceCount > 0) {
|
||||
return `AI Learning: ${resourceCount} resources baselined`;
|
||||
}
|
||||
return 'AI Baseline Learning active';
|
||||
}
|
||||
if (s?.license_required) {
|
||||
if (s.license_status === 'active') {
|
||||
return 'AI Patrol is not included in this license tier';
|
||||
|
|
@ -113,6 +132,7 @@ export function AIStatusIndicator() {
|
|||
return `AI Intelligence: ${parts.join(' | ')}`;
|
||||
});
|
||||
|
||||
|
||||
const statusClass = createMemo(() => {
|
||||
if (hasIssues() || hasAnomalies()) return 'ai-status--issues';
|
||||
if (hasWatch() || hasMildAnomalies()) return 'ai-status--watch';
|
||||
|
|
@ -127,10 +147,12 @@ export function AIStatusIndicator() {
|
|||
// Combined total for badge
|
||||
const badgeCount = createMemo(() => totalFindings() + totalAnomalies());
|
||||
|
||||
// Show indicator if patrol is enabled OR if we have anomalies (anomalies work without patrol)
|
||||
// Show indicator if patrol is enabled, we have anomalies, OR we have learned baselines
|
||||
// This makes the AI presence visible even before Patrol is configured
|
||||
const showIndicator = createMemo(() => {
|
||||
const s = status();
|
||||
return s?.enabled || totalAnomalies() > 0;
|
||||
const hasBaselines = learningStatus.resourceCount() > 0;
|
||||
return s?.enabled || totalAnomalies() > 0 || hasBaselines;
|
||||
});
|
||||
|
||||
return (
|
||||
|
|
|
|||
57
frontend-modern/src/hooks/useLearningStatus.ts
Normal file
57
frontend-modern/src/hooks/useLearningStatus.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* useLearningStatus - Hook for fetching AI learning/baseline status
|
||||
*
|
||||
* This shows users how much the AI has learned about their infrastructure,
|
||||
* providing transparency into the baseline learning process.
|
||||
*
|
||||
* FREE feature - no license required.
|
||||
*/
|
||||
|
||||
import { createResource, onCleanup } from 'solid-js';
|
||||
import { AIAPI } from '@/api/ai';
|
||||
import type { LearningStatusResponse } from '@/types/aiIntelligence';
|
||||
|
||||
// Default empty state
|
||||
const emptyLearningStatus: LearningStatusResponse = {
|
||||
resources_baselined: 0,
|
||||
total_metrics: 0,
|
||||
metric_breakdown: {},
|
||||
status: 'waiting',
|
||||
message: 'Loading learning status...',
|
||||
license_required: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to get the current learning/baseline status
|
||||
* Polls every 60 seconds (learning status changes slowly)
|
||||
*/
|
||||
export function useLearningStatus() {
|
||||
const [learningStatus, { refetch }] = createResource<LearningStatusResponse>(
|
||||
async () => {
|
||||
try {
|
||||
return await AIAPI.getLearningStatus();
|
||||
} catch {
|
||||
return emptyLearningStatus;
|
||||
}
|
||||
},
|
||||
{ initialValue: emptyLearningStatus }
|
||||
);
|
||||
|
||||
// Poll every 60 seconds (learning progress changes slowly)
|
||||
const intervalId = setInterval(() => refetch(), 60000);
|
||||
onCleanup(() => clearInterval(intervalId));
|
||||
|
||||
return {
|
||||
status: learningStatus,
|
||||
refetch,
|
||||
// Convenience accessors
|
||||
resourceCount: () => learningStatus()?.resources_baselined ?? 0,
|
||||
metricCount: () => learningStatus()?.total_metrics ?? 0,
|
||||
learningState: () => learningStatus()?.status ?? 'waiting',
|
||||
isActive: () => learningStatus()?.status === 'active',
|
||||
isLearning: () => learningStatus()?.status === 'learning',
|
||||
isWaiting: () => learningStatus()?.status === 'waiting',
|
||||
};
|
||||
}
|
||||
|
||||
export default useLearningStatus;
|
||||
Loading…
Reference in a new issue