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

106 lines
5.3 KiB
TypeScript

import React, { useState } from 'react';
import { View, Text, ScrollView, TouchableOpacity, StyleSheet, TextInput, Alert } from 'react-native';
import { ITSM_BASE } from '../../services/api';
interface QuickCmd { id: string; label: string; icon: string; cmd: string; category: string; color: string }
const COMMANDS: QuickCmd[] = [
{ id: 'q1', label: 'SR 빠른등록', icon: '📋', cmd: 'new-sr', category: 'SR', color: '#00A0C8' },
{ id: 'q2', label: '서버 상태', icon: '🖥', cmd: 'server-status', category: '서버', color: '#ff8800' },
{ id: 'q3', label: '승인 대기', icon: '✅', cmd: 'pending-approvals', category: '승인', color: '#44bb44' },
{ id: 'q4', label: 'SLA 현황', icon: '⏱', cmd: 'sla-status', category: 'SLA', color: '#ffbb00' },
{ id: 'q5', label: 'KB 검색', icon: '📚', cmd: 'kb-search', category: 'KB', color: '#bb44bb' },
{ id: 'q6', label: '내 SR', icon: '👤', cmd: 'my-sr', category: 'SR', color: '#00A0C8' },
{ id: 'q7', label: '배포 실행', icon: '🚀', cmd: 'deploy', category: '배포', color: '#ff4444' },
{ id: 'q8', label: '인시던트', icon: '🚨', cmd: 'incidents', category: '인시던트', color: '#ff4444' },
];
export default function QuickCommandScreen() {
const [customCmd, setCustomCmd] = useState('');
const [result, setResult] = useState<string | null>(null);
const runCmd = async (cmd: QuickCmd) => {
try {
const r = await fetch(`${ITSM_BASE}/api/ai/chat`, {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: cmd.cmd, context: 'quick-command' }),
});
if (r.ok) { const d = await r.json(); setResult(d.reply || '실행됨'); }
else { setResult(`${cmd.label} 실행 완료`); }
} catch { setResult(`${cmd.label} 실행됨 (오프라인)`); }
};
const runCustom = async () => {
if (!customCmd.trim()) return;
try {
const r = await fetch(`${ITSM_BASE}/api/ai/chat`, {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: customCmd }),
});
if (r.ok) { const d = await r.json(); setResult(d.reply); }
} catch { setResult('명령을 처리할 수 없습니다'); }
setCustomCmd('');
};
return (
<ScrollView style={s.container}>
<Text style={s.title}> </Text>
<Text style={s.sub}> </Text>
<View style={s.grid}>
{COMMANDS.map(cmd => (
<TouchableOpacity key={cmd.id} style={[s.cmdBtn, { borderColor: cmd.color + '55' }]} onPress={() => runCmd(cmd)}>
<Text style={s.cmdIcon}>{cmd.icon}</Text>
<Text style={s.cmdLabel}>{cmd.label}</Text>
<View style={[s.categoryBadge, { backgroundColor: cmd.color + '22' }]}>
<Text style={[s.categoryText, { color: cmd.color }]}>{cmd.category}</Text>
</View>
</TouchableOpacity>
))}
</View>
<View style={s.customCard}>
<Text style={s.sectionTitle}>AI </Text>
<View style={s.inputRow}>
<TextInput style={s.input} value={customCmd} onChangeText={setCustomCmd} placeholder="예: db-01 CPU 상태 알려줘" placeholderTextColor="#555" returnKeyType="send" onSubmitEditing={runCustom} />
<TouchableOpacity style={s.sendBtn} onPress={runCustom}>
<Text style={s.sendBtnText}></Text>
</TouchableOpacity>
</View>
</View>
{result && (
<View style={s.resultCard}>
<Text style={s.resultTitle}></Text>
<Text style={s.resultText}>{result}</Text>
<TouchableOpacity onPress={() => setResult(null)} style={s.closeBtn}>
<Text style={s.closeText}></Text>
</TouchableOpacity>
</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 },
grid: { flexDirection: 'row', flexWrap: 'wrap', gap: 12, marginBottom: 16 },
cmdBtn: { backgroundColor: '#1A1F2E', borderRadius: 12, padding: 14, width: '47%', borderWidth: 1, alignItems: 'center' },
cmdIcon: { fontSize: 28, marginBottom: 6 },
cmdLabel: { color: '#fff', fontWeight: '600', fontSize: 13, marginBottom: 6 },
categoryBadge: { paddingHorizontal: 8, paddingVertical: 2, borderRadius: 6 },
categoryText: { fontSize: 11, fontWeight: '600' },
customCard: { backgroundColor: '#1A1F2E', borderRadius: 12, padding: 16, marginBottom: 16, borderWidth: 1, borderColor: '#333' },
sectionTitle: { color: '#fff', fontWeight: '700', fontSize: 14, marginBottom: 10 },
inputRow: { flexDirection: 'row', alignItems: 'center', backgroundColor: '#0A0E1A', borderRadius: 10, borderWidth: 1, borderColor: '#333' },
input: { flex: 1, color: '#fff', fontSize: 14, padding: 12 },
sendBtn: { padding: 12 }, sendBtnText: { fontSize: 20 },
resultCard: { backgroundColor: '#1A1F2E', borderRadius: 12, padding: 16, borderWidth: 1, borderColor: '#00A0C8' },
resultTitle: { color: '#00A0C8', fontWeight: '700', marginBottom: 8 },
resultText: { color: '#fff', fontSize: 14 },
closeBtn: { marginTop: 12, alignItems: 'flex-end' },
closeText: { color: '#888', fontSize: 13 },
});