import { useEffect, useState } from 'react' import { guardiaApi } from '../api/clients' type Tab = 'jira' | 'slack' | 'servicenow' | 'erp' | 'kakao' | 'sso' export default function IntegrationHub() { const [tab, setTab] = useState('jira') const tabs: { id: Tab; label: string; icon: string }[] = [ { id: 'jira', label: 'Jira', icon: 'πŸ”΅' }, { id: 'slack', label: 'Slack', icon: 'πŸ’¬' }, { id: 'servicenow', label: 'ServiceNow', icon: 'πŸ”—' }, { id: 'erp', label: 'ERP', icon: '🏒' }, { id: 'kakao', label: '카카였', icon: 'πŸ’›' }, { id: 'sso', label: 'SSO', icon: 'πŸ”' }, ] return (

πŸ”— μ™ΈλΆ€ 연동 ν—ˆλΈŒ

{tabs.map(t => ( ))}
{tab === 'jira' && } {tab === 'slack' && } {tab === 'servicenow' && } {tab === 'erp' && } {tab === 'kakao' && } {tab === 'sso' && }
) } function Card({ children, style }: { children: React.ReactNode; style?: React.CSSProperties }) { return
{children}
} function JiraTab() { const [cfg, setCfg] = useState(null) const [mappings, setMappings] = useState([]) useEffect(() => { guardiaApi.get('/api/jira/config').then((r: any) => setCfg(r.data)).catch(() => {}) guardiaApi.get('/api/jira/mappings').then((r: any) => setMappings(r.data || [])).catch(() => {}) }, []) return (

Jira 연동 μ„€μ •

{cfg ? (
URL: {cfg.base_url}
ν”„λ‘œμ νŠΈ: {cfg.project_key}
βœ… 연동됨
) :

μ„€μ • μ—†μŒ

}

SR-Issue λ§€ν•‘ ({mappings.length}건)

{['SR ID', 'Jira Key', '동기화 μ‹œκ°„'].map(h => )} {mappings.slice(0, 8).map((m: any) => ( ))} {!mappings.length && }
{h}
SR-{m.sr_id} {m.jira_key} {m.synced_at ? new Date(m.synced_at).toLocaleDateString('ko-KR') : '-'}
λ§€ν•‘ μ—†μŒ
) } function SlackTab() { const [cfg, setCfg] = useState(null) const [webhook, setWebhook] = useState('') const [channel, setChannel] = useState('#guardia-ops') useEffect(() => { guardiaApi.get('/api/slack/config').then((r: any) => setCfg(r.data)).catch(() => {}) }, []) async function save() { await guardiaApi.post('/api/slack/config', { name: 'Slack', webhook_url: webhook, default_channel: channel }) const r: any = await guardiaApi.get('/api/slack/config') setCfg(r.data) } async function testMsg() { await guardiaApi.get('/api/slack/test') } return (

Slack 연동

{cfg &&
βœ… 연동됨 ({cfg.default_channel})
}
setWebhook(e.target.value)} placeholder="https://hooks.slack.com/..." style={{ width: '100%', padding: '8px 12px', border: '1px solid #e2e8f0', borderRadius: 6, fontSize: 13, boxSizing: 'border-box' }} />
setChannel(e.target.value)} style={{ width: '100%', padding: '8px 12px', border: '1px solid #e2e8f0', borderRadius: 6, fontSize: 13, boxSizing: 'border-box' }} />
{cfg && }
) } function ServiceNowTab() { const [url, setUrl] = useState(''); const [user, setUser] = useState(''); const [pw, setPw] = useState('') async function save() { await guardiaApi.post('/api/servicenow/config', { instance_url: url, username: user, password: pw }) } return (

ServiceNow 연동

{[['μΈμŠ€ν„΄μŠ€ URL', url, setUrl, 'https://company.service-now.com'], ['μ‚¬μš©μžλͺ…', user, setUser, ''], ['λΉ„λ°€λ²ˆν˜Έ', pw, setPw, '']].map(([label, val, set, ph]: any) => (
(set as Function)(e.target.value)} placeholder={ph as string} style={{ width: '100%', padding: '8px 12px', border: '1px solid #e2e8f0', borderRadius: 6, fontSize: 13, boxSizing: 'border-box' }} />
))}
) } function ERPTab() { const [cfgs, setCfgs] = useState([]) useEffect(() => { guardiaApi.get('/api/erp/config').then((r: any) => setCfgs(r.data || [])).catch(() => {}) }, []) return (

λ“±λ‘λœ ERP 연동 ({cfgs.length}개)

{cfgs.map((c: any) => ( 🏒
{c.name}
{c.erp_type} Β· {c.base_url}
))} {!cfgs.length &&

λ“±λ‘λœ 연동 μ—†μŒ

}
) } function KakaoTab() { const [cfg, setCfg] = useState(null) const [history, setHistory] = useState([]) useEffect(() => { guardiaApi.get('/api/kakao/config').then((r: any) => setCfg(r.data)).catch(() => {}) guardiaApi.get('/api/kakao/history').then((r: any) => setHistory(r.data || [])).catch(() => {}) }, []) return (

카카였 μ•Œλ¦Όν†‘

{cfg ?
βœ… 연동됨
λ°œμ‹ : {cfg.sender}
:

λ―Έμ„€μ •

}

λ°œμ†‘ 이λ ₯

{['ν…œν”Œλ¦Ώ', 'μˆ˜μ‹ ', 'κ²°κ³Ό', 'μ‹œκ°„'].map(h => )} {history.slice(0, 8).map((h: any) => ( ))} {!history.length && }
{h}
{h.template} {h.receivers}λͺ… {h.success ? '성곡' : 'μ‹€νŒ¨'} {h.sent_at ? new Date(h.sent_at).toLocaleDateString('ko-KR') : '-'}
이λ ₯ μ—†μŒ
) } function SSOTab() { const [configs, setConfigs] = useState([]) useEffect(() => { guardiaApi.get('/api/sso/config').then((r: any) => setConfigs(r.data || [])).catch(() => {}) }, []) return (

λ“±λ‘λœ SSO IdP ({configs.length}개)

{configs.map((c: any) => ( {c.provider_type === 'SAML' ? 'πŸ›οΈ' : 'πŸ”‘'}
{c.name}
{c.provider_type} Β· {c.is_active ? 'ν™œμ„±' : 'λΉ„ν™œμ„±'}
ν…ŒμŠ€νŠΈ β†’
))} {!configs.length &&

λ“±λ‘λœ IdP μ—†μŒ

}
) }