guardia-messenger/app/(tabs)/auto_sr.tsx

88 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react';
import { View, Text, ScrollView, TouchableOpacity, StyleSheet, Switch } from 'react-native';
import { ITSM_BASE } from '../../services/api';
interface AutoSRRule { id: string; name: string; condition: string; template: string; priority: string; enabled: boolean; created_count: number }
const RULES: AutoSRRule[] = [
{ id: 'R01', name: 'CPU 90% 초과', condition: 'cpu_usage > 90', template: '[자동] CPU 과부하 감지', priority: 'high', enabled: true, created_count: 8 },
{ id: 'R02', name: '디스크 95% 초과', condition: 'disk_usage > 95', template: '[자동] 디스크 용량 위험', priority: 'critical', enabled: true, created_count: 3 },
{ id: 'R03', name: 'HTTP 500 연속 5회', condition: 'http_5xx_count >= 5', template: '[자동] 서비스 오류 감지', priority: 'high', enabled: true, created_count: 12 },
{ id: 'R04', name: 'SLA 임박', condition: 'sla_remaining < 30', template: '[자동] SLA 위반 위험', priority: 'medium', enabled: false, created_count: 0 },
];
export default function AutoSRScreen() {
const [rules, setRules] = useState(RULES);
const [globalEnabled, setGlobalEnabled] = useState(true);
const [stats, setStats] = useState({ today: 5, week: 23, total: 146, auto_resolved: 89 });
const toggleRule = (id: string) => {
setRules(prev => prev.map(r => r.id === id ? { ...r, enabled: !r.enabled } : r));
};
const priorityColor = (p: string) => ({ critical: '#ff4444', high: '#ff8800', medium: '#ffbb00', low: '#44bb44' })[p] || '#888';
return (
<ScrollView style={s.container}>
<Text style={s.title}> SR </Text>
<Text style={s.sub}> SR </Text>
<View style={s.statsGrid}>
<View style={s.statBox}><Text style={s.statVal}>{stats.today}</Text><Text style={s.statLbl}></Text></View>
<View style={s.statBox}><Text style={s.statVal}>{stats.week}</Text><Text style={s.statLbl}> </Text></View>
<View style={s.statBox}><Text style={s.statVal}>{stats.total}</Text><Text style={s.statLbl}></Text></View>
<View style={s.statBox}><Text style={[s.statVal, { color: '#44bb44' }]}>{stats.auto_resolved}</Text><Text style={s.statLbl}></Text></View>
</View>
<View style={s.globalCard}>
<View style={s.row}>
<Text style={s.globalLabel}>🤖 SR </Text>
<Switch value={globalEnabled} onValueChange={setGlobalEnabled} trackColor={{ true: '#00A0C8', false: '#333' }} />
</View>
{!globalEnabled && <Text style={s.warningText}> SR </Text>}
</View>
<Text style={s.sectionTitle}> </Text>
{rules.map(rule => (
<View key={rule.id} style={[s.ruleCard, !rule.enabled && s.ruleDisabled]}>
<View style={s.ruleHeader}>
<View style={[s.priorityBadge, { backgroundColor: priorityColor(rule.priority) }]}>
<Text style={s.priorityText}>{rule.priority}</Text>
</View>
<Text style={s.ruleCount}>{rule.created_count} </Text>
<Switch value={rule.enabled && globalEnabled} onValueChange={() => toggleRule(rule.id)}
disabled={!globalEnabled} trackColor={{ true: '#00A0C8', false: '#333' }} />
</View>
<Text style={s.ruleName}>{rule.name}</Text>
<Text style={s.ruleCondition}>: {rule.condition}</Text>
<Text style={s.ruleTemplate}>릿: {rule.template}</Text>
</View>
))}
</ScrollView>
);
}
const s = StyleSheet.create({
container: { flex: 1, backgroundColor: '#0A0E1A', padding: 16 },
title: { color: '#fff', fontSize: 20, fontWeight: '700', marginBottom: 4 },
sub: { color: '#888', fontSize: 13, marginBottom: 16 },
statsGrid: { flexDirection: 'row', backgroundColor: '#1A1F2E', borderRadius: 12, padding: 14, marginBottom: 16, borderWidth: 1, borderColor: '#333', justifyContent: 'space-around' },
statBox: { alignItems: 'center' },
statVal: { color: '#00A0C8', fontSize: 22, fontWeight: '700' },
statLbl: { color: '#888', fontSize: 11, marginTop: 2 },
globalCard: { backgroundColor: '#1A1F2E', borderRadius: 12, padding: 14, marginBottom: 16, borderWidth: 1, borderColor: '#333' },
row: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' },
globalLabel: { color: '#fff', fontSize: 15, fontWeight: '600', flex: 1 },
warningText: { color: '#ffbb00', fontSize: 12, marginTop: 8 },
sectionTitle: { color: '#fff', fontSize: 16, fontWeight: '700', marginBottom: 12 },
ruleCard: { backgroundColor: '#1A1F2E', borderRadius: 12, padding: 14, marginBottom: 10, borderWidth: 1, borderColor: '#333' },
ruleDisabled: { opacity: 0.5 },
ruleHeader: { flexDirection: 'row', alignItems: 'center', marginBottom: 10 },
priorityBadge: { paddingHorizontal: 8, paddingVertical: 3, borderRadius: 6, marginRight: 8 },
priorityText: { color: '#fff', fontSize: 11, fontWeight: '700' },
ruleCount: { color: '#888', fontSize: 12, flex: 1 },
ruleName: { color: '#fff', fontWeight: '700', fontSize: 15, marginBottom: 4 },
ruleCondition: { color: '#aaa', fontSize: 12, fontFamily: 'monospace', marginBottom: 2 },
ruleTemplate: { color: '#aaa', fontSize: 12 },
});