88 lines
5.3 KiB
TypeScript
88 lines
5.3 KiB
TypeScript
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 },
|
||
});
|