@midscene/visualizer 1.0.1-beta-20251027074226.0 → 1.0.1-beta-20251028065320.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/dist/es/components/screenshot-viewer/index.css +170 -0
- package/dist/es/components/screenshot-viewer/index.mjs +258 -0
- package/dist/es/index.mjs +3 -1
- package/dist/es/utils/replay-scripts.mjs +7 -7
- package/dist/lib/components/screenshot-viewer/index.css +170 -0
- package/dist/lib/components/screenshot-viewer/index.js +292 -0
- package/dist/lib/index.js +6 -0
- package/dist/lib/utils/replay-scripts.js +7 -7
- package/dist/types/components/screenshot-viewer/index.d.ts +15 -0
- package/dist/types/index.d.ts +2 -0
- package/package.json +5 -5
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
.screenshot-viewer {
|
|
2
|
+
flex-direction: column;
|
|
3
|
+
height: 100%;
|
|
4
|
+
display: flex;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.screenshot-viewer.offline, .screenshot-viewer.loading, .screenshot-viewer.error {
|
|
8
|
+
text-align: center;
|
|
9
|
+
color: #666;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
align-items: center;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.screenshot-viewer.offline .screenshot-placeholder h3, .screenshot-viewer.loading .screenshot-placeholder h3, .screenshot-viewer.error .screenshot-placeholder h3 {
|
|
15
|
+
color: #1890ff;
|
|
16
|
+
text-transform: capitalize;
|
|
17
|
+
margin-bottom: 12px;
|
|
18
|
+
font-size: 18px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.screenshot-viewer.offline .screenshot-placeholder p, .screenshot-viewer.loading .screenshot-placeholder p, .screenshot-viewer.error .screenshot-placeholder p {
|
|
22
|
+
color: #666;
|
|
23
|
+
margin: 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.screenshot-viewer.offline .screenshot-placeholder p.error-message, .screenshot-viewer.loading .screenshot-placeholder p.error-message, .screenshot-viewer.error .screenshot-placeholder p.error-message {
|
|
27
|
+
color: #ff4d4f;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.screenshot-viewer .screenshot-header {
|
|
31
|
+
justify-content: space-between;
|
|
32
|
+
align-items: center;
|
|
33
|
+
height: 56px;
|
|
34
|
+
display: flex;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.screenshot-viewer .screenshot-header .screenshot-title {
|
|
38
|
+
flex-direction: column;
|
|
39
|
+
gap: 4px;
|
|
40
|
+
display: flex;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.screenshot-viewer .screenshot-header .screenshot-title h3 {
|
|
44
|
+
color: #000;
|
|
45
|
+
text-transform: capitalize;
|
|
46
|
+
align-items: center;
|
|
47
|
+
gap: 8px;
|
|
48
|
+
margin: 0;
|
|
49
|
+
font-size: 14px;
|
|
50
|
+
font-weight: 600;
|
|
51
|
+
display: flex;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.screenshot-viewer .screenshot-header .screenshot-title .screenshot-subtitle {
|
|
55
|
+
color: #999;
|
|
56
|
+
margin: 0;
|
|
57
|
+
font-size: 12px;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.screenshot-viewer .screenshot-container {
|
|
61
|
+
background: #f2f4f7;
|
|
62
|
+
border-radius: 16px;
|
|
63
|
+
flex-direction: column;
|
|
64
|
+
flex: 1;
|
|
65
|
+
padding: 0 15px;
|
|
66
|
+
display: flex;
|
|
67
|
+
overflow: hidden;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay {
|
|
71
|
+
z-index: 10;
|
|
72
|
+
justify-content: space-between;
|
|
73
|
+
align-items: flex-start;
|
|
74
|
+
padding: 12px 5px 8px;
|
|
75
|
+
display: flex;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .device-name-overlay {
|
|
79
|
+
color: rgba(0, 0, 0, .85);
|
|
80
|
+
text-transform: capitalize;
|
|
81
|
+
align-items: center;
|
|
82
|
+
gap: 8px;
|
|
83
|
+
font-size: 12px;
|
|
84
|
+
font-weight: 500;
|
|
85
|
+
display: flex;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .device-name-overlay .info-icon {
|
|
89
|
+
opacity: .8;
|
|
90
|
+
cursor: pointer;
|
|
91
|
+
font-size: 12px;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .device-name-overlay .info-icon:hover {
|
|
95
|
+
opacity: 1;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls {
|
|
99
|
+
opacity: 1;
|
|
100
|
+
box-sizing: border-box;
|
|
101
|
+
border-radius: 4px;
|
|
102
|
+
align-items: center;
|
|
103
|
+
gap: 10px;
|
|
104
|
+
height: 18px;
|
|
105
|
+
padding: 4px 8px;
|
|
106
|
+
display: flex;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .last-update-time {
|
|
110
|
+
color: #666;
|
|
111
|
+
white-space: nowrap;
|
|
112
|
+
text-overflow: ellipsis;
|
|
113
|
+
font-size: 12px;
|
|
114
|
+
overflow: hidden;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .operation-indicator {
|
|
118
|
+
align-items: center;
|
|
119
|
+
gap: 4px;
|
|
120
|
+
font-size: 12px;
|
|
121
|
+
display: flex;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .ant-btn {
|
|
125
|
+
box-shadow: none;
|
|
126
|
+
background: none;
|
|
127
|
+
border: none;
|
|
128
|
+
justify-content: center;
|
|
129
|
+
align-items: center;
|
|
130
|
+
width: 16px;
|
|
131
|
+
min-width: 16px;
|
|
132
|
+
height: 16px;
|
|
133
|
+
padding: 0;
|
|
134
|
+
display: flex;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .ant-btn:hover {
|
|
138
|
+
background-color: rgba(0, 0, 0, .06);
|
|
139
|
+
border-radius: 2px;
|
|
140
|
+
transition: all .2s;
|
|
141
|
+
transform: scale(1.1);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .ant-btn .anticon {
|
|
145
|
+
color: #666;
|
|
146
|
+
font-size: 12px;
|
|
147
|
+
transition: color .2s;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.screenshot-viewer .screenshot-container .screenshot-content {
|
|
151
|
+
flex: 1;
|
|
152
|
+
justify-content: center;
|
|
153
|
+
align-items: center;
|
|
154
|
+
min-height: 0;
|
|
155
|
+
display: flex;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.screenshot-viewer .screenshot-container .screenshot-content .screenshot-image {
|
|
159
|
+
object-fit: contain;
|
|
160
|
+
border-radius: 12px;
|
|
161
|
+
max-width: 100%;
|
|
162
|
+
height: auto;
|
|
163
|
+
max-height: 100%;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.screenshot-viewer .screenshot-container .screenshot-content .screenshot-placeholder {
|
|
167
|
+
text-align: center;
|
|
168
|
+
color: #999;
|
|
169
|
+
}
|
|
170
|
+
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { InfoCircleOutlined, ReloadOutlined } from "@ant-design/icons";
|
|
3
|
+
import { Button, Spin, Tooltip } from "antd";
|
|
4
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
5
|
+
import "./index.css";
|
|
6
|
+
function ScreenshotViewer(param) {
|
|
7
|
+
let { getScreenshot, getInterfaceInfo, serverOnline, isUserOperating = false } = param;
|
|
8
|
+
const [screenshot, setScreenshot] = useState(null);
|
|
9
|
+
const [loading, setLoading] = useState(false);
|
|
10
|
+
const [error, setError] = useState(null);
|
|
11
|
+
const [lastUpdateTime, setLastUpdateTime] = useState(0);
|
|
12
|
+
const [interfaceInfo, setInterfaceInfo] = useState(null);
|
|
13
|
+
const pollingIntervalRef = useRef(null);
|
|
14
|
+
const isPollingPausedRef = useRef(false);
|
|
15
|
+
const fetchScreenshot = useCallback(async function() {
|
|
16
|
+
let isManual = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : false;
|
|
17
|
+
if (!serverOnline) return;
|
|
18
|
+
setLoading(true);
|
|
19
|
+
if (isManual) setError(null);
|
|
20
|
+
try {
|
|
21
|
+
const result = await getScreenshot();
|
|
22
|
+
console.log('Screenshot API response:', result);
|
|
23
|
+
if (null == result ? void 0 : result.screenshot) {
|
|
24
|
+
const screenshotData = result.screenshot.toString().trim();
|
|
25
|
+
if (screenshotData) {
|
|
26
|
+
setScreenshot(screenshotData);
|
|
27
|
+
setError(null);
|
|
28
|
+
setLastUpdateTime(Date.now());
|
|
29
|
+
} else setError('Empty screenshot data received');
|
|
30
|
+
} else setError('No screenshot data in response');
|
|
31
|
+
} catch (err) {
|
|
32
|
+
console.error('Screenshot fetch error:', err);
|
|
33
|
+
setError(err instanceof Error ? err.message : 'Failed to fetch screenshot');
|
|
34
|
+
} finally{
|
|
35
|
+
setLoading(false);
|
|
36
|
+
}
|
|
37
|
+
}, [
|
|
38
|
+
getScreenshot,
|
|
39
|
+
serverOnline
|
|
40
|
+
]);
|
|
41
|
+
const fetchInterfaceInfo = useCallback(async ()=>{
|
|
42
|
+
if (!serverOnline || !getInterfaceInfo) return;
|
|
43
|
+
try {
|
|
44
|
+
const info = await getInterfaceInfo();
|
|
45
|
+
if (info) setInterfaceInfo(info);
|
|
46
|
+
} catch (err) {
|
|
47
|
+
console.error('Interface info fetch error:', err);
|
|
48
|
+
}
|
|
49
|
+
}, [
|
|
50
|
+
getInterfaceInfo,
|
|
51
|
+
serverOnline
|
|
52
|
+
]);
|
|
53
|
+
const startPolling = useCallback(()=>{
|
|
54
|
+
if (pollingIntervalRef.current) clearInterval(pollingIntervalRef.current);
|
|
55
|
+
console.log('Starting screenshot polling (5s interval)');
|
|
56
|
+
pollingIntervalRef.current = setInterval(()=>{
|
|
57
|
+
if (!isPollingPausedRef.current && serverOnline) fetchScreenshot(false);
|
|
58
|
+
}, 5000);
|
|
59
|
+
}, [
|
|
60
|
+
fetchScreenshot,
|
|
61
|
+
serverOnline
|
|
62
|
+
]);
|
|
63
|
+
const stopPolling = useCallback(()=>{
|
|
64
|
+
if (pollingIntervalRef.current) {
|
|
65
|
+
console.log('Stopping screenshot polling');
|
|
66
|
+
clearInterval(pollingIntervalRef.current);
|
|
67
|
+
pollingIntervalRef.current = null;
|
|
68
|
+
}
|
|
69
|
+
}, []);
|
|
70
|
+
const pausePolling = useCallback(()=>{
|
|
71
|
+
console.log('Pausing screenshot polling');
|
|
72
|
+
isPollingPausedRef.current = true;
|
|
73
|
+
}, []);
|
|
74
|
+
const resumePolling = useCallback(()=>{
|
|
75
|
+
console.log('Resuming screenshot polling');
|
|
76
|
+
isPollingPausedRef.current = false;
|
|
77
|
+
}, []);
|
|
78
|
+
const handleManualRefresh = useCallback(()=>{
|
|
79
|
+
fetchScreenshot(true);
|
|
80
|
+
}, [
|
|
81
|
+
fetchScreenshot
|
|
82
|
+
]);
|
|
83
|
+
useEffect(()=>{
|
|
84
|
+
if (!serverOnline) {
|
|
85
|
+
setScreenshot(null);
|
|
86
|
+
setError(null);
|
|
87
|
+
setInterfaceInfo(null);
|
|
88
|
+
stopPolling();
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
fetchScreenshot(false);
|
|
92
|
+
fetchInterfaceInfo();
|
|
93
|
+
startPolling();
|
|
94
|
+
return ()=>{
|
|
95
|
+
stopPolling();
|
|
96
|
+
};
|
|
97
|
+
}, [
|
|
98
|
+
serverOnline,
|
|
99
|
+
startPolling,
|
|
100
|
+
stopPolling,
|
|
101
|
+
fetchScreenshot,
|
|
102
|
+
fetchInterfaceInfo
|
|
103
|
+
]);
|
|
104
|
+
useEffect(()=>{
|
|
105
|
+
if (!serverOnline) return;
|
|
106
|
+
if (isUserOperating) pausePolling();
|
|
107
|
+
else {
|
|
108
|
+
resumePolling();
|
|
109
|
+
fetchScreenshot(false);
|
|
110
|
+
}
|
|
111
|
+
}, [
|
|
112
|
+
isUserOperating,
|
|
113
|
+
pausePolling,
|
|
114
|
+
resumePolling,
|
|
115
|
+
fetchScreenshot,
|
|
116
|
+
serverOnline
|
|
117
|
+
]);
|
|
118
|
+
useEffect(()=>()=>{
|
|
119
|
+
stopPolling();
|
|
120
|
+
}, [
|
|
121
|
+
stopPolling
|
|
122
|
+
]);
|
|
123
|
+
if (!serverOnline) return /*#__PURE__*/ jsx("div", {
|
|
124
|
+
className: "screenshot-viewer offline",
|
|
125
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
126
|
+
className: "screenshot-placeholder",
|
|
127
|
+
children: [
|
|
128
|
+
/*#__PURE__*/ jsx("h3", {
|
|
129
|
+
children: "\uD83D\uDCF1 Screen Preview"
|
|
130
|
+
}),
|
|
131
|
+
/*#__PURE__*/ jsx("p", {
|
|
132
|
+
children: "Start the playground server to see real-time screenshots"
|
|
133
|
+
})
|
|
134
|
+
]
|
|
135
|
+
})
|
|
136
|
+
});
|
|
137
|
+
if (loading && !screenshot) return /*#__PURE__*/ jsxs("div", {
|
|
138
|
+
className: "screenshot-viewer loading",
|
|
139
|
+
children: [
|
|
140
|
+
/*#__PURE__*/ jsx(Spin, {
|
|
141
|
+
size: "large"
|
|
142
|
+
}),
|
|
143
|
+
/*#__PURE__*/ jsx("p", {
|
|
144
|
+
children: "Loading screenshot..."
|
|
145
|
+
})
|
|
146
|
+
]
|
|
147
|
+
});
|
|
148
|
+
if (error && !screenshot) return /*#__PURE__*/ jsx("div", {
|
|
149
|
+
className: "screenshot-viewer error",
|
|
150
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
151
|
+
className: "screenshot-placeholder",
|
|
152
|
+
children: [
|
|
153
|
+
/*#__PURE__*/ jsx("h3", {
|
|
154
|
+
children: "\uD83D\uDCF1 Screen Preview"
|
|
155
|
+
}),
|
|
156
|
+
/*#__PURE__*/ jsx("p", {
|
|
157
|
+
className: "error-message",
|
|
158
|
+
children: error
|
|
159
|
+
})
|
|
160
|
+
]
|
|
161
|
+
})
|
|
162
|
+
});
|
|
163
|
+
const formatLastUpdateTime = (timestamp)=>{
|
|
164
|
+
if (!timestamp) return '';
|
|
165
|
+
const now = Date.now();
|
|
166
|
+
const diff = Math.floor((now - timestamp) / 1000);
|
|
167
|
+
if (diff < 60) return `${diff}s ago`;
|
|
168
|
+
if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
|
|
169
|
+
return new Date(timestamp).toLocaleTimeString();
|
|
170
|
+
};
|
|
171
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
172
|
+
className: "screenshot-viewer",
|
|
173
|
+
children: [
|
|
174
|
+
/*#__PURE__*/ jsx("div", {
|
|
175
|
+
className: "screenshot-header",
|
|
176
|
+
children: /*#__PURE__*/ jsx("div", {
|
|
177
|
+
className: "screenshot-title",
|
|
178
|
+
children: /*#__PURE__*/ jsx("h3", {
|
|
179
|
+
children: (null == interfaceInfo ? void 0 : interfaceInfo.type) ? interfaceInfo.type : 'Device Name'
|
|
180
|
+
})
|
|
181
|
+
})
|
|
182
|
+
}),
|
|
183
|
+
/*#__PURE__*/ jsxs("div", {
|
|
184
|
+
className: "screenshot-container",
|
|
185
|
+
children: [
|
|
186
|
+
/*#__PURE__*/ jsxs("div", {
|
|
187
|
+
className: "screenshot-overlay",
|
|
188
|
+
children: [
|
|
189
|
+
/*#__PURE__*/ jsxs("div", {
|
|
190
|
+
className: "device-name-overlay",
|
|
191
|
+
children: [
|
|
192
|
+
"Device Name",
|
|
193
|
+
/*#__PURE__*/ jsx(Tooltip, {
|
|
194
|
+
title: null == interfaceInfo ? void 0 : interfaceInfo.description,
|
|
195
|
+
children: /*#__PURE__*/ jsx(InfoCircleOutlined, {
|
|
196
|
+
size: 16,
|
|
197
|
+
className: "info-icon"
|
|
198
|
+
})
|
|
199
|
+
})
|
|
200
|
+
]
|
|
201
|
+
}),
|
|
202
|
+
/*#__PURE__*/ jsxs("div", {
|
|
203
|
+
className: "screenshot-controls",
|
|
204
|
+
children: [
|
|
205
|
+
lastUpdateTime > 0 && /*#__PURE__*/ jsxs("span", {
|
|
206
|
+
className: "last-update-time",
|
|
207
|
+
children: [
|
|
208
|
+
"Last updated ",
|
|
209
|
+
formatLastUpdateTime(lastUpdateTime)
|
|
210
|
+
]
|
|
211
|
+
}),
|
|
212
|
+
/*#__PURE__*/ jsx(Tooltip, {
|
|
213
|
+
title: "Refresh screenshot",
|
|
214
|
+
children: /*#__PURE__*/ jsx(Button, {
|
|
215
|
+
icon: /*#__PURE__*/ jsx(ReloadOutlined, {}),
|
|
216
|
+
onClick: handleManualRefresh,
|
|
217
|
+
loading: loading,
|
|
218
|
+
size: "small"
|
|
219
|
+
})
|
|
220
|
+
}),
|
|
221
|
+
isUserOperating && /*#__PURE__*/ jsxs("span", {
|
|
222
|
+
className: "operation-indicator",
|
|
223
|
+
children: [
|
|
224
|
+
/*#__PURE__*/ jsx(Spin, {
|
|
225
|
+
size: "small"
|
|
226
|
+
}),
|
|
227
|
+
" Operating..."
|
|
228
|
+
]
|
|
229
|
+
})
|
|
230
|
+
]
|
|
231
|
+
})
|
|
232
|
+
]
|
|
233
|
+
}),
|
|
234
|
+
/*#__PURE__*/ jsx("div", {
|
|
235
|
+
className: "screenshot-content",
|
|
236
|
+
children: screenshot ? /*#__PURE__*/ jsx("img", {
|
|
237
|
+
src: screenshot.startsWith('data:image/') ? screenshot : `data:image/png;base64,${screenshot}`,
|
|
238
|
+
alt: "Device Screenshot",
|
|
239
|
+
className: "screenshot-image",
|
|
240
|
+
onLoad: ()=>console.log('Screenshot image loaded successfully'),
|
|
241
|
+
onError: (e)=>{
|
|
242
|
+
console.error('Screenshot image load error:', e);
|
|
243
|
+
console.error('Screenshot data preview:', screenshot.substring(0, 100));
|
|
244
|
+
setError('Failed to load screenshot image');
|
|
245
|
+
}
|
|
246
|
+
}) : /*#__PURE__*/ jsx("div", {
|
|
247
|
+
className: "screenshot-placeholder",
|
|
248
|
+
children: /*#__PURE__*/ jsx("p", {
|
|
249
|
+
children: "No screenshot available"
|
|
250
|
+
})
|
|
251
|
+
})
|
|
252
|
+
})
|
|
253
|
+
]
|
|
254
|
+
})
|
|
255
|
+
]
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
export { ScreenshotViewer as default };
|
package/dist/es/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "./component/playground/index.css";
|
|
2
2
|
import "./component/universal-playground/index.css";
|
|
3
|
+
import "./components/screenshot-viewer/index.css";
|
|
3
4
|
import { allScriptsFromDump, generateAnimationScripts } from "./utils/replay-scripts.mjs";
|
|
4
5
|
import { useEnvConfig } from "./store/store.mjs";
|
|
5
6
|
import { colorForName, globalThemeConfig, highlightColorForType } from "./utils/color.mjs";
|
|
@@ -16,10 +17,11 @@ import { ContextPreview } from "./component/context-preview/index.mjs";
|
|
|
16
17
|
import { PromptInput } from "./component/prompt-input/index.mjs";
|
|
17
18
|
import { Player } from "./component/player/index.mjs";
|
|
18
19
|
import { Blackboard } from "./component/blackboard/index.mjs";
|
|
20
|
+
import screenshot_viewer from "./components/screenshot-viewer/index.mjs";
|
|
19
21
|
import { actionNameForType, getPlaceholderForType, staticAgentFromContext } from "./utils/playground-utils.mjs";
|
|
20
22
|
import { filterBase64Value, timeStr } from "./utils/index.mjs";
|
|
21
23
|
import shiny_text from "./component/shiny-text/index.mjs";
|
|
22
24
|
import universal_playground, { UniversalPlayground } from "./component/universal-playground/index.mjs";
|
|
23
25
|
import { IndexedDBStorageProvider, LocalStorageProvider, MemoryStorageProvider, NoOpStorageProvider, StorageType, createStorageProvider, detectBestStorageType } from "./component/universal-playground/providers/storage-provider.mjs";
|
|
24
26
|
import { AgentContextProvider, BaseContextProvider, NoOpContextProvider, StaticContextProvider } from "./component/universal-playground/providers/context-provider.mjs";
|
|
25
|
-
export { AgentContextProvider, BaseContextProvider, Blackboard, ContextPreview, EnvConfig, EnvConfigReminder, IndexedDBStorageProvider, LocalStorageProvider, Logo, MemoryStorageProvider, NavActions, NoOpContextProvider, NoOpStorageProvider, Player, PlaygroundResultView, PromptInput, ServiceModeControl, shiny_text as ShinyText, StaticContextProvider, StorageType, UniversalPlayground, universal_playground as UniversalPlaygroundDefault, actionNameForType, allScriptsFromDump, colorForName, createStorageProvider, detectBestStorageType, filterBase64Value, generateAnimationScripts, getPlaceholderForType, globalThemeConfig, highlightColorForType, iconForStatus, safeOverrideAIConfig, staticAgentFromContext, timeCostStrElement, timeStr, useEnvConfig, useSafeOverrideAIConfig, useServerValid };
|
|
27
|
+
export { AgentContextProvider, BaseContextProvider, Blackboard, ContextPreview, EnvConfig, EnvConfigReminder, IndexedDBStorageProvider, LocalStorageProvider, Logo, MemoryStorageProvider, NavActions, NoOpContextProvider, NoOpStorageProvider, Player, PlaygroundResultView, PromptInput, screenshot_viewer as ScreenshotViewer, ServiceModeControl, shiny_text as ShinyText, StaticContextProvider, StorageType, UniversalPlayground, universal_playground as UniversalPlaygroundDefault, actionNameForType, allScriptsFromDump, colorForName, createStorageProvider, detectBestStorageType, filterBase64Value, generateAnimationScripts, getPlaceholderForType, globalThemeConfig, highlightColorForType, iconForStatus, safeOverrideAIConfig, staticAgentFromContext, timeCostStrElement, timeStr, useEnvConfig, useSafeOverrideAIConfig, useServerValid };
|
|
@@ -160,9 +160,9 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight)=>{
|
|
|
160
160
|
});
|
|
161
161
|
}
|
|
162
162
|
} else if ('Insight' === task.type && 'Locate' === task.subType) {
|
|
163
|
-
var
|
|
164
|
-
const
|
|
165
|
-
const resultElement = null == (
|
|
163
|
+
var _serviceTask_output;
|
|
164
|
+
const serviceTask = task;
|
|
165
|
+
const resultElement = null == (_serviceTask_output = serviceTask.output) ? void 0 : _serviceTask_output.element;
|
|
166
166
|
const title = typeStr(task);
|
|
167
167
|
const subTitle = paramStr(task);
|
|
168
168
|
if (null == resultElement ? void 0 : resultElement.rect) insightCameraState = {
|
|
@@ -170,10 +170,10 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight)=>{
|
|
|
170
170
|
pointerLeft: resultElement.center[0],
|
|
171
171
|
pointerTop: resultElement.center[1]
|
|
172
172
|
};
|
|
173
|
-
const context =
|
|
173
|
+
const context = serviceTask.uiContext;
|
|
174
174
|
if (null == context ? void 0 : context.screenshotBase64) {
|
|
175
|
-
var
|
|
176
|
-
const insightDump =
|
|
175
|
+
var _serviceTask_output1, _insightDump_taskInfo, _context_size, _context_size1;
|
|
176
|
+
const insightDump = serviceTask.log;
|
|
177
177
|
const insightContentLength = 0;
|
|
178
178
|
if (context.screenshotBase64) {
|
|
179
179
|
var _context_size2, _context_size3;
|
|
@@ -194,7 +194,7 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight)=>{
|
|
|
194
194
|
img: context.screenshotBase64,
|
|
195
195
|
context: context,
|
|
196
196
|
camera: cameraState,
|
|
197
|
-
highlightElement: (null == (
|
|
197
|
+
highlightElement: (null == (_serviceTask_output1 = serviceTask.output) ? void 0 : _serviceTask_output1.element) || void 0,
|
|
198
198
|
searchArea: null == insightDump ? void 0 : null == (_insightDump_taskInfo = insightDump.taskInfo) ? void 0 : _insightDump_taskInfo.searchArea,
|
|
199
199
|
duration: insightContentLength > 20 ? locateDuration : 0.5 * locateDuration,
|
|
200
200
|
insightCameraDuration: locateDuration,
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
.screenshot-viewer {
|
|
2
|
+
flex-direction: column;
|
|
3
|
+
height: 100%;
|
|
4
|
+
display: flex;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.screenshot-viewer.offline, .screenshot-viewer.loading, .screenshot-viewer.error {
|
|
8
|
+
text-align: center;
|
|
9
|
+
color: #666;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
align-items: center;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.screenshot-viewer.offline .screenshot-placeholder h3, .screenshot-viewer.loading .screenshot-placeholder h3, .screenshot-viewer.error .screenshot-placeholder h3 {
|
|
15
|
+
color: #1890ff;
|
|
16
|
+
text-transform: capitalize;
|
|
17
|
+
margin-bottom: 12px;
|
|
18
|
+
font-size: 18px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.screenshot-viewer.offline .screenshot-placeholder p, .screenshot-viewer.loading .screenshot-placeholder p, .screenshot-viewer.error .screenshot-placeholder p {
|
|
22
|
+
color: #666;
|
|
23
|
+
margin: 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.screenshot-viewer.offline .screenshot-placeholder p.error-message, .screenshot-viewer.loading .screenshot-placeholder p.error-message, .screenshot-viewer.error .screenshot-placeholder p.error-message {
|
|
27
|
+
color: #ff4d4f;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.screenshot-viewer .screenshot-header {
|
|
31
|
+
justify-content: space-between;
|
|
32
|
+
align-items: center;
|
|
33
|
+
height: 56px;
|
|
34
|
+
display: flex;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.screenshot-viewer .screenshot-header .screenshot-title {
|
|
38
|
+
flex-direction: column;
|
|
39
|
+
gap: 4px;
|
|
40
|
+
display: flex;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.screenshot-viewer .screenshot-header .screenshot-title h3 {
|
|
44
|
+
color: #000;
|
|
45
|
+
text-transform: capitalize;
|
|
46
|
+
align-items: center;
|
|
47
|
+
gap: 8px;
|
|
48
|
+
margin: 0;
|
|
49
|
+
font-size: 14px;
|
|
50
|
+
font-weight: 600;
|
|
51
|
+
display: flex;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.screenshot-viewer .screenshot-header .screenshot-title .screenshot-subtitle {
|
|
55
|
+
color: #999;
|
|
56
|
+
margin: 0;
|
|
57
|
+
font-size: 12px;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.screenshot-viewer .screenshot-container {
|
|
61
|
+
background: #f2f4f7;
|
|
62
|
+
border-radius: 16px;
|
|
63
|
+
flex-direction: column;
|
|
64
|
+
flex: 1;
|
|
65
|
+
padding: 0 15px;
|
|
66
|
+
display: flex;
|
|
67
|
+
overflow: hidden;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay {
|
|
71
|
+
z-index: 10;
|
|
72
|
+
justify-content: space-between;
|
|
73
|
+
align-items: flex-start;
|
|
74
|
+
padding: 12px 5px 8px;
|
|
75
|
+
display: flex;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .device-name-overlay {
|
|
79
|
+
color: rgba(0, 0, 0, .85);
|
|
80
|
+
text-transform: capitalize;
|
|
81
|
+
align-items: center;
|
|
82
|
+
gap: 8px;
|
|
83
|
+
font-size: 12px;
|
|
84
|
+
font-weight: 500;
|
|
85
|
+
display: flex;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .device-name-overlay .info-icon {
|
|
89
|
+
opacity: .8;
|
|
90
|
+
cursor: pointer;
|
|
91
|
+
font-size: 12px;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .device-name-overlay .info-icon:hover {
|
|
95
|
+
opacity: 1;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls {
|
|
99
|
+
opacity: 1;
|
|
100
|
+
box-sizing: border-box;
|
|
101
|
+
border-radius: 4px;
|
|
102
|
+
align-items: center;
|
|
103
|
+
gap: 10px;
|
|
104
|
+
height: 18px;
|
|
105
|
+
padding: 4px 8px;
|
|
106
|
+
display: flex;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .last-update-time {
|
|
110
|
+
color: #666;
|
|
111
|
+
white-space: nowrap;
|
|
112
|
+
text-overflow: ellipsis;
|
|
113
|
+
font-size: 12px;
|
|
114
|
+
overflow: hidden;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .operation-indicator {
|
|
118
|
+
align-items: center;
|
|
119
|
+
gap: 4px;
|
|
120
|
+
font-size: 12px;
|
|
121
|
+
display: flex;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .ant-btn {
|
|
125
|
+
box-shadow: none;
|
|
126
|
+
background: none;
|
|
127
|
+
border: none;
|
|
128
|
+
justify-content: center;
|
|
129
|
+
align-items: center;
|
|
130
|
+
width: 16px;
|
|
131
|
+
min-width: 16px;
|
|
132
|
+
height: 16px;
|
|
133
|
+
padding: 0;
|
|
134
|
+
display: flex;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .ant-btn:hover {
|
|
138
|
+
background-color: rgba(0, 0, 0, .06);
|
|
139
|
+
border-radius: 2px;
|
|
140
|
+
transition: all .2s;
|
|
141
|
+
transform: scale(1.1);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .ant-btn .anticon {
|
|
145
|
+
color: #666;
|
|
146
|
+
font-size: 12px;
|
|
147
|
+
transition: color .2s;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.screenshot-viewer .screenshot-container .screenshot-content {
|
|
151
|
+
flex: 1;
|
|
152
|
+
justify-content: center;
|
|
153
|
+
align-items: center;
|
|
154
|
+
min-height: 0;
|
|
155
|
+
display: flex;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.screenshot-viewer .screenshot-container .screenshot-content .screenshot-image {
|
|
159
|
+
object-fit: contain;
|
|
160
|
+
border-radius: 12px;
|
|
161
|
+
max-width: 100%;
|
|
162
|
+
height: auto;
|
|
163
|
+
max-height: 100%;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.screenshot-viewer .screenshot-container .screenshot-content .screenshot-placeholder {
|
|
167
|
+
text-align: center;
|
|
168
|
+
color: #999;
|
|
169
|
+
}
|
|
170
|
+
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
default: ()=>ScreenshotViewer
|
|
28
|
+
});
|
|
29
|
+
const jsx_runtime_namespaceObject = require("react/jsx-runtime");
|
|
30
|
+
const icons_namespaceObject = require("@ant-design/icons");
|
|
31
|
+
const external_antd_namespaceObject = require("antd");
|
|
32
|
+
const external_react_namespaceObject = require("react");
|
|
33
|
+
require("./index.css");
|
|
34
|
+
function ScreenshotViewer(param) {
|
|
35
|
+
let { getScreenshot, getInterfaceInfo, serverOnline, isUserOperating = false } = param;
|
|
36
|
+
const [screenshot, setScreenshot] = (0, external_react_namespaceObject.useState)(null);
|
|
37
|
+
const [loading, setLoading] = (0, external_react_namespaceObject.useState)(false);
|
|
38
|
+
const [error, setError] = (0, external_react_namespaceObject.useState)(null);
|
|
39
|
+
const [lastUpdateTime, setLastUpdateTime] = (0, external_react_namespaceObject.useState)(0);
|
|
40
|
+
const [interfaceInfo, setInterfaceInfo] = (0, external_react_namespaceObject.useState)(null);
|
|
41
|
+
const pollingIntervalRef = (0, external_react_namespaceObject.useRef)(null);
|
|
42
|
+
const isPollingPausedRef = (0, external_react_namespaceObject.useRef)(false);
|
|
43
|
+
const fetchScreenshot = (0, external_react_namespaceObject.useCallback)(async function() {
|
|
44
|
+
let isManual = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : false;
|
|
45
|
+
if (!serverOnline) return;
|
|
46
|
+
setLoading(true);
|
|
47
|
+
if (isManual) setError(null);
|
|
48
|
+
try {
|
|
49
|
+
const result = await getScreenshot();
|
|
50
|
+
console.log('Screenshot API response:', result);
|
|
51
|
+
if (null == result ? void 0 : result.screenshot) {
|
|
52
|
+
const screenshotData = result.screenshot.toString().trim();
|
|
53
|
+
if (screenshotData) {
|
|
54
|
+
setScreenshot(screenshotData);
|
|
55
|
+
setError(null);
|
|
56
|
+
setLastUpdateTime(Date.now());
|
|
57
|
+
} else setError('Empty screenshot data received');
|
|
58
|
+
} else setError('No screenshot data in response');
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.error('Screenshot fetch error:', err);
|
|
61
|
+
setError(err instanceof Error ? err.message : 'Failed to fetch screenshot');
|
|
62
|
+
} finally{
|
|
63
|
+
setLoading(false);
|
|
64
|
+
}
|
|
65
|
+
}, [
|
|
66
|
+
getScreenshot,
|
|
67
|
+
serverOnline
|
|
68
|
+
]);
|
|
69
|
+
const fetchInterfaceInfo = (0, external_react_namespaceObject.useCallback)(async ()=>{
|
|
70
|
+
if (!serverOnline || !getInterfaceInfo) return;
|
|
71
|
+
try {
|
|
72
|
+
const info = await getInterfaceInfo();
|
|
73
|
+
if (info) setInterfaceInfo(info);
|
|
74
|
+
} catch (err) {
|
|
75
|
+
console.error('Interface info fetch error:', err);
|
|
76
|
+
}
|
|
77
|
+
}, [
|
|
78
|
+
getInterfaceInfo,
|
|
79
|
+
serverOnline
|
|
80
|
+
]);
|
|
81
|
+
const startPolling = (0, external_react_namespaceObject.useCallback)(()=>{
|
|
82
|
+
if (pollingIntervalRef.current) clearInterval(pollingIntervalRef.current);
|
|
83
|
+
console.log('Starting screenshot polling (5s interval)');
|
|
84
|
+
pollingIntervalRef.current = setInterval(()=>{
|
|
85
|
+
if (!isPollingPausedRef.current && serverOnline) fetchScreenshot(false);
|
|
86
|
+
}, 5000);
|
|
87
|
+
}, [
|
|
88
|
+
fetchScreenshot,
|
|
89
|
+
serverOnline
|
|
90
|
+
]);
|
|
91
|
+
const stopPolling = (0, external_react_namespaceObject.useCallback)(()=>{
|
|
92
|
+
if (pollingIntervalRef.current) {
|
|
93
|
+
console.log('Stopping screenshot polling');
|
|
94
|
+
clearInterval(pollingIntervalRef.current);
|
|
95
|
+
pollingIntervalRef.current = null;
|
|
96
|
+
}
|
|
97
|
+
}, []);
|
|
98
|
+
const pausePolling = (0, external_react_namespaceObject.useCallback)(()=>{
|
|
99
|
+
console.log('Pausing screenshot polling');
|
|
100
|
+
isPollingPausedRef.current = true;
|
|
101
|
+
}, []);
|
|
102
|
+
const resumePolling = (0, external_react_namespaceObject.useCallback)(()=>{
|
|
103
|
+
console.log('Resuming screenshot polling');
|
|
104
|
+
isPollingPausedRef.current = false;
|
|
105
|
+
}, []);
|
|
106
|
+
const handleManualRefresh = (0, external_react_namespaceObject.useCallback)(()=>{
|
|
107
|
+
fetchScreenshot(true);
|
|
108
|
+
}, [
|
|
109
|
+
fetchScreenshot
|
|
110
|
+
]);
|
|
111
|
+
(0, external_react_namespaceObject.useEffect)(()=>{
|
|
112
|
+
if (!serverOnline) {
|
|
113
|
+
setScreenshot(null);
|
|
114
|
+
setError(null);
|
|
115
|
+
setInterfaceInfo(null);
|
|
116
|
+
stopPolling();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
fetchScreenshot(false);
|
|
120
|
+
fetchInterfaceInfo();
|
|
121
|
+
startPolling();
|
|
122
|
+
return ()=>{
|
|
123
|
+
stopPolling();
|
|
124
|
+
};
|
|
125
|
+
}, [
|
|
126
|
+
serverOnline,
|
|
127
|
+
startPolling,
|
|
128
|
+
stopPolling,
|
|
129
|
+
fetchScreenshot,
|
|
130
|
+
fetchInterfaceInfo
|
|
131
|
+
]);
|
|
132
|
+
(0, external_react_namespaceObject.useEffect)(()=>{
|
|
133
|
+
if (!serverOnline) return;
|
|
134
|
+
if (isUserOperating) pausePolling();
|
|
135
|
+
else {
|
|
136
|
+
resumePolling();
|
|
137
|
+
fetchScreenshot(false);
|
|
138
|
+
}
|
|
139
|
+
}, [
|
|
140
|
+
isUserOperating,
|
|
141
|
+
pausePolling,
|
|
142
|
+
resumePolling,
|
|
143
|
+
fetchScreenshot,
|
|
144
|
+
serverOnline
|
|
145
|
+
]);
|
|
146
|
+
(0, external_react_namespaceObject.useEffect)(()=>()=>{
|
|
147
|
+
stopPolling();
|
|
148
|
+
}, [
|
|
149
|
+
stopPolling
|
|
150
|
+
]);
|
|
151
|
+
if (!serverOnline) return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
|
|
152
|
+
className: "screenshot-viewer offline",
|
|
153
|
+
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
|
|
154
|
+
className: "screenshot-placeholder",
|
|
155
|
+
children: [
|
|
156
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("h3", {
|
|
157
|
+
children: "\uD83D\uDCF1 Screen Preview"
|
|
158
|
+
}),
|
|
159
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("p", {
|
|
160
|
+
children: "Start the playground server to see real-time screenshots"
|
|
161
|
+
})
|
|
162
|
+
]
|
|
163
|
+
})
|
|
164
|
+
});
|
|
165
|
+
if (loading && !screenshot) return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
|
|
166
|
+
className: "screenshot-viewer loading",
|
|
167
|
+
children: [
|
|
168
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_antd_namespaceObject.Spin, {
|
|
169
|
+
size: "large"
|
|
170
|
+
}),
|
|
171
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("p", {
|
|
172
|
+
children: "Loading screenshot..."
|
|
173
|
+
})
|
|
174
|
+
]
|
|
175
|
+
});
|
|
176
|
+
if (error && !screenshot) return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
|
|
177
|
+
className: "screenshot-viewer error",
|
|
178
|
+
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
|
|
179
|
+
className: "screenshot-placeholder",
|
|
180
|
+
children: [
|
|
181
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("h3", {
|
|
182
|
+
children: "\uD83D\uDCF1 Screen Preview"
|
|
183
|
+
}),
|
|
184
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("p", {
|
|
185
|
+
className: "error-message",
|
|
186
|
+
children: error
|
|
187
|
+
})
|
|
188
|
+
]
|
|
189
|
+
})
|
|
190
|
+
});
|
|
191
|
+
const formatLastUpdateTime = (timestamp)=>{
|
|
192
|
+
if (!timestamp) return '';
|
|
193
|
+
const now = Date.now();
|
|
194
|
+
const diff = Math.floor((now - timestamp) / 1000);
|
|
195
|
+
if (diff < 60) return `${diff}s ago`;
|
|
196
|
+
if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
|
|
197
|
+
return new Date(timestamp).toLocaleTimeString();
|
|
198
|
+
};
|
|
199
|
+
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
|
|
200
|
+
className: "screenshot-viewer",
|
|
201
|
+
children: [
|
|
202
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
|
|
203
|
+
className: "screenshot-header",
|
|
204
|
+
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
|
|
205
|
+
className: "screenshot-title",
|
|
206
|
+
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("h3", {
|
|
207
|
+
children: (null == interfaceInfo ? void 0 : interfaceInfo.type) ? interfaceInfo.type : 'Device Name'
|
|
208
|
+
})
|
|
209
|
+
})
|
|
210
|
+
}),
|
|
211
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
|
|
212
|
+
className: "screenshot-container",
|
|
213
|
+
children: [
|
|
214
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
|
|
215
|
+
className: "screenshot-overlay",
|
|
216
|
+
children: [
|
|
217
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
|
|
218
|
+
className: "device-name-overlay",
|
|
219
|
+
children: [
|
|
220
|
+
"Device Name",
|
|
221
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_antd_namespaceObject.Tooltip, {
|
|
222
|
+
title: null == interfaceInfo ? void 0 : interfaceInfo.description,
|
|
223
|
+
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(icons_namespaceObject.InfoCircleOutlined, {
|
|
224
|
+
size: 16,
|
|
225
|
+
className: "info-icon"
|
|
226
|
+
})
|
|
227
|
+
})
|
|
228
|
+
]
|
|
229
|
+
}),
|
|
230
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
|
|
231
|
+
className: "screenshot-controls",
|
|
232
|
+
children: [
|
|
233
|
+
lastUpdateTime > 0 && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("span", {
|
|
234
|
+
className: "last-update-time",
|
|
235
|
+
children: [
|
|
236
|
+
"Last updated ",
|
|
237
|
+
formatLastUpdateTime(lastUpdateTime)
|
|
238
|
+
]
|
|
239
|
+
}),
|
|
240
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_antd_namespaceObject.Tooltip, {
|
|
241
|
+
title: "Refresh screenshot",
|
|
242
|
+
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_antd_namespaceObject.Button, {
|
|
243
|
+
icon: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(icons_namespaceObject.ReloadOutlined, {}),
|
|
244
|
+
onClick: handleManualRefresh,
|
|
245
|
+
loading: loading,
|
|
246
|
+
size: "small"
|
|
247
|
+
})
|
|
248
|
+
}),
|
|
249
|
+
isUserOperating && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("span", {
|
|
250
|
+
className: "operation-indicator",
|
|
251
|
+
children: [
|
|
252
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_antd_namespaceObject.Spin, {
|
|
253
|
+
size: "small"
|
|
254
|
+
}),
|
|
255
|
+
" Operating..."
|
|
256
|
+
]
|
|
257
|
+
})
|
|
258
|
+
]
|
|
259
|
+
})
|
|
260
|
+
]
|
|
261
|
+
}),
|
|
262
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
|
|
263
|
+
className: "screenshot-content",
|
|
264
|
+
children: screenshot ? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("img", {
|
|
265
|
+
src: screenshot.startsWith('data:image/') ? screenshot : `data:image/png;base64,${screenshot}`,
|
|
266
|
+
alt: "Device Screenshot",
|
|
267
|
+
className: "screenshot-image",
|
|
268
|
+
onLoad: ()=>console.log('Screenshot image loaded successfully'),
|
|
269
|
+
onError: (e)=>{
|
|
270
|
+
console.error('Screenshot image load error:', e);
|
|
271
|
+
console.error('Screenshot data preview:', screenshot.substring(0, 100));
|
|
272
|
+
setError('Failed to load screenshot image');
|
|
273
|
+
}
|
|
274
|
+
}) : /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
|
|
275
|
+
className: "screenshot-placeholder",
|
|
276
|
+
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("p", {
|
|
277
|
+
children: "No screenshot available"
|
|
278
|
+
})
|
|
279
|
+
})
|
|
280
|
+
})
|
|
281
|
+
]
|
|
282
|
+
})
|
|
283
|
+
]
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
exports["default"] = __webpack_exports__["default"];
|
|
287
|
+
for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
288
|
+
"default"
|
|
289
|
+
].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
|
|
290
|
+
Object.defineProperty(exports, '__esModule', {
|
|
291
|
+
value: true
|
|
292
|
+
});
|
package/dist/lib/index.js
CHANGED
|
@@ -63,6 +63,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
63
63
|
PromptInput: ()=>prompt_input_index_js_namespaceObject.PromptInput,
|
|
64
64
|
StaticContextProvider: ()=>context_provider_js_namespaceObject.StaticContextProvider,
|
|
65
65
|
Blackboard: ()=>blackboard_index_js_namespaceObject.Blackboard,
|
|
66
|
+
ScreenshotViewer: ()=>screenshot_viewer_index_js_default(),
|
|
66
67
|
Player: ()=>player_index_js_namespaceObject.Player,
|
|
67
68
|
AgentContextProvider: ()=>context_provider_js_namespaceObject.AgentContextProvider,
|
|
68
69
|
EnvConfigReminder: ()=>env_config_reminder_index_js_namespaceObject.EnvConfigReminder,
|
|
@@ -76,6 +77,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
76
77
|
});
|
|
77
78
|
require("./component/playground/index.css");
|
|
78
79
|
require("./component/universal-playground/index.css");
|
|
80
|
+
require("./components/screenshot-viewer/index.css");
|
|
79
81
|
const replay_scripts_js_namespaceObject = require("./utils/replay-scripts.js");
|
|
80
82
|
const store_js_namespaceObject = require("./store/store.js");
|
|
81
83
|
const color_js_namespaceObject = require("./utils/color.js");
|
|
@@ -92,6 +94,8 @@ const context_preview_index_js_namespaceObject = require("./component/context-pr
|
|
|
92
94
|
const prompt_input_index_js_namespaceObject = require("./component/prompt-input/index.js");
|
|
93
95
|
const player_index_js_namespaceObject = require("./component/player/index.js");
|
|
94
96
|
const blackboard_index_js_namespaceObject = require("./component/blackboard/index.js");
|
|
97
|
+
const screenshot_viewer_index_js_namespaceObject = require("./components/screenshot-viewer/index.js");
|
|
98
|
+
var screenshot_viewer_index_js_default = /*#__PURE__*/ __webpack_require__.n(screenshot_viewer_index_js_namespaceObject);
|
|
95
99
|
const playground_utils_js_namespaceObject = require("./utils/playground-utils.js");
|
|
96
100
|
const external_utils_index_js_namespaceObject = require("./utils/index.js");
|
|
97
101
|
const shiny_text_index_js_namespaceObject = require("./component/shiny-text/index.js");
|
|
@@ -116,6 +120,7 @@ exports.NoOpStorageProvider = __webpack_exports__.NoOpStorageProvider;
|
|
|
116
120
|
exports.Player = __webpack_exports__.Player;
|
|
117
121
|
exports.PlaygroundResultView = __webpack_exports__.PlaygroundResultView;
|
|
118
122
|
exports.PromptInput = __webpack_exports__.PromptInput;
|
|
123
|
+
exports.ScreenshotViewer = __webpack_exports__.ScreenshotViewer;
|
|
119
124
|
exports.ServiceModeControl = __webpack_exports__.ServiceModeControl;
|
|
120
125
|
exports.ShinyText = __webpack_exports__.ShinyText;
|
|
121
126
|
exports.StaticContextProvider = __webpack_exports__.StaticContextProvider;
|
|
@@ -157,6 +162,7 @@ for(var __webpack_i__ in __webpack_exports__)if (-1 === [
|
|
|
157
162
|
"Player",
|
|
158
163
|
"PlaygroundResultView",
|
|
159
164
|
"PromptInput",
|
|
165
|
+
"ScreenshotViewer",
|
|
160
166
|
"ServiceModeControl",
|
|
161
167
|
"ShinyText",
|
|
162
168
|
"StaticContextProvider",
|
|
@@ -191,9 +191,9 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight)=>{
|
|
|
191
191
|
});
|
|
192
192
|
}
|
|
193
193
|
} else if ('Insight' === task.type && 'Locate' === task.subType) {
|
|
194
|
-
var
|
|
195
|
-
const
|
|
196
|
-
const resultElement = null == (
|
|
194
|
+
var _serviceTask_output;
|
|
195
|
+
const serviceTask = task;
|
|
196
|
+
const resultElement = null == (_serviceTask_output = serviceTask.output) ? void 0 : _serviceTask_output.element;
|
|
197
197
|
const title = (0, agent_namespaceObject.typeStr)(task);
|
|
198
198
|
const subTitle = (0, agent_namespaceObject.paramStr)(task);
|
|
199
199
|
if (null == resultElement ? void 0 : resultElement.rect) insightCameraState = {
|
|
@@ -201,10 +201,10 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight)=>{
|
|
|
201
201
|
pointerLeft: resultElement.center[0],
|
|
202
202
|
pointerTop: resultElement.center[1]
|
|
203
203
|
};
|
|
204
|
-
const context =
|
|
204
|
+
const context = serviceTask.uiContext;
|
|
205
205
|
if (null == context ? void 0 : context.screenshotBase64) {
|
|
206
|
-
var
|
|
207
|
-
const insightDump =
|
|
206
|
+
var _serviceTask_output1, _insightDump_taskInfo, _context_size, _context_size1;
|
|
207
|
+
const insightDump = serviceTask.log;
|
|
208
208
|
const insightContentLength = 0;
|
|
209
209
|
if (context.screenshotBase64) {
|
|
210
210
|
var _context_size2, _context_size3;
|
|
@@ -225,7 +225,7 @@ const generateAnimationScripts = (execution, task, imageWidth, imageHeight)=>{
|
|
|
225
225
|
img: context.screenshotBase64,
|
|
226
226
|
context: context,
|
|
227
227
|
camera: cameraState,
|
|
228
|
-
highlightElement: (null == (
|
|
228
|
+
highlightElement: (null == (_serviceTask_output1 = serviceTask.output) ? void 0 : _serviceTask_output1.element) || void 0,
|
|
229
229
|
searchArea: null == insightDump ? void 0 : null == (_insightDump_taskInfo = insightDump.taskInfo) ? void 0 : _insightDump_taskInfo.searchArea,
|
|
230
230
|
duration: insightContentLength > 20 ? locateDuration : 0.5 * locateDuration,
|
|
231
231
|
insightCameraDuration: locateDuration,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import './index.less';
|
|
2
|
+
interface ScreenshotViewerProps {
|
|
3
|
+
getScreenshot: () => Promise<{
|
|
4
|
+
screenshot: string;
|
|
5
|
+
timestamp: number;
|
|
6
|
+
} | null>;
|
|
7
|
+
getInterfaceInfo?: () => Promise<{
|
|
8
|
+
type: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
} | null>;
|
|
11
|
+
serverOnline: boolean;
|
|
12
|
+
isUserOperating?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export default function ScreenshotViewer({ getScreenshot, getInterfaceInfo, serverOnline, isUserOperating, }: ScreenshotViewerProps): import("react").JSX.Element;
|
|
15
|
+
export {};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import './component/playground/index.less';
|
|
2
2
|
import './component/universal-playground/index.less';
|
|
3
|
+
import './components/screenshot-viewer/index.less';
|
|
3
4
|
export { type AnimationScript, type ReplayScriptsInfo, allScriptsFromDump, generateAnimationScripts, } from './utils/replay-scripts';
|
|
4
5
|
export { useEnvConfig } from './store/store';
|
|
5
6
|
export { colorForName, highlightColorForType, globalThemeConfig, } from './utils/color';
|
|
@@ -18,6 +19,7 @@ export { ContextPreview } from './component/context-preview';
|
|
|
18
19
|
export { PromptInput } from './component/prompt-input';
|
|
19
20
|
export { Player } from './component/player';
|
|
20
21
|
export { Blackboard } from './component/blackboard';
|
|
22
|
+
export { default as ScreenshotViewer } from './components/screenshot-viewer';
|
|
21
23
|
export { actionNameForType, staticAgentFromContext, getPlaceholderForType, } from './utils/playground-utils';
|
|
22
24
|
export { timeStr, filterBase64Value } from './utils';
|
|
23
25
|
export { default as ShinyText } from './component/shiny-text';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midscene/visualizer",
|
|
3
|
-
"version": "1.0.1-beta-
|
|
3
|
+
"version": "1.0.1-beta-20251028065320.0",
|
|
4
4
|
"repository": "https://github.com/web-infra-dev/midscene",
|
|
5
5
|
"homepage": "https://midscenejs.com/",
|
|
6
6
|
"types": "./dist/types/index.d.ts",
|
|
@@ -60,10 +60,10 @@
|
|
|
60
60
|
"antd": "^5.21.6",
|
|
61
61
|
"buffer": "6.0.3",
|
|
62
62
|
"dayjs": "^1.11.11",
|
|
63
|
-
"@midscene/
|
|
64
|
-
"@midscene/web": "1.0.1-beta-
|
|
65
|
-
"@midscene/
|
|
66
|
-
"@midscene/shared": "1.0.1-beta-
|
|
63
|
+
"@midscene/playground": "1.0.1-beta-20251028065320.0",
|
|
64
|
+
"@midscene/web": "1.0.1-beta-20251028065320.0",
|
|
65
|
+
"@midscene/core": "1.0.1-beta-20251028065320.0",
|
|
66
|
+
"@midscene/shared": "1.0.1-beta-20251028065320.0"
|
|
67
67
|
},
|
|
68
68
|
"license": "MIT",
|
|
69
69
|
"scripts": {
|