@midscene/playground-app 1.8.0 → 1.8.1
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/SessionSetupPanel.css +8 -7
- package/dist/es/controller/usePlaygroundController.mjs +16 -9
- package/dist/es/panels/PlaygroundConversationPanel.mjs +1 -4
- package/dist/es/scrcpy-stream.mjs +6 -1
- package/dist/lib/SessionSetupPanel.css +8 -7
- package/dist/lib/controller/usePlaygroundController.js +15 -8
- package/dist/lib/panels/PlaygroundConversationPanel.js +1 -4
- package/dist/lib/scrcpy-stream.js +6 -1
- package/dist/types/controller/usePlaygroundController.d.ts +8 -1
- package/dist/types/scrcpy-stream.d.ts +2 -1
- package/package.json +4 -4
|
@@ -212,7 +212,8 @@
|
|
|
212
212
|
|
|
213
213
|
.platform-selector-group .ant-radio-button-wrapper {
|
|
214
214
|
white-space: normal;
|
|
215
|
-
|
|
215
|
+
border-color: var(--midscene-border-strong, #e9ecf3);
|
|
216
|
+
background: var(--midscene-surface-elevated, #fff);
|
|
216
217
|
border-radius: 14px;
|
|
217
218
|
justify-content: flex-start;
|
|
218
219
|
align-items: flex-start;
|
|
@@ -252,24 +253,24 @@
|
|
|
252
253
|
}
|
|
253
254
|
|
|
254
255
|
.platform-selector-group .ant-radio-button-wrapper:hover {
|
|
255
|
-
border-color: #1677ff;
|
|
256
|
+
border-color: var(--midscene-brand, #1677ff);
|
|
256
257
|
transform: translateY(-1px);
|
|
257
258
|
}
|
|
258
259
|
|
|
259
260
|
.platform-selector-group .ant-radio-button-wrapper-checked {
|
|
260
|
-
border-color: #1677ff;
|
|
261
|
+
border-color: var(--midscene-brand, #1677ff);
|
|
261
262
|
box-shadow: 0 10px 24px rgba(22, 119, 255, .12);
|
|
262
263
|
}
|
|
263
264
|
|
|
264
265
|
.platform-selector-card .platform-selector-title {
|
|
265
|
-
color: rgba(0, 0, 0, .88);
|
|
266
|
+
color: var(--midscene-text-primary, rgba(0, 0, 0, .88));
|
|
266
267
|
font-size: 15px;
|
|
267
268
|
font-weight: 600;
|
|
268
269
|
line-height: 1.4;
|
|
269
270
|
}
|
|
270
271
|
|
|
271
272
|
.platform-selector-card .platform-selector-description {
|
|
272
|
-
color: rgba(0, 0, 0, .5);
|
|
273
|
+
color: var(--midscene-text-tertiary, rgba(0, 0, 0, .5));
|
|
273
274
|
margin-top: 6px;
|
|
274
275
|
font-size: 12px;
|
|
275
276
|
line-height: 1.5;
|
|
@@ -283,11 +284,11 @@
|
|
|
283
284
|
}
|
|
284
285
|
|
|
285
286
|
.session-select-option-label {
|
|
286
|
-
color: rgba(0, 0, 0, .88);
|
|
287
|
+
color: var(--midscene-text-primary, rgba(0, 0, 0, .88));
|
|
287
288
|
}
|
|
288
289
|
|
|
289
290
|
.session-select-option-description {
|
|
290
|
-
color: rgba(0, 0, 0, .45);
|
|
291
|
+
color: var(--midscene-text-tertiary, rgba(0, 0, 0, .45));
|
|
291
292
|
font-size: 12px;
|
|
292
293
|
}
|
|
293
294
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PlaygroundSDK } from "@midscene/playground";
|
|
2
|
-
import { useEnvConfig } from "@midscene/visualizer";
|
|
2
|
+
import { notifyError, useEnvConfig } from "@midscene/visualizer";
|
|
3
3
|
import { Form, message } from "antd";
|
|
4
4
|
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
5
5
|
import { resolveAutoCreateSessionInput } from "../session-setup.mjs";
|
|
@@ -80,7 +80,7 @@ function getPlatformSelectorFieldKey(setup) {
|
|
|
80
80
|
var _setup_platformSelector;
|
|
81
81
|
return null == setup ? void 0 : null == (_setup_platformSelector = setup.platformSelector) ? void 0 : _setup_platformSelector.fieldKey;
|
|
82
82
|
}
|
|
83
|
-
function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollIntervalMs = 5000, countdownSeconds = 3, initialFormValues }) {
|
|
83
|
+
function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollIntervalMs = 5000, countdownSeconds = 3, initialFormValues, onCountdownFinish }) {
|
|
84
84
|
const [form] = Form.useForm();
|
|
85
85
|
const initialFormValuesRef = useRef(initialFormValues);
|
|
86
86
|
useLayoutEffect(()=>{
|
|
@@ -144,8 +144,9 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
144
144
|
appliedAiConfigSignatureRef.current = aiConfigSignature;
|
|
145
145
|
return true;
|
|
146
146
|
} catch (error) {
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
notifyError(error, {
|
|
148
|
+
title: 'Failed to apply AI configuration'
|
|
149
|
+
});
|
|
149
150
|
return false;
|
|
150
151
|
} finally{
|
|
151
152
|
if (pendingAiConfigApplicationRef.current === pendingApplicationState) pendingAiConfigApplicationRef.current = null;
|
|
@@ -160,6 +161,7 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
160
161
|
playgroundSDK
|
|
161
162
|
]);
|
|
162
163
|
const finishCountdown = useCallback(()=>{
|
|
164
|
+
const wasActive = null !== countdownTimerRef.current;
|
|
163
165
|
if (null !== countdownTimerRef.current) {
|
|
164
166
|
window.clearInterval(countdownTimerRef.current);
|
|
165
167
|
countdownTimerRef.current = null;
|
|
@@ -168,7 +170,10 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
168
170
|
countdownResolveRef.current = null;
|
|
169
171
|
if (mountedRef.current) setCountdown(null);
|
|
170
172
|
null == resolve || resolve();
|
|
171
|
-
|
|
173
|
+
if (wasActive && mountedRef.current) null == onCountdownFinish || onCountdownFinish();
|
|
174
|
+
}, [
|
|
175
|
+
onCountdownFinish
|
|
176
|
+
]);
|
|
172
177
|
const showCountdownModal = useCallback(()=>_async_to_generator(function*() {
|
|
173
178
|
if (countdownSeconds <= 0) return;
|
|
174
179
|
finishCountdown();
|
|
@@ -249,8 +254,9 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
249
254
|
return true;
|
|
250
255
|
} catch (error) {
|
|
251
256
|
if (error.errorFields) return false;
|
|
252
|
-
|
|
253
|
-
|
|
257
|
+
notifyError(error, {
|
|
258
|
+
title: 'Failed to create Agent'
|
|
259
|
+
});
|
|
254
260
|
return false;
|
|
255
261
|
} finally{
|
|
256
262
|
sessionMutatingRef.current = false;
|
|
@@ -273,8 +279,9 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
273
279
|
yield refreshServerState();
|
|
274
280
|
yield refreshSessionSetup();
|
|
275
281
|
} catch (error) {
|
|
276
|
-
|
|
277
|
-
|
|
282
|
+
notifyError(error, {
|
|
283
|
+
title: 'Failed to disconnect session'
|
|
284
|
+
});
|
|
278
285
|
} finally{
|
|
279
286
|
sessionMutatingRef.current = false;
|
|
280
287
|
setSessionMutating(false);
|
|
@@ -53,9 +53,6 @@ function PlaygroundConversationPanel({ controller, appVersion, title = 'Playgrou
|
|
|
53
53
|
onCancel: actions.finishCountdown,
|
|
54
54
|
centered: true,
|
|
55
55
|
width: 400,
|
|
56
|
-
style: {
|
|
57
|
-
top: '30%'
|
|
58
|
-
},
|
|
59
56
|
styles: {
|
|
60
57
|
mask: {
|
|
61
58
|
backgroundColor: 'rgba(0, 0, 0, 0.75)'
|
|
@@ -69,7 +66,7 @@ function PlaygroundConversationPanel({ controller, appVersion, title = 'Playgrou
|
|
|
69
66
|
children: [
|
|
70
67
|
/*#__PURE__*/ jsx("div", {
|
|
71
68
|
style: {
|
|
72
|
-
fontSize: '
|
|
69
|
+
fontSize: '120px',
|
|
73
70
|
fontWeight: 'bold',
|
|
74
71
|
color: 'GO!' === state.countdown ? '#52c41a' : '#1890ff',
|
|
75
72
|
marginBottom: '24px',
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
function toUint8Array(data) {
|
|
2
|
+
if (data instanceof Uint8Array) return data;
|
|
3
|
+
if (data instanceof ArrayBuffer) return new Uint8Array(data);
|
|
4
|
+
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
5
|
+
}
|
|
1
6
|
function createScrcpyVideoStream(socket) {
|
|
2
7
|
let configurationPacketSent = false;
|
|
3
8
|
let pendingDataPackets = [];
|
|
@@ -19,7 +24,7 @@ function createScrcpyVideoStream(socket) {
|
|
|
19
24
|
start (controller) {
|
|
20
25
|
const handleVideoData = (data)=>{
|
|
21
26
|
try {
|
|
22
|
-
const payload =
|
|
27
|
+
const payload = toUint8Array(data.data);
|
|
23
28
|
if ('configuration' === data.type) return void controller.enqueue({
|
|
24
29
|
type: 'configuration',
|
|
25
30
|
data: payload
|
|
@@ -212,7 +212,8 @@
|
|
|
212
212
|
|
|
213
213
|
.platform-selector-group .ant-radio-button-wrapper {
|
|
214
214
|
white-space: normal;
|
|
215
|
-
|
|
215
|
+
border-color: var(--midscene-border-strong, #e9ecf3);
|
|
216
|
+
background: var(--midscene-surface-elevated, #fff);
|
|
216
217
|
border-radius: 14px;
|
|
217
218
|
justify-content: flex-start;
|
|
218
219
|
align-items: flex-start;
|
|
@@ -252,24 +253,24 @@
|
|
|
252
253
|
}
|
|
253
254
|
|
|
254
255
|
.platform-selector-group .ant-radio-button-wrapper:hover {
|
|
255
|
-
border-color: #1677ff;
|
|
256
|
+
border-color: var(--midscene-brand, #1677ff);
|
|
256
257
|
transform: translateY(-1px);
|
|
257
258
|
}
|
|
258
259
|
|
|
259
260
|
.platform-selector-group .ant-radio-button-wrapper-checked {
|
|
260
|
-
border-color: #1677ff;
|
|
261
|
+
border-color: var(--midscene-brand, #1677ff);
|
|
261
262
|
box-shadow: 0 10px 24px rgba(22, 119, 255, .12);
|
|
262
263
|
}
|
|
263
264
|
|
|
264
265
|
.platform-selector-card .platform-selector-title {
|
|
265
|
-
color: rgba(0, 0, 0, .88);
|
|
266
|
+
color: var(--midscene-text-primary, rgba(0, 0, 0, .88));
|
|
266
267
|
font-size: 15px;
|
|
267
268
|
font-weight: 600;
|
|
268
269
|
line-height: 1.4;
|
|
269
270
|
}
|
|
270
271
|
|
|
271
272
|
.platform-selector-card .platform-selector-description {
|
|
272
|
-
color: rgba(0, 0, 0, .5);
|
|
273
|
+
color: var(--midscene-text-tertiary, rgba(0, 0, 0, .5));
|
|
273
274
|
margin-top: 6px;
|
|
274
275
|
font-size: 12px;
|
|
275
276
|
line-height: 1.5;
|
|
@@ -283,11 +284,11 @@
|
|
|
283
284
|
}
|
|
284
285
|
|
|
285
286
|
.session-select-option-label {
|
|
286
|
-
color: rgba(0, 0, 0, .88);
|
|
287
|
+
color: var(--midscene-text-primary, rgba(0, 0, 0, .88));
|
|
287
288
|
}
|
|
288
289
|
|
|
289
290
|
.session-select-option-description {
|
|
290
|
-
color: rgba(0, 0, 0, .45);
|
|
291
|
+
color: var(--midscene-text-tertiary, rgba(0, 0, 0, .45));
|
|
291
292
|
font-size: 12px;
|
|
292
293
|
}
|
|
293
294
|
|
|
@@ -108,7 +108,7 @@ function getPlatformSelectorFieldKey(setup) {
|
|
|
108
108
|
var _setup_platformSelector;
|
|
109
109
|
return null == setup ? void 0 : null == (_setup_platformSelector = setup.platformSelector) ? void 0 : _setup_platformSelector.fieldKey;
|
|
110
110
|
}
|
|
111
|
-
function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollIntervalMs = 5000, countdownSeconds = 3, initialFormValues }) {
|
|
111
|
+
function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollIntervalMs = 5000, countdownSeconds = 3, initialFormValues, onCountdownFinish }) {
|
|
112
112
|
const [form] = external_antd_namespaceObject.Form.useForm();
|
|
113
113
|
const initialFormValuesRef = (0, external_react_namespaceObject.useRef)(initialFormValues);
|
|
114
114
|
(0, external_react_namespaceObject.useLayoutEffect)(()=>{
|
|
@@ -172,8 +172,9 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
172
172
|
appliedAiConfigSignatureRef.current = aiConfigSignature;
|
|
173
173
|
return true;
|
|
174
174
|
} catch (error) {
|
|
175
|
-
|
|
176
|
-
|
|
175
|
+
(0, visualizer_namespaceObject.notifyError)(error, {
|
|
176
|
+
title: 'Failed to apply AI configuration'
|
|
177
|
+
});
|
|
177
178
|
return false;
|
|
178
179
|
} finally{
|
|
179
180
|
if (pendingAiConfigApplicationRef.current === pendingApplicationState) pendingAiConfigApplicationRef.current = null;
|
|
@@ -188,6 +189,7 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
188
189
|
playgroundSDK
|
|
189
190
|
]);
|
|
190
191
|
const finishCountdown = (0, external_react_namespaceObject.useCallback)(()=>{
|
|
192
|
+
const wasActive = null !== countdownTimerRef.current;
|
|
191
193
|
if (null !== countdownTimerRef.current) {
|
|
192
194
|
window.clearInterval(countdownTimerRef.current);
|
|
193
195
|
countdownTimerRef.current = null;
|
|
@@ -196,7 +198,10 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
196
198
|
countdownResolveRef.current = null;
|
|
197
199
|
if (mountedRef.current) setCountdown(null);
|
|
198
200
|
null == resolve || resolve();
|
|
199
|
-
|
|
201
|
+
if (wasActive && mountedRef.current) null == onCountdownFinish || onCountdownFinish();
|
|
202
|
+
}, [
|
|
203
|
+
onCountdownFinish
|
|
204
|
+
]);
|
|
200
205
|
const showCountdownModal = (0, external_react_namespaceObject.useCallback)(()=>_async_to_generator(function*() {
|
|
201
206
|
if (countdownSeconds <= 0) return;
|
|
202
207
|
finishCountdown();
|
|
@@ -277,8 +282,9 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
277
282
|
return true;
|
|
278
283
|
} catch (error) {
|
|
279
284
|
if (error.errorFields) return false;
|
|
280
|
-
|
|
281
|
-
|
|
285
|
+
(0, visualizer_namespaceObject.notifyError)(error, {
|
|
286
|
+
title: 'Failed to create Agent'
|
|
287
|
+
});
|
|
282
288
|
return false;
|
|
283
289
|
} finally{
|
|
284
290
|
sessionMutatingRef.current = false;
|
|
@@ -301,8 +307,9 @@ function usePlaygroundController({ serverUrl, defaultDeviceType = 'web', pollInt
|
|
|
301
307
|
yield refreshServerState();
|
|
302
308
|
yield refreshSessionSetup();
|
|
303
309
|
} catch (error) {
|
|
304
|
-
|
|
305
|
-
|
|
310
|
+
(0, visualizer_namespaceObject.notifyError)(error, {
|
|
311
|
+
title: 'Failed to disconnect session'
|
|
312
|
+
});
|
|
306
313
|
} finally{
|
|
307
314
|
sessionMutatingRef.current = false;
|
|
308
315
|
setSessionMutating(false);
|
|
@@ -81,9 +81,6 @@ function PlaygroundConversationPanel({ controller, appVersion, title = 'Playgrou
|
|
|
81
81
|
onCancel: actions.finishCountdown,
|
|
82
82
|
centered: true,
|
|
83
83
|
width: 400,
|
|
84
|
-
style: {
|
|
85
|
-
top: '30%'
|
|
86
|
-
},
|
|
87
84
|
styles: {
|
|
88
85
|
mask: {
|
|
89
86
|
backgroundColor: 'rgba(0, 0, 0, 0.75)'
|
|
@@ -97,7 +94,7 @@ function PlaygroundConversationPanel({ controller, appVersion, title = 'Playgrou
|
|
|
97
94
|
children: [
|
|
98
95
|
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
|
|
99
96
|
style: {
|
|
100
|
-
fontSize: '
|
|
97
|
+
fontSize: '120px',
|
|
101
98
|
fontWeight: 'bold',
|
|
102
99
|
color: 'GO!' === state.countdown ? '#52c41a' : '#1890ff',
|
|
103
100
|
marginBottom: '24px',
|
|
@@ -26,6 +26,11 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
26
26
|
__webpack_require__.d(__webpack_exports__, {
|
|
27
27
|
createScrcpyVideoStream: ()=>createScrcpyVideoStream
|
|
28
28
|
});
|
|
29
|
+
function toUint8Array(data) {
|
|
30
|
+
if (data instanceof Uint8Array) return data;
|
|
31
|
+
if (data instanceof ArrayBuffer) return new Uint8Array(data);
|
|
32
|
+
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
33
|
+
}
|
|
29
34
|
function createScrcpyVideoStream(socket) {
|
|
30
35
|
let configurationPacketSent = false;
|
|
31
36
|
let pendingDataPackets = [];
|
|
@@ -47,7 +52,7 @@ function createScrcpyVideoStream(socket) {
|
|
|
47
52
|
start (controller) {
|
|
48
53
|
const handleVideoData = (data)=>{
|
|
49
54
|
try {
|
|
50
|
-
const payload =
|
|
55
|
+
const payload = toUint8Array(data.data);
|
|
51
56
|
if ('configuration' === data.type) return void controller.enqueue({
|
|
52
57
|
type: 'configuration',
|
|
53
58
|
data: payload
|
|
@@ -12,5 +12,12 @@ export interface UsePlaygroundControllerOptions {
|
|
|
12
12
|
* returning a generic "Choose a platform" setup.
|
|
13
13
|
*/
|
|
14
14
|
initialFormValues?: Record<string, unknown>;
|
|
15
|
+
/**
|
|
16
|
+
* Invoked when an active countdown dismisses — either reaching its natural
|
|
17
|
+
* end or being skipped by the user. Lets hosts step out of the way before
|
|
18
|
+
* automation begins (Studio minimises so the controlled desktop is in
|
|
19
|
+
* view). Not fired during unmount cleanup.
|
|
20
|
+
*/
|
|
21
|
+
onCountdownFinish?: () => void;
|
|
15
22
|
}
|
|
16
|
-
export declare function usePlaygroundController({ serverUrl, defaultDeviceType, pollIntervalMs, countdownSeconds, initialFormValues, }: UsePlaygroundControllerOptions): PlaygroundControllerResult;
|
|
23
|
+
export declare function usePlaygroundController({ serverUrl, defaultDeviceType, pollIntervalMs, countdownSeconds, initialFormValues, onCountdownFinish, }: UsePlaygroundControllerOptions): PlaygroundControllerResult;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { ScrcpyMediaStreamPacket } from '@yume-chan/scrcpy';
|
|
2
|
+
type RawScrcpyVideoData = ArrayBuffer | ArrayBufferView;
|
|
2
3
|
interface RawScrcpyVideoPacket {
|
|
3
4
|
type?: string;
|
|
4
|
-
data:
|
|
5
|
+
data: RawScrcpyVideoData;
|
|
5
6
|
keyFrame?: boolean;
|
|
6
7
|
}
|
|
7
8
|
interface ScrcpyVideoSocketLike {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midscene/playground-app",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "Reusable React shell for Midscene playground applications",
|
|
5
5
|
"repository": "https://github.com/web-infra-dev/midscene",
|
|
6
6
|
"homepage": "https://midscenejs.com/",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
"antd": "^5.21.6",
|
|
29
29
|
"react-resizable-panels": "2.0.22",
|
|
30
30
|
"socket.io-client": "4.8.1",
|
|
31
|
-
"@midscene/playground": "1.8.
|
|
32
|
-
"@midscene/shared": "1.8.
|
|
33
|
-
"@midscene/visualizer": "1.8.
|
|
31
|
+
"@midscene/playground": "1.8.1",
|
|
32
|
+
"@midscene/shared": "1.8.1",
|
|
33
|
+
"@midscene/visualizer": "1.8.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@rsbuild/plugin-less": "^1.5.0",
|