whistle.mock-plugins 1.3.1 → 1.4.0-beta.2
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/VERSION.md +29 -0
- package/app/cgi-bin/interfaces.js +2 -0
- package/app/cgi-bin/settings.js +1 -0
- package/app/cgi-bin/stats.js +22 -12
- package/app/cgi-bin/webdav.js +56 -0
- package/app/public/index.html +1 -1
- package/app/public/js/11.index.js +2 -0
- package/app/public/js/11.index.js.LICENSE.txt +5 -0
- package/app/public/js/704.index.js +2 -0
- package/app/public/js/704.index.js.LICENSE.txt +1 -0
- package/app/public/js/798.index.js +2 -0
- package/app/public/js/798.index.js.LICENSE.txt +53 -0
- package/app/public/js/807.index.js +2 -0
- package/app/public/js/807.index.js.LICENSE.txt +1 -0
- package/app/public/js/968.index.js +2 -0
- package/app/public/js/968.index.js.LICENSE.txt +12 -0
- package/app/public/js/index.js +1 -1
- package/app/public/js/index.js.LICENSE.txt +0 -173
- package/lib/routes/settings.js +1 -0
- package/lib/webdav-sync.js +806 -0
- package/package.json +9 -2
- package/API.md +0 -247
- package/COLUMN_RESIZE_IMPLEMENTATION.md +0 -162
- package/FEATURE_ENHANCEMENT.md +0 -157
- package/TEST_GUIDE.md +0 -156
- package/data/features.json +0 -1
- package/data/interfaces.json +0 -1
- package/index.html +0 -52
- package/initialize.js +0 -32
- package/public/bundle.js +0 -2
- package/public/bundle.js.LICENSE.txt +0 -38
- package/public/index.html +0 -1
- package/public/plugin.mock-plugin.html +0 -14
- package/rules.txt +0 -22
- package/ui/src/App.css +0 -173
- package/ui/src/components/AppLayout.js +0 -407
- package/ui/src/components/FeatureCard.js +0 -58
- package/ui/src/components/KeyboardShortcutsHelp.js +0 -58
- package/ui/src/components/Layout.js +0 -94
- package/ui/src/components/MainNav.js +0 -42
- package/ui/src/components/PageContainer.js +0 -16
- package/ui/src/components/VersionModal.js +0 -99
- package/ui/src/components/interface-management/DataManagementDrawer.js +0 -115
- package/ui/src/components/interface-management/DataManagementModal.js +0 -110
- package/ui/src/components/interface-management/InterfaceTestModal.js +0 -313
- package/ui/src/components/interface-management/PreviewModal.js +0 -48
- package/ui/src/components/interface-management/README.md +0 -184
- package/ui/src/components/interface-management/RealResponseRecorder.js +0 -165
- package/ui/src/components/interface-management/ResponseContentEditor.js +0 -645
- package/ui/src/components/interface-management/constants.js +0 -36
- package/ui/src/components/interface-management/index.js +0 -7
- package/ui/src/components/interface-management/utils.js +0 -103
- package/ui/src/hooks/useKeyboardShortcuts.js +0 -99
- package/ui/src/index.html +0 -14
- package/ui/src/index.js +0 -50
- package/ui/src/pages/InterfaceManagementV2.js +0 -2351
- package/ui/src/pages/MockDataV2.js +0 -1089
- package/ui/src/pages/Settings.js +0 -299
- package/ui/src/pages/Sniffer.js +0 -521
- package/ui/src/pages/Stats.js +0 -288
- package/ui/src/services/del_api.js +0 -192
- package/ui/src/styles/app-layout.css +0 -373
- package/ui/src/styles/cyber-theme.css +0 -1234
- package/ui/src/styles/earth-theme.css +0 -618
- package/ui/src/styles/global.css +0 -224
- package/ui/src/styles/interface-management.css +0 -1321
- package/ui/src/styles/mock-data.css +0 -1185
- package/ui/src/styles/settings.css +0 -252
- package/ui/src/styles/version-modal.css +0 -116
- package/webpack.config.js +0 -54
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
3
|
-
|
|
4
|
-
// 清理JSON响应
|
|
5
|
-
export const cleanJsonResponse = (jsonStr) => {
|
|
6
|
-
try {
|
|
7
|
-
const parsed = JSON.parse(jsonStr);
|
|
8
|
-
return JSON.stringify(parsed);
|
|
9
|
-
} catch (e) {
|
|
10
|
-
return jsonStr;
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
// 验证URL是否合法
|
|
15
|
-
export const isValidUrl = (url) => {
|
|
16
|
-
if (!url) return false;
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
new URL(url);
|
|
20
|
-
return true;
|
|
21
|
-
} catch (e) {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
// 缓存刷新服务
|
|
27
|
-
export const flushCache = async () => {
|
|
28
|
-
try {
|
|
29
|
-
const response = await axios.get('/_flush_cache');
|
|
30
|
-
return response.data;
|
|
31
|
-
} catch (error) {
|
|
32
|
-
console.error('刷新缓存失败:', error);
|
|
33
|
-
throw error;
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
// 更新成功后刷新缓存
|
|
38
|
-
export const refreshCacheAfterUpdate = async () => {
|
|
39
|
-
try {
|
|
40
|
-
await flushCache();
|
|
41
|
-
// 这里不需要显示提示,因为主要操作会有自己的提示
|
|
42
|
-
} catch (error) {
|
|
43
|
-
// 如果刷新缓存失败,记录错误但不影响用户体验
|
|
44
|
-
console.error('刷新缓存失败,可能需要等待缓存自动过期:', error);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
// 检查 URL 是否匹配模式
|
|
49
|
-
export const isUrlMatchPattern = (url, pattern, proxyType) => {
|
|
50
|
-
if (!url || !pattern) return false;
|
|
51
|
-
|
|
52
|
-
try {
|
|
53
|
-
// 对于url_redirect类型,需要完全匹配
|
|
54
|
-
if (proxyType === 'url_redirect') {
|
|
55
|
-
return url === pattern;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// 对于redirect类型,只要url以pattern开头即可命中(前缀匹配)
|
|
59
|
-
if (proxyType === 'redirect') {
|
|
60
|
-
return url.indexOf(pattern) === 0;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// 以下是默认的匹配逻辑(用于response类型等)
|
|
64
|
-
// 如果是正则表达式
|
|
65
|
-
if (pattern.startsWith('/') && pattern.endsWith('/')) {
|
|
66
|
-
const regex = new RegExp(pattern.slice(1, -1));
|
|
67
|
-
return regex.test(url);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// 如果是通配符模式
|
|
71
|
-
if (pattern.includes('*')) {
|
|
72
|
-
const regexPattern = pattern
|
|
73
|
-
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
74
|
-
.replace(/\*/g, '.*');
|
|
75
|
-
const regex = new RegExp(`^${regexPattern}$`);
|
|
76
|
-
return regex.test(url);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// 精确匹配
|
|
80
|
-
return url === pattern;
|
|
81
|
-
} catch (e) {
|
|
82
|
-
console.error('URL匹配检查失败:', e);
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
// 格式化响应内容
|
|
88
|
-
export const formatResponseContent = (content, contentType) => {
|
|
89
|
-
if (contentType && contentType.includes('json')) {
|
|
90
|
-
try {
|
|
91
|
-
const parsed = JSON.parse(content);
|
|
92
|
-
return JSON.stringify(parsed, null, 2);
|
|
93
|
-
} catch (e) {
|
|
94
|
-
return content;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return content;
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
// 生成唯一的响应ID
|
|
101
|
-
export const generateResponseId = () => {
|
|
102
|
-
return uuidv4();
|
|
103
|
-
};
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { useEffect, useCallback } from 'react';
|
|
2
|
-
import { useHistory } from 'react-router-dom';
|
|
3
|
-
import { message } from 'antd';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 全局键盘快捷键 Hook
|
|
7
|
-
*
|
|
8
|
-
* 支持的快捷键:
|
|
9
|
-
* - Esc: 关闭当前弹窗/抽屉(触发全局 close-modal 事件)
|
|
10
|
-
* - Ctrl/Cmd + S: 保存(触发全局 save-form 事件)
|
|
11
|
-
* - Ctrl/Cmd + 1: 跳转到功能模块
|
|
12
|
-
* - Ctrl/Cmd + 2: 跳转到接口管理
|
|
13
|
-
* - Ctrl/Cmd + 3: 跳转到系统设置
|
|
14
|
-
* - Ctrl/Cmd + 4: 跳转到请求统计
|
|
15
|
-
* - Ctrl/Cmd + 5: 跳转到接口嗅探
|
|
16
|
-
* - Ctrl/Cmd + Shift + N: 新建接口(在接口管理页触发)
|
|
17
|
-
* - Ctrl/Cmd + K: 聚焦搜索框(触发全局 focus-search 事件)
|
|
18
|
-
* - Shift + ?: 显示快捷键帮助
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
const SHORTCUTS = [
|
|
22
|
-
{ key: 'Esc', desc: '关闭弹窗/抽屉' },
|
|
23
|
-
{ key: 'Ctrl + S', desc: '保存表单' },
|
|
24
|
-
{ key: 'Ctrl + 1', desc: '功能模块' },
|
|
25
|
-
{ key: 'Ctrl + 2', desc: '接口管理' },
|
|
26
|
-
{ key: 'Ctrl + 3', desc: '系统设置' },
|
|
27
|
-
{ key: 'Ctrl + 4', desc: '请求统计' },
|
|
28
|
-
{ key: 'Ctrl + 5', desc: '接口嗅探' },
|
|
29
|
-
{ key: 'Ctrl + Shift + N', desc: '新建接口' },
|
|
30
|
-
{ key: 'Ctrl + K', desc: '聚焦搜索' },
|
|
31
|
-
{ key: 'Shift + ?', desc: '快捷键帮助' },
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
export const getShortcutsList = () => SHORTCUTS;
|
|
35
|
-
|
|
36
|
-
export const useKeyboardShortcuts = () => {
|
|
37
|
-
const history = useHistory();
|
|
38
|
-
|
|
39
|
-
const handleKeyDown = useCallback((e) => {
|
|
40
|
-
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
|
41
|
-
const ctrlOrCmd = isMac ? e.metaKey : e.ctrlKey;
|
|
42
|
-
|
|
43
|
-
// 忽略在输入框、文本域中的快捷键(导航类除外)
|
|
44
|
-
const tagName = e.target?.tagName?.toLowerCase();
|
|
45
|
-
const isInput = tagName === 'input' || tagName === 'textarea' || e.target?.isContentEditable;
|
|
46
|
-
|
|
47
|
-
// Shift + ? 显示帮助(非输入框时)
|
|
48
|
-
if (e.shiftKey && e.key === '?' && !isInput) {
|
|
49
|
-
e.preventDefault();
|
|
50
|
-
window.dispatchEvent(new CustomEvent('keyboard-shortcuts-help'));
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Esc 关闭弹窗/抽屉
|
|
55
|
-
if (e.key === 'Escape') {
|
|
56
|
-
window.dispatchEvent(new CustomEvent('shortcut-esc'));
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Ctrl/Cmd + 数字键 导航
|
|
61
|
-
if (ctrlOrCmd && !e.shiftKey && /^[1-5]$/.test(e.key)) {
|
|
62
|
-
e.preventDefault();
|
|
63
|
-
const routes = ['/', '/interface', '/settings', '/stats', '/sniffer'];
|
|
64
|
-
const names = ['功能模块', '接口管理', '系统设置', '请求统计', '接口嗅探'];
|
|
65
|
-
const idx = parseInt(e.key, 10) - 1;
|
|
66
|
-
history.push(routes[idx]);
|
|
67
|
-
message.success(`已切换到${names[idx]}`);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Ctrl/Cmd + S 保存
|
|
72
|
-
if (ctrlOrCmd && e.key.toLowerCase() === 's' && !e.shiftKey) {
|
|
73
|
-
e.preventDefault();
|
|
74
|
-
window.dispatchEvent(new CustomEvent('shortcut-save'));
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Ctrl/Cmd + Shift + N 新建接口
|
|
79
|
-
if (ctrlOrCmd && e.shiftKey && e.key.toLowerCase() === 'n') {
|
|
80
|
-
e.preventDefault();
|
|
81
|
-
window.dispatchEvent(new CustomEvent('shortcut-new-interface'));
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Ctrl/Cmd + K 聚焦搜索
|
|
86
|
-
if (ctrlOrCmd && e.key.toLowerCase() === 'k' && !e.shiftKey) {
|
|
87
|
-
e.preventDefault();
|
|
88
|
-
window.dispatchEvent(new CustomEvent('shortcut-focus-search'));
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
}, [history]);
|
|
92
|
-
|
|
93
|
-
useEffect(() => {
|
|
94
|
-
document.addEventListener('keydown', handleKeyDown);
|
|
95
|
-
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
96
|
-
}, [handleKeyDown]);
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
export default useKeyboardShortcuts;
|
package/ui/src/index.html
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="zh-CN">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>Whistle Mock Plugin</title>
|
|
7
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
|
-
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700;900&family=Orbitron:wght@400;500;600;700;800;900&family=Share+Tech+Mono&display=swap" rel="stylesheet">
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<div id="root"></div>
|
|
13
|
-
</body>
|
|
14
|
-
</html>
|
package/ui/src/index.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import ReactDOM from 'react-dom';
|
|
3
|
-
import { HashRouter as Router, Switch, Route, Redirect } from 'react-router-dom';
|
|
4
|
-
|
|
5
|
-
// 导入样式
|
|
6
|
-
import 'antd/dist/reset.css';
|
|
7
|
-
import './styles/global.css';
|
|
8
|
-
import './App.css';
|
|
9
|
-
|
|
10
|
-
// 赛博朋克主题 CSS(规则均带 body.cyber-theme 前缀,默认不生效)
|
|
11
|
-
require('./styles/cyber-theme.css');
|
|
12
|
-
|
|
13
|
-
// 大地色系主题 CSS(规则均带 body.earth-theme 前缀,默认不生效)
|
|
14
|
-
require('./styles/earth-theme.css');
|
|
15
|
-
|
|
16
|
-
// 导入页面组件
|
|
17
|
-
import MockData from './pages/MockDataV2';
|
|
18
|
-
import InterfaceManagement from './pages/InterfaceManagementV2';
|
|
19
|
-
import Settings from './pages/Settings';
|
|
20
|
-
import Stats from './pages/Stats';
|
|
21
|
-
import Sniffer from './pages/Sniffer';
|
|
22
|
-
|
|
23
|
-
const App = () => {
|
|
24
|
-
return (
|
|
25
|
-
<Router>
|
|
26
|
-
<div className="App">
|
|
27
|
-
<Switch>
|
|
28
|
-
<Route exact path="/" component={MockData} />
|
|
29
|
-
<Route exact path="/interface" component={InterfaceManagement} />
|
|
30
|
-
<Route path="/interface/:featureId" component={InterfaceManagement} />
|
|
31
|
-
<Route path="/stats" component={Stats} />
|
|
32
|
-
<Route path="/sniffer" component={Sniffer} />
|
|
33
|
-
<Route path="/settings" component={Settings} />
|
|
34
|
-
<Redirect to="/" />
|
|
35
|
-
</Switch>
|
|
36
|
-
</div>
|
|
37
|
-
</Router>
|
|
38
|
-
);
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
// 确保使用正确的渲染方法,兼容React 18和旧版本
|
|
42
|
-
const root = document.getElementById('root');
|
|
43
|
-
if (ReactDOM.createRoot) {
|
|
44
|
-
// React 18+
|
|
45
|
-
const rootElement = ReactDOM.createRoot(root);
|
|
46
|
-
rootElement.render(<App />);
|
|
47
|
-
} else {
|
|
48
|
-
// 旧版本React
|
|
49
|
-
ReactDOM.render(<App />, root);
|
|
50
|
-
}
|