@mcp-shark/mcp-shark
Version:
Aggregate multiple Model Context Protocol (MCP) servers into a single unified interface with a powerful monitoring UI. Prov deep visibility into every request and response.
270 lines (263 loc) • 7.57 kB
JSX
import { ExternalLinkIcon } from '../SmartScanIcons';
import { colors, fonts } from '../../theme';
import { getRiskLevelColor } from './utils';
export default function SingleResultDisplay({ scanResult }) {
if (!scanResult) return null;
return (
<div
style={{
background: colors.bgCard,
border: `1px solid ${colors.borderLight}`,
borderRadius: '8px',
padding: '20px',
boxShadow: `0 1px 3px ${colors.shadowSm}`,
}}
>
<h2
style={{
fontSize: '16px',
fontWeight: '600',
color: colors.textPrimary,
fontFamily: fonts.body,
marginBottom: '16px',
}}
>
Scan Results
</h2>
{/* Overall Risk */}
{scanResult.data?.overall_risk_level && (
<div
style={{
background: colors.bgTertiary,
border: `1px solid ${colors.borderLight}`,
borderRadius: '8px',
padding: '16px',
marginBottom: '20px',
}}
>
<div
style={{
display: 'flex',
alignItems: 'center',
gap: '12px',
marginBottom: '8px',
}}
>
<span
style={{
padding: '4px 12px',
borderRadius: '6px',
fontSize: '12px',
fontWeight: '700',
fontFamily: fonts.body,
background: getRiskLevelColor(scanResult.data.overall_risk_level),
color: colors.textInverse,
}}
>
{scanResult.data.overall_risk_level.toUpperCase()}
</span>
<span
style={{
fontSize: '14px',
color: colors.textSecondary,
fontFamily: fonts.body,
}}
>
Overall Risk Level
</span>
</div>
{scanResult.data.overall_reason && (
<p
style={{
fontSize: '13px',
color: colors.textSecondary,
fontFamily: fonts.body,
margin: 0,
}}
>
{scanResult.data.overall_reason}
</p>
)}
</div>
)}
{/* Findings Summary */}
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
gap: '12px',
marginBottom: '20px',
}}
>
{scanResult.data?.tool_findings?.length > 0 && (
<div
style={{
background: colors.bgTertiary,
border: `1px solid ${colors.borderLight}`,
borderRadius: '8px',
padding: '12px',
}}
>
<div
style={{
fontSize: '24px',
fontWeight: '700',
color: colors.textPrimary,
fontFamily: fonts.body,
}}
>
{scanResult.data.tool_findings.length}
</div>
<div
style={{
fontSize: '12px',
color: colors.textSecondary,
fontFamily: fonts.body,
}}
>
Tool Findings
</div>
</div>
)}
{scanResult.data?.resource_findings?.length > 0 && (
<div
style={{
background: colors.bgTertiary,
border: `1px solid ${colors.borderLight}`,
borderRadius: '8px',
padding: '12px',
}}
>
<div
style={{
fontSize: '24px',
fontWeight: '700',
color: colors.textPrimary,
fontFamily: fonts.body,
}}
>
{scanResult.data.resource_findings.length}
</div>
<div
style={{
fontSize: '12px',
color: colors.textSecondary,
fontFamily: fonts.body,
}}
>
Resource Findings
</div>
</div>
)}
{scanResult.data?.prompt_findings?.length > 0 && (
<div
style={{
background: colors.bgTertiary,
border: `1px solid ${colors.borderLight}`,
borderRadius: '8px',
padding: '12px',
}}
>
<div
style={{
fontSize: '24px',
fontWeight: '700',
color: colors.textPrimary,
fontFamily: fonts.body,
}}
>
{scanResult.data.prompt_findings.length}
</div>
<div
style={{
fontSize: '12px',
color: colors.textSecondary,
fontFamily: fonts.body,
}}
>
Prompt Findings
</div>
</div>
)}
</div>
{/* Recommendations */}
{scanResult.data?.recommendations?.length > 0 && (
<div
style={{
background: colors.bgTertiary,
border: `1px solid ${colors.borderLight}`,
borderRadius: '8px',
padding: '16px',
marginBottom: '20px',
}}
>
<h3
style={{
fontSize: '14px',
fontWeight: '600',
color: colors.textPrimary,
fontFamily: fonts.body,
marginBottom: '12px',
}}
>
Recommendations
</h3>
<ul
style={{
margin: 0,
paddingLeft: '20px',
fontSize: '13px',
color: colors.textSecondary,
fontFamily: fonts.body,
lineHeight: '1.8',
}}
>
{scanResult.data.recommendations.map((rec, idx) => (
<li key={idx}>{rec}</li>
))}
</ul>
</div>
)}
{/* View Full Results Link */}
{scanResult.scan_id && (
<div
style={{
marginTop: '20px',
paddingTop: '20px',
borderTop: `1px solid ${colors.borderLight}`,
}}
>
<a
href={`https://smart.mcpshark.sh/scan-results?id=${scanResult.scan_id}`}
target="_blank"
rel="noopener noreferrer"
style={{
display: 'inline-flex',
alignItems: 'center',
gap: '8px',
padding: '10px 20px',
background: colors.buttonSecondary,
color: colors.textPrimary,
border: `1px solid ${colors.borderMedium}`,
borderRadius: '8px',
textDecoration: 'none',
fontSize: '13px',
fontWeight: '600',
fontFamily: fonts.body,
transition: 'all 0.2s ease',
}}
onMouseEnter={(e) => {
e.currentTarget.style.background = colors.buttonSecondaryHover;
}}
onMouseLeave={(e) => {
e.currentTarget.style.background = colors.buttonSecondary;
}}
>
<span>View Full Results</span>
<ExternalLinkIcon size={14} color={colors.textPrimary} />
</a>
</div>
)}
</div>
);
}