@mcp-shark/mcp-shark 1.4.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -645
- package/bin/mcp-shark.js +30 -36
- package/mcp-server/index.js +115 -0
- package/mcp-server/lib/auditor/audit.js +34 -42
- package/mcp-server/lib/common/error.js +1 -1
- package/mcp-server/lib/server/external/all.js +5 -6
- package/mcp-server/lib/server/external/config.js +1 -3
- package/mcp-server/lib/server/external/kv.js +21 -40
- package/mcp-server/lib/server/external/single/request.js +3 -6
- package/mcp-server/lib/server/external/single/run.js +8 -19
- package/mcp-server/lib/server/internal/handlers/prompts-get.js +5 -7
- package/mcp-server/lib/server/internal/handlers/prompts-list.js +5 -4
- package/mcp-server/lib/server/internal/handlers/resources-list.js +5 -4
- package/mcp-server/lib/server/internal/handlers/resources-read.js +5 -4
- package/mcp-server/lib/server/internal/handlers/tools-call.js +8 -10
- package/mcp-server/lib/server/internal/handlers/tools-list.js +6 -5
- package/mcp-server/lib/server/internal/run.js +5 -17
- package/mcp-server/lib/server/internal/server.js +14 -15
- package/mcp-server/lib/server/internal/session.js +8 -13
- package/mcp-server/mcp-shark.js +16 -66
- package/package.json +23 -38
- package/ui/dist/assets/index-Cc-IUa83.css +1 -0
- package/ui/dist/assets/index-srLDlk97.js +35 -0
- package/ui/dist/index.html +17 -0
- package/ui/dist/og-image.png +0 -0
- package/ui/server/routes/backups/deleteBackup.js +54 -0
- package/ui/server/routes/backups/index.js +15 -0
- package/ui/server/routes/backups/listBackups.js +75 -0
- package/ui/server/routes/backups/restoreBackup.js +83 -0
- package/ui/server/routes/backups/viewBackup.js +47 -0
- package/ui/server/routes/composite/index.js +46 -0
- package/ui/server/routes/composite/servers.js +18 -0
- package/ui/server/routes/composite/setup.js +129 -0
- package/ui/server/routes/composite/status.js +7 -0
- package/ui/server/routes/composite/stop.js +39 -0
- package/ui/server/routes/composite/utils.js +45 -0
- package/ui/server/routes/config.js +34 -30
- package/ui/server/routes/conversations.js +3 -3
- package/ui/server/routes/help.js +2 -2
- package/ui/server/routes/logs.js +5 -5
- package/ui/server/routes/playground.js +91 -62
- package/ui/server/routes/requests.js +112 -108
- package/ui/server/routes/sessions.js +4 -4
- package/ui/server/routes/settings.js +199 -0
- package/ui/server/routes/smartscan/discover.js +7 -6
- package/ui/server/routes/smartscan/scans/clearCache.js +3 -2
- package/ui/server/routes/smartscan/scans/createBatchScans.js +4 -3
- package/ui/server/routes/smartscan/scans/createScan.js +2 -1
- package/ui/server/routes/smartscan/scans/getCachedResults.js +2 -1
- package/ui/server/routes/smartscan/scans/getScan.js +2 -1
- package/ui/server/routes/smartscan/scans/listScans.js +5 -4
- package/ui/server/routes/smartscan/scans.js +3 -3
- package/ui/server/routes/smartscan/token.js +4 -3
- package/ui/server/routes/smartscan/transport.js +1 -1
- package/ui/server/routes/smartscan.js +1 -1
- package/ui/server/routes/statistics.js +13 -10
- package/ui/server/utils/config-update.js +140 -112
- package/ui/server/utils/config.js +4 -4
- package/ui/server/utils/logger.js +2 -0
- package/ui/server/utils/paths.js +210 -2
- package/ui/server/utils/port.js +2 -2
- package/ui/server/utils/process.js +0 -67
- package/ui/server/utils/scan-cache/all-results.js +76 -59
- package/ui/server/utils/scan-cache/directory.js +1 -1
- package/ui/server/utils/scan-cache/file-operations.js +19 -16
- package/ui/server/utils/scan-cache/server-operations.js +14 -9
- package/ui/server/utils/serialization.js +9 -3
- package/ui/server/utils/smartscan-token.js +4 -3
- package/ui/server.js +87 -41
- package/ui/src/App.jsx +5 -5
- package/ui/src/CompositeLogs.jsx +20 -20
- package/ui/src/CompositeSetup.jsx +9 -9
- package/ui/src/HelpGuide/HelpGuideFooter.jsx +1 -0
- package/ui/src/HelpGuide/HelpGuideHeader.jsx +2 -1
- package/ui/src/HelpGuide.jsx +17 -4
- package/ui/src/IntroTour.jsx +19 -5
- package/ui/src/LogDetail.jsx +1 -0
- package/ui/src/LogTable.jsx +24 -6
- package/ui/src/PacketDetail.jsx +21 -16
- package/ui/src/PacketFilters.jsx +29 -14
- package/ui/src/PacketList.jsx +4 -5
- package/ui/src/SmartScan.jsx +5 -5
- package/ui/src/TabNavigation.jsx +5 -5
- package/ui/src/components/App/HelpButton.jsx +4 -0
- package/ui/src/components/App/TrafficTab.jsx +4 -4
- package/ui/src/components/App/useAppState.js +118 -24
- package/ui/src/components/BackupList.jsx +6 -2
- package/ui/src/components/CollapsibleSection.jsx +16 -2
- package/ui/src/components/ConfigViewerModal.jsx +17 -3
- package/ui/src/components/ConfirmationModal.jsx +20 -3
- package/ui/src/components/DetailsTab/BodySection.jsx +3 -1
- package/ui/src/components/DetailsTab/CollapsibleRequestResponse.jsx +14 -3
- package/ui/src/components/DetailsTab/InfoSection.jsx +4 -2
- package/ui/src/components/DetailsTab/RequestDetailsSection.jsx +7 -5
- package/ui/src/components/DetailsTab/ResponseDetailsSection.jsx +7 -5
- package/ui/src/components/DetectedPathsList.jsx +5 -2
- package/ui/src/components/FileInput.jsx +3 -1
- package/ui/src/components/GroupHeader.jsx +14 -0
- package/ui/src/components/GroupedByMcpView.jsx +3 -10
- package/ui/src/components/GroupedByServerView.jsx +1 -1
- package/ui/src/components/GroupedBySessionView.jsx +1 -1
- package/ui/src/components/HexTab.jsx +17 -4
- package/ui/src/components/LogsToolbar.jsx +3 -1
- package/ui/src/components/McpPlayground/LoadingModal.jsx +7 -3
- package/ui/src/components/McpPlayground/PromptsSection/PromptCallPanel.jsx +5 -0
- package/ui/src/components/McpPlayground/PromptsSection/PromptItem.jsx +52 -23
- package/ui/src/components/McpPlayground/PromptsSection/PromptsList.jsx +13 -11
- package/ui/src/components/McpPlayground/PromptsSection.jsx +2 -1
- package/ui/src/components/McpPlayground/ResourcesSection/ResourceCallPanel.jsx +3 -0
- package/ui/src/components/McpPlayground/ResourcesSection/ResourceItem.jsx +66 -34
- package/ui/src/components/McpPlayground/ResourcesSection/ResourcesList.jsx +13 -11
- package/ui/src/components/McpPlayground/ResourcesSection.jsx +2 -1
- package/ui/src/components/McpPlayground/ToolsSection/ToolCallPanel.jsx +5 -0
- package/ui/src/components/McpPlayground/ToolsSection/ToolItem.jsx +52 -23
- package/ui/src/components/McpPlayground/ToolsSection/ToolsList.jsx +13 -11
- package/ui/src/components/McpPlayground/ToolsSection.jsx +2 -1
- package/ui/src/components/McpPlayground/hooks/useMcpDataLoader.js +107 -0
- package/ui/src/components/McpPlayground/hooks/useMcpRequest.js +70 -0
- package/ui/src/components/McpPlayground/hooks/useMcpServerStatus.js +90 -0
- package/ui/src/components/McpPlayground/useMcpPlayground.js +118 -159
- package/ui/src/components/McpPlayground.jsx +105 -23
- package/ui/src/components/PacketDetailHeader.jsx +8 -3
- package/ui/src/components/PacketFilters/ExportControls.jsx +2 -1
- package/ui/src/components/PacketFilters/FilterInput.jsx +1 -1
- package/ui/src/components/RawTab.jsx +15 -2
- package/ui/src/components/RequestRow/OrphanedResponseRow.jsx +10 -2
- package/ui/src/components/RequestRow/RequestRowMain.jsx +12 -3
- package/ui/src/components/RequestRow/ResponseRow.jsx +11 -3
- package/ui/src/components/RequestRow.jsx +17 -9
- package/ui/src/components/ServerControl.jsx +3 -1
- package/ui/src/components/ServiceSelector.jsx +2 -0
- package/ui/src/components/SmartScan/AnalysisResult.jsx +2 -2
- package/ui/src/components/SmartScan/BatchResultsDisplay/BatchResultItem.jsx +2 -1
- package/ui/src/components/SmartScan/BatchResultsDisplay/BatchResultsHeader.jsx +1 -1
- package/ui/src/components/SmartScan/BatchResultsDisplay.jsx +9 -3
- package/ui/src/components/SmartScan/EmptyState.jsx +3 -0
- package/ui/src/components/SmartScan/ErrorDisplay.jsx +4 -2
- package/ui/src/components/SmartScan/ExpandableSection.jsx +4 -0
- package/ui/src/components/SmartScan/FindingsTable.jsx +46 -42
- package/ui/src/components/SmartScan/ListViewContent.jsx +2 -2
- package/ui/src/components/SmartScan/NotablePatternsSection.jsx +13 -8
- package/ui/src/components/SmartScan/OverallSummarySection.jsx +36 -29
- package/ui/src/components/SmartScan/RecommendationsSection.jsx +10 -8
- package/ui/src/components/SmartScan/ScanDetailHeader.jsx +2 -1
- package/ui/src/components/SmartScan/ScanDetailView.jsx +4 -4
- package/ui/src/components/SmartScan/ScanListView/ScanListHeader.jsx +2 -1
- package/ui/src/components/SmartScan/ScanListView/ScanListItem.jsx +15 -1
- package/ui/src/components/SmartScan/ScanOverviewSection.jsx +3 -1
- package/ui/src/components/SmartScan/ScanResultsDisplay.jsx +1 -1
- package/ui/src/components/SmartScan/ScanViewContent.jsx +2 -2
- package/ui/src/components/SmartScan/ScanningProgress.jsx +4 -2
- package/ui/src/components/SmartScan/ServerInfoSection.jsx +3 -1
- package/ui/src/components/SmartScan/ServerSelectionRow.jsx +4 -2
- package/ui/src/components/SmartScan/SingleResultDisplay.jsx +5 -3
- package/ui/src/components/SmartScan/SmartScanControls.jsx +11 -7
- package/ui/src/components/SmartScan/SmartScanHeader.jsx +1 -1
- package/ui/src/components/SmartScan/ViewModeTabs.jsx +2 -0
- package/ui/src/components/SmartScan/hooks/useCacheManagement.js +1 -2
- package/ui/src/components/SmartScan/hooks/useMcpDiscovery.js +22 -26
- package/ui/src/components/SmartScan/hooks/useScanList.js +10 -9
- package/ui/src/components/SmartScan/hooks/useScanOperations.js +23 -14
- package/ui/src/components/SmartScan/hooks/useServerStatus.js +2 -2
- package/ui/src/components/SmartScan/hooks/useTokenManagement.js +2 -2
- package/ui/src/components/SmartScan/scanDataUtils.js +22 -17
- package/ui/src/components/SmartScan/useSmartScan.js +4 -4
- package/ui/src/components/SmartScan/utils.js +3 -1
- package/ui/src/components/SmartScanIcons.jsx +6 -3
- package/ui/src/components/TabNavigation/DesktopTabs.jsx +8 -3
- package/ui/src/components/TabNavigation/MobileDropdown.jsx +3 -1
- package/ui/src/components/TabNavigation.jsx +8 -3
- package/ui/src/components/TabNavigationIcons.jsx +4 -4
- package/ui/src/components/TourOverlay.jsx +1 -1
- package/ui/src/components/TourTooltip/TourTooltipButtons.jsx +3 -0
- package/ui/src/components/TourTooltip/TourTooltipHeader.jsx +1 -0
- package/ui/src/components/TourTooltip/TourTooltipIcons.jsx +9 -0
- package/ui/src/components/TourTooltip/useTooltipPosition.js +63 -36
- package/ui/src/components/TourTooltip.jsx +11 -3
- package/ui/src/components/ViewModeTabs.jsx +3 -1
- package/ui/src/config/tourSteps.jsx +0 -2
- package/ui/src/hooks/useAnimation.js +15 -12
- package/ui/src/hooks/useConfigManagement.js +8 -8
- package/ui/src/hooks/useServiceExtraction.js +1 -1
- package/ui/src/index.css +3 -8
- package/ui/src/theme.js +3 -3
- package/ui/src/utils/hexUtils.js +11 -5
- package/ui/src/utils/mcpGroupingUtils.js +18 -10
- package/ui/src/utils/requestPairing.js +89 -0
- package/ui/src/utils/requestUtils.js +37 -105
- package/ui/vite.config.js +1 -1
- package/mcp-server/.editorconfig +0 -15
- package/mcp-server/.prettierignore +0 -11
- package/mcp-server/.prettierrc +0 -12
- package/mcp-server/README.md +0 -280
- package/mcp-server/commitlint.config.cjs +0 -42
- package/mcp-server/eslint.config.js +0 -131
- package/mcp-server/package-lock.json +0 -4784
- package/mcp-server/package.json +0 -30
- package/ui/README.md +0 -212
- package/ui/package-lock.json +0 -3574
- package/ui/package.json +0 -12
- package/ui/paths.js +0 -282
- package/ui/server/routes/backups.js +0 -251
- package/ui/server/routes/composite.js +0 -244
package/ui/src/CompositeLogs.jsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { colors } from './theme';
|
|
3
|
-
import LogsToolbar from './components/LogsToolbar';
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
4
2
|
import LogsDisplay from './components/LogsDisplay';
|
|
3
|
+
import LogsToolbar from './components/LogsToolbar';
|
|
4
|
+
import { colors } from './theme';
|
|
5
5
|
|
|
6
6
|
function CompositeLogs() {
|
|
7
7
|
const [logs, setLogs] = useState([]);
|
|
@@ -11,27 +11,23 @@ function CompositeLogs() {
|
|
|
11
11
|
const logEndRef = useRef(null);
|
|
12
12
|
const wsRef = useRef(null);
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
useEffect(() => {
|
|
15
15
|
if (autoScroll && logEndRef.current) {
|
|
16
16
|
logEndRef.current.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
17
17
|
}
|
|
18
|
-
};
|
|
18
|
+
}, [autoScroll]);
|
|
19
19
|
|
|
20
20
|
useEffect(() => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
console.error('Failed to load logs:', error);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
21
|
+
const loadLogs = async () => {
|
|
22
|
+
try {
|
|
23
|
+
const response = await fetch('/api/composite/logs?limit=5000');
|
|
24
|
+
const data = await response.json();
|
|
25
|
+
setLogs(data);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error('Failed to load logs:', error);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
33
30
|
|
|
34
|
-
useEffect(() => {
|
|
35
31
|
loadLogs();
|
|
36
32
|
|
|
37
33
|
const wsUrl = import.meta.env.DEV
|
|
@@ -106,8 +102,12 @@ function CompositeLogs() {
|
|
|
106
102
|
};
|
|
107
103
|
|
|
108
104
|
const filteredLogs = logs.filter((log) => {
|
|
109
|
-
if (logType !== 'all' && log.type !== logType)
|
|
110
|
-
|
|
105
|
+
if (logType !== 'all' && log.type !== logType) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
if (filter && !log.line.toLowerCase().includes(filter.toLowerCase())) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
111
|
return true;
|
|
112
112
|
});
|
|
113
113
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { colors } from './theme';
|
|
3
|
-
import SetupHeader from './components/SetupHeader';
|
|
4
|
-
import ConfigFileSection from './components/ConfigFileSection';
|
|
5
|
-
import WhatThisDoesSection from './components/WhatThisDoesSection';
|
|
6
|
-
import ServerControl from './components/ServerControl';
|
|
7
|
-
import MessageDisplay from './components/MessageDisplay';
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
8
2
|
import BackupList from './components/BackupList';
|
|
3
|
+
import ConfigFileSection from './components/ConfigFileSection';
|
|
9
4
|
import ConfigViewerModal from './components/ConfigViewerModal';
|
|
10
|
-
import
|
|
5
|
+
import MessageDisplay from './components/MessageDisplay';
|
|
6
|
+
import ServerControl from './components/ServerControl';
|
|
7
|
+
import SetupHeader from './components/SetupHeader';
|
|
8
|
+
import WhatThisDoesSection from './components/WhatThisDoesSection';
|
|
11
9
|
import { useConfigManagement } from './hooks/useConfigManagement';
|
|
10
|
+
import { useServiceExtraction } from './hooks/useServiceExtraction';
|
|
11
|
+
import { colors } from './theme';
|
|
12
12
|
|
|
13
13
|
function CompositeSetup() {
|
|
14
14
|
const [fileContent, setFileContent] = useState('');
|
|
@@ -181,7 +181,7 @@ function CompositeSetup() {
|
|
|
181
181
|
if (res.ok) {
|
|
182
182
|
const msg = data.message || 'MCP Shark server stopped';
|
|
183
183
|
setMessage(
|
|
184
|
-
data.message
|
|
184
|
+
data.message?.includes('restored')
|
|
185
185
|
? 'MCP Shark server stopped and original config file restored'
|
|
186
186
|
: msg
|
|
187
187
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { colors, fonts } from '../theme';
|
|
2
1
|
import { IconHelp, IconX } from '@tabler/icons-react';
|
|
2
|
+
import { colors, fonts } from '../theme';
|
|
3
3
|
|
|
4
4
|
export default function HelpGuideHeader({ onClose }) {
|
|
5
5
|
return (
|
|
@@ -29,6 +29,7 @@ export default function HelpGuideHeader({ onClose }) {
|
|
|
29
29
|
</h2>
|
|
30
30
|
</div>
|
|
31
31
|
<button
|
|
32
|
+
type="button"
|
|
32
33
|
onClick={onClose}
|
|
33
34
|
style={{
|
|
34
35
|
background: 'transparent',
|
package/ui/src/HelpGuide.jsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
|
-
import { colors } from './theme';
|
|
3
|
-
import HelpGuideHeader from './HelpGuide/HelpGuideHeader';
|
|
4
2
|
import HelpGuideContent from './HelpGuide/HelpGuideContent';
|
|
5
3
|
import HelpGuideFooter from './HelpGuide/HelpGuideFooter';
|
|
4
|
+
import HelpGuideHeader from './HelpGuide/HelpGuideHeader';
|
|
5
|
+
import { colors } from './theme';
|
|
6
6
|
|
|
7
7
|
function HelpGuide({ onClose }) {
|
|
8
8
|
const [dontShowAgain, setDontShowAgain] = useState(false);
|
|
@@ -19,7 +19,9 @@ function HelpGuide({ onClose }) {
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
return (
|
|
22
|
-
<
|
|
22
|
+
<dialog
|
|
23
|
+
open
|
|
24
|
+
aria-modal="true"
|
|
23
25
|
style={{
|
|
24
26
|
position: 'fixed',
|
|
25
27
|
top: 0,
|
|
@@ -32,10 +34,20 @@ function HelpGuide({ onClose }) {
|
|
|
32
34
|
alignItems: 'center',
|
|
33
35
|
justifyContent: 'center',
|
|
34
36
|
padding: '20px',
|
|
37
|
+
border: 'none',
|
|
38
|
+
margin: 0,
|
|
39
|
+
width: '100%',
|
|
40
|
+
height: '100%',
|
|
35
41
|
}}
|
|
36
42
|
onClick={handleClose}
|
|
43
|
+
onKeyDown={(e) => {
|
|
44
|
+
if (e.key === 'Escape') {
|
|
45
|
+
handleClose();
|
|
46
|
+
}
|
|
47
|
+
}}
|
|
37
48
|
>
|
|
38
49
|
<div
|
|
50
|
+
role="document"
|
|
39
51
|
style={{
|
|
40
52
|
background: colors.bgCard,
|
|
41
53
|
border: `1px solid ${colors.borderLight}`,
|
|
@@ -47,6 +59,7 @@ function HelpGuide({ onClose }) {
|
|
|
47
59
|
boxShadow: '0 8px 32px rgba(0, 0, 0, 0.5)',
|
|
48
60
|
}}
|
|
49
61
|
onClick={(e) => e.stopPropagation()}
|
|
62
|
+
onKeyDown={(e) => e.stopPropagation()}
|
|
50
63
|
>
|
|
51
64
|
<HelpGuideHeader onClose={handleClose} />
|
|
52
65
|
<div style={{ padding: '24px' }}>
|
|
@@ -58,7 +71,7 @@ function HelpGuide({ onClose }) {
|
|
|
58
71
|
/>
|
|
59
72
|
</div>
|
|
60
73
|
</div>
|
|
61
|
-
</
|
|
74
|
+
</dialog>
|
|
62
75
|
);
|
|
63
76
|
}
|
|
64
77
|
|
package/ui/src/IntroTour.jsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
2
|
import TourOverlay from './components/TourOverlay';
|
|
3
3
|
import TourTooltip from './components/TourTooltip';
|
|
4
4
|
|
|
@@ -9,7 +9,9 @@ function IntroTour({ steps, onComplete, onSkip, onStepChange }) {
|
|
|
9
9
|
const overlayRef = useRef(null);
|
|
10
10
|
|
|
11
11
|
useEffect(() => {
|
|
12
|
-
if (!highlightedElement)
|
|
12
|
+
if (!highlightedElement) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
13
15
|
|
|
14
16
|
const updatePosition = () => {
|
|
15
17
|
if (highlightedElement) {
|
|
@@ -31,10 +33,14 @@ function IntroTour({ steps, onComplete, onSkip, onStepChange }) {
|
|
|
31
33
|
}, [highlightedElement]);
|
|
32
34
|
|
|
33
35
|
useEffect(() => {
|
|
34
|
-
if (steps.length === 0)
|
|
36
|
+
if (steps.length === 0) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
35
39
|
|
|
36
40
|
const step = steps[currentStep];
|
|
37
|
-
if (!step)
|
|
41
|
+
if (!step) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
38
44
|
|
|
39
45
|
if (onStepChange) {
|
|
40
46
|
onStepChange(currentStep);
|
|
@@ -95,7 +101,9 @@ function IntroTour({ steps, onComplete, onSkip, onStepChange }) {
|
|
|
95
101
|
|
|
96
102
|
const handleSkip = () => {
|
|
97
103
|
handleComplete();
|
|
98
|
-
if (onSkip)
|
|
104
|
+
if (onSkip) {
|
|
105
|
+
onSkip();
|
|
106
|
+
}
|
|
99
107
|
};
|
|
100
108
|
|
|
101
109
|
if (steps.length === 0 || currentStep >= steps.length) {
|
|
@@ -108,6 +116,7 @@ function IntroTour({ steps, onComplete, onSkip, onStepChange }) {
|
|
|
108
116
|
<>
|
|
109
117
|
<div
|
|
110
118
|
ref={overlayRef}
|
|
119
|
+
role="presentation"
|
|
111
120
|
style={{
|
|
112
121
|
position: 'fixed',
|
|
113
122
|
top: 0,
|
|
@@ -118,6 +127,11 @@ function IntroTour({ steps, onComplete, onSkip, onStepChange }) {
|
|
|
118
127
|
pointerEvents: 'auto',
|
|
119
128
|
}}
|
|
120
129
|
onClick={handleSkip}
|
|
130
|
+
onKeyDown={(e) => {
|
|
131
|
+
if (e.key === 'Escape') {
|
|
132
|
+
handleSkip();
|
|
133
|
+
}
|
|
134
|
+
}}
|
|
121
135
|
>
|
|
122
136
|
<TourOverlay elementRect={elementRect} />
|
|
123
137
|
</div>
|
package/ui/src/LogDetail.jsx
CHANGED
package/ui/src/LogTable.jsx
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import { colors, fonts
|
|
1
|
+
import { colors, fonts } from './theme';
|
|
2
2
|
|
|
3
3
|
function LogTable({ logs, selected, onSelect }) {
|
|
4
4
|
const getStatusColor = (status) => {
|
|
5
|
-
if (status === 'error')
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
if (status === 'error') {
|
|
6
|
+
return colors.error;
|
|
7
|
+
}
|
|
8
|
+
if (status === 'success') {
|
|
9
|
+
return colors.success;
|
|
10
|
+
}
|
|
11
|
+
if (status === 'pending') {
|
|
12
|
+
return colors.warning;
|
|
13
|
+
}
|
|
8
14
|
return colors.textTertiary;
|
|
9
15
|
};
|
|
10
16
|
|
|
@@ -144,6 +150,14 @@ function LogTable({ logs, selected, onSelect }) {
|
|
|
144
150
|
<tr
|
|
145
151
|
key={log.id}
|
|
146
152
|
onClick={() => onSelect(log)}
|
|
153
|
+
onKeyDown={(e) => {
|
|
154
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
155
|
+
e.preventDefault();
|
|
156
|
+
onSelect(log);
|
|
157
|
+
}
|
|
158
|
+
}}
|
|
159
|
+
tabIndex={0}
|
|
160
|
+
aria-label={`Select log entry ${log.id}`}
|
|
147
161
|
style={{
|
|
148
162
|
cursor: 'pointer',
|
|
149
163
|
background: selected?.id === log.id ? colors.bgSelected : colors.bgCard,
|
|
@@ -151,10 +165,14 @@ function LogTable({ logs, selected, onSelect }) {
|
|
|
151
165
|
transition: 'background-color 0.15s ease',
|
|
152
166
|
}}
|
|
153
167
|
onMouseEnter={(e) => {
|
|
154
|
-
if (selected?.id !== log.id)
|
|
168
|
+
if (selected?.id !== log.id) {
|
|
169
|
+
e.currentTarget.style.background = colors.bgHover;
|
|
170
|
+
}
|
|
155
171
|
}}
|
|
156
172
|
onMouseLeave={(e) => {
|
|
157
|
-
if (selected?.id !== log.id)
|
|
173
|
+
if (selected?.id !== log.id) {
|
|
174
|
+
e.currentTarget.style.background = colors.bgCard;
|
|
175
|
+
}
|
|
158
176
|
}}
|
|
159
177
|
>
|
|
160
178
|
<td
|
package/ui/src/PacketDetail.jsx
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { colors, fonts } from './theme';
|
|
3
|
-
import PacketDetailHeader from './components/PacketDetailHeader';
|
|
4
|
-
import TabNavigation from './components/TabNavigation';
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
5
2
|
import DetailsTab from './components/DetailsTab';
|
|
6
3
|
import HexTab from './components/HexTab';
|
|
4
|
+
import PacketDetailHeader from './components/PacketDetailHeader';
|
|
7
5
|
import RawTab from './components/RawTab';
|
|
8
|
-
import
|
|
6
|
+
import TabNavigation from './components/TabNavigation';
|
|
7
|
+
import { colors } from './theme';
|
|
9
8
|
import { fadeIn } from './utils/animations';
|
|
9
|
+
import { createFullRequestText, generateHexDump } from './utils/hexUtils.js';
|
|
10
10
|
|
|
11
11
|
function RequestDetail({ request, onClose, requests = [] }) {
|
|
12
12
|
const [activeTab, setActiveTab] = useState('details');
|
|
@@ -20,7 +20,9 @@ function RequestDetail({ request, onClose, requests = [] }) {
|
|
|
20
20
|
}
|
|
21
21
|
}, [activeTab]);
|
|
22
22
|
|
|
23
|
-
if (!request)
|
|
23
|
+
if (!request) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
24
26
|
|
|
25
27
|
// Helper function to extract JSON-RPC method
|
|
26
28
|
const getJsonRpcMethod = (req) => {
|
|
@@ -38,7 +40,7 @@ function RequestDetail({ request, onClose, requests = [] }) {
|
|
|
38
40
|
if (body && typeof body === 'object' && body.method) {
|
|
39
41
|
return body.method;
|
|
40
42
|
}
|
|
41
|
-
} catch (
|
|
43
|
+
} catch (_e) {
|
|
42
44
|
// Failed to parse
|
|
43
45
|
}
|
|
44
46
|
}
|
|
@@ -48,7 +50,7 @@ function RequestDetail({ request, onClose, requests = [] }) {
|
|
|
48
50
|
if (body && typeof body === 'object' && body.method) {
|
|
49
51
|
return body.method;
|
|
50
52
|
}
|
|
51
|
-
} catch (
|
|
53
|
+
} catch (_e) {
|
|
52
54
|
// Failed to parse
|
|
53
55
|
}
|
|
54
56
|
}
|
|
@@ -61,7 +63,9 @@ function RequestDetail({ request, onClose, requests = [] }) {
|
|
|
61
63
|
const findMatchingPair = () => {
|
|
62
64
|
const matches = (req, resp) => {
|
|
63
65
|
// Session ID must match
|
|
64
|
-
if (req.session_id !== resp.session_id)
|
|
66
|
+
if (req.session_id !== resp.session_id) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
65
69
|
|
|
66
70
|
// JSON-RPC Method must match
|
|
67
71
|
const reqMethod = getJsonRpcMethod(req);
|
|
@@ -78,7 +82,9 @@ function RequestDetail({ request, onClose, requests = [] }) {
|
|
|
78
82
|
return false;
|
|
79
83
|
}
|
|
80
84
|
|
|
81
|
-
if (reqMethod !== respMethod)
|
|
85
|
+
if (reqMethod !== respMethod) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
82
88
|
|
|
83
89
|
// If JSON-RPC ID exists, it must match
|
|
84
90
|
if (req.jsonrpc_id && resp.jsonrpc_id) {
|
|
@@ -94,13 +100,12 @@ function RequestDetail({ request, onClose, requests = [] }) {
|
|
|
94
100
|
(r) =>
|
|
95
101
|
r.direction === 'response' && matches(request, r) && r.frame_number > request.frame_number
|
|
96
102
|
);
|
|
97
|
-
} else {
|
|
98
|
-
// Find the corresponding request
|
|
99
|
-
return requests.find(
|
|
100
|
-
(r) =>
|
|
101
|
-
r.direction === 'request' && matches(r, request) && r.frame_number < request.frame_number
|
|
102
|
-
);
|
|
103
103
|
}
|
|
104
|
+
// Find the corresponding request
|
|
105
|
+
return requests.find(
|
|
106
|
+
(r) =>
|
|
107
|
+
r.direction === 'request' && matches(r, request) && r.frame_number < request.frame_number
|
|
108
|
+
);
|
|
104
109
|
};
|
|
105
110
|
|
|
106
111
|
const matchingPair = findMatchingPair();
|
package/ui/src/PacketFilters.jsx
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
import { IconSearch, IconTrash } from '@tabler/icons-react';
|
|
2
|
+
import anime from 'animejs';
|
|
1
3
|
import { useEffect, useRef, useState } from 'react';
|
|
4
|
+
import ConfirmationModal from './components/ConfirmationModal';
|
|
5
|
+
import ExportControls from './components/PacketFilters/ExportControls';
|
|
6
|
+
import FilterInput from './components/PacketFilters/FilterInput';
|
|
2
7
|
import { colors, fonts } from './theme';
|
|
3
8
|
import { fadeIn } from './utils/animations';
|
|
4
|
-
import FilterInput from './components/PacketFilters/FilterInput';
|
|
5
|
-
import ExportControls from './components/PacketFilters/ExportControls';
|
|
6
|
-
import ConfirmationModal from './components/ConfirmationModal';
|
|
7
|
-
import { IconTrash, IconSearch } from '@tabler/icons-react';
|
|
8
|
-
import anime from 'animejs';
|
|
9
9
|
|
|
10
|
-
function RequestFilters({ filters, onFilterChange, stats,
|
|
10
|
+
function RequestFilters({ filters, onFilterChange, stats, onClear }) {
|
|
11
11
|
const filtersRef = useRef(null);
|
|
12
12
|
const [showClearModal, setShowClearModal] = useState(false);
|
|
13
13
|
|
|
@@ -20,13 +20,27 @@ function RequestFilters({ filters, onFilterChange, stats, onExport, onClear }) {
|
|
|
20
20
|
const handleExport = async (format = 'json') => {
|
|
21
21
|
try {
|
|
22
22
|
const queryParams = new URLSearchParams();
|
|
23
|
-
if (filters.search)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (filters.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (filters.
|
|
23
|
+
if (filters.search) {
|
|
24
|
+
queryParams.append('search', filters.search);
|
|
25
|
+
}
|
|
26
|
+
if (filters.serverName) {
|
|
27
|
+
queryParams.append('serverName', filters.serverName);
|
|
28
|
+
}
|
|
29
|
+
if (filters.sessionId) {
|
|
30
|
+
queryParams.append('sessionId', filters.sessionId);
|
|
31
|
+
}
|
|
32
|
+
if (filters.method) {
|
|
33
|
+
queryParams.append('method', filters.method);
|
|
34
|
+
}
|
|
35
|
+
if (filters.jsonrpcMethod) {
|
|
36
|
+
queryParams.append('jsonrpcMethod', filters.jsonrpcMethod);
|
|
37
|
+
}
|
|
38
|
+
if (filters.statusCode) {
|
|
39
|
+
queryParams.append('statusCode', filters.statusCode);
|
|
40
|
+
}
|
|
41
|
+
if (filters.jsonrpcId) {
|
|
42
|
+
queryParams.append('jsonrpcId', filters.jsonrpcId);
|
|
43
|
+
}
|
|
30
44
|
queryParams.append('format', format);
|
|
31
45
|
|
|
32
46
|
const response = await fetch(`/api/requests/export?${queryParams}`);
|
|
@@ -127,7 +141,7 @@ function RequestFilters({ filters, onFilterChange, stats, onExport, onClear }) {
|
|
|
127
141
|
onChange={(e) =>
|
|
128
142
|
onFilterChange({
|
|
129
143
|
...filters,
|
|
130
|
-
statusCode: e.target.value ? parseInt(e.target.value) : null,
|
|
144
|
+
statusCode: e.target.value ? Number.parseInt(e.target.value) : null,
|
|
131
145
|
})
|
|
132
146
|
}
|
|
133
147
|
style={{ width: '120px' }}
|
|
@@ -144,6 +158,7 @@ function RequestFilters({ filters, onFilterChange, stats, onExport, onClear }) {
|
|
|
144
158
|
<ExportControls stats={stats} onExport={handleExport} />
|
|
145
159
|
|
|
146
160
|
<button
|
|
161
|
+
type="button"
|
|
147
162
|
onClick={() => setShowClearModal(true)}
|
|
148
163
|
style={{
|
|
149
164
|
padding: '8px 14px',
|
package/ui/src/PacketList.jsx
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import GroupedByMcpView from './components/GroupedByMcpView';
|
|
3
3
|
import RequestRow from './components/RequestRow';
|
|
4
4
|
import TableHeader from './components/TableHeader';
|
|
5
5
|
import ViewModeTabs from './components/ViewModeTabs';
|
|
6
|
-
import
|
|
6
|
+
import { colors, fonts } from './theme';
|
|
7
|
+
import { staggerIn } from './utils/animations';
|
|
7
8
|
import { groupByMcpSessionAndCategory } from './utils/mcpGroupingUtils.js';
|
|
8
9
|
import { pairRequestsWithResponses } from './utils/requestUtils.js';
|
|
9
|
-
import { staggerIn } from './utils/animations';
|
|
10
|
-
import anime from 'animejs';
|
|
11
10
|
|
|
12
11
|
function RequestList({ requests, selected, onSelect, firstRequestTime }) {
|
|
13
12
|
const [viewMode, setViewMode] = useState('general');
|
package/ui/src/SmartScan.jsx
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import ListViewContent from './components/SmartScan/ListViewContent';
|
|
3
|
+
import ScanViewContent from './components/SmartScan/ScanViewContent';
|
|
4
4
|
import SmartScanControls from './components/SmartScan/SmartScanControls';
|
|
5
|
+
import SmartScanHeader from './components/SmartScan/SmartScanHeader';
|
|
5
6
|
import ViewModeTabs from './components/SmartScan/ViewModeTabs';
|
|
6
|
-
import ScanViewContent from './components/SmartScan/ScanViewContent';
|
|
7
|
-
import ListViewContent from './components/SmartScan/ListViewContent';
|
|
8
7
|
import { useSmartScan } from './components/SmartScan/useSmartScan';
|
|
8
|
+
import { colors } from './theme';
|
|
9
9
|
|
|
10
10
|
function SmartScan() {
|
|
11
11
|
const [viewMode, setViewMode] = useState('scan'); // 'scan' or 'list'
|
|
@@ -151,7 +151,7 @@ function SmartScan() {
|
|
|
151
151
|
const serverName =
|
|
152
152
|
matchingScan?.serverName || scanData.serverName || 'Unknown Server';
|
|
153
153
|
|
|
154
|
-
if (scanData
|
|
154
|
+
if (scanData?.data && typeof scanData.data === 'object') {
|
|
155
155
|
const actualScan = scanData.data;
|
|
156
156
|
setSelectedScan({
|
|
157
157
|
...actualScan,
|
package/ui/src/TabNavigation.jsx
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { colors, fonts } from './theme';
|
|
3
2
|
import { SharkLogo } from './components/SharkLogo';
|
|
3
|
+
import DesktopTabs from './components/TabNavigation/DesktopTabs';
|
|
4
|
+
import MobileDropdown from './components/TabNavigation/MobileDropdown';
|
|
4
5
|
import {
|
|
5
|
-
NetworkIcon,
|
|
6
6
|
LogsIcon,
|
|
7
|
-
|
|
7
|
+
NetworkIcon,
|
|
8
8
|
PlaygroundIcon,
|
|
9
|
+
SettingsIcon,
|
|
9
10
|
ShieldIcon,
|
|
10
11
|
} from './components/TabNavigationIcons';
|
|
11
|
-
import
|
|
12
|
-
import DesktopTabs from './components/TabNavigation/DesktopTabs';
|
|
12
|
+
import { colors, fonts } from './theme';
|
|
13
13
|
|
|
14
14
|
function TabNavigation({ activeTab, onTabChange }) {
|
|
15
15
|
const tabs = [
|
|
@@ -10,7 +10,10 @@ const TourIcon = ({ size = 16, color = 'currentColor' }) => (
|
|
|
10
10
|
strokeWidth="2"
|
|
11
11
|
strokeLinecap="round"
|
|
12
12
|
strokeLinejoin="round"
|
|
13
|
+
role="img"
|
|
14
|
+
aria-label="Tour icon"
|
|
13
15
|
>
|
|
16
|
+
<title>Tour icon</title>
|
|
14
17
|
<path d="M12 2L2 7l10 5 10-5-10-5z" />
|
|
15
18
|
<path d="M2 17l10 5 10-5" />
|
|
16
19
|
<path d="M2 12l10 5 10-5" />
|
|
@@ -20,6 +23,7 @@ const TourIcon = ({ size = 16, color = 'currentColor' }) => (
|
|
|
20
23
|
export default function HelpButton({ onClick }) {
|
|
21
24
|
return (
|
|
22
25
|
<button
|
|
26
|
+
type="button"
|
|
23
27
|
onClick={onClick}
|
|
24
28
|
data-tour="help-button"
|
|
25
29
|
style={{
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { colors } from '../../theme';
|
|
3
|
-
import { slideInRight } from '../../utils/animations';
|
|
4
|
-
import RequestList from '../../PacketList';
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
5
2
|
import RequestDetail from '../../PacketDetail';
|
|
6
3
|
import RequestFilters from '../../PacketFilters';
|
|
4
|
+
import RequestList from '../../PacketList';
|
|
5
|
+
import { colors } from '../../theme';
|
|
6
|
+
import { slideInRight } from '../../utils/animations';
|
|
7
7
|
|
|
8
8
|
export default function TrafficTab({
|
|
9
9
|
requests,
|