@xenon-device-management/xenon 1.1.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 +446 -0
- package/lib/package.json +207 -0
- package/lib/public/assets/Layouts-7IT8aFLI.js +11 -0
- package/lib/public/assets/Layouts-DPMls9vh.css +1 -0
- package/lib/public/assets/ai-settings-BbnfgdEx.js +11 -0
- package/lib/public/assets/apps-CRMrI4_p.js +16 -0
- package/lib/public/assets/apps-CcM77dgg.css +1 -0
- package/lib/public/assets/badge-B1nKs8zj.css +1 -0
- package/lib/public/assets/badge-CSvl5xIU.js +11 -0
- package/lib/public/assets/button-CJlKn4PZ.css +1 -0
- package/lib/public/assets/button-CvLaGFYj.js +26 -0
- package/lib/public/assets/calendar-6w-D6Oaw.js +6 -0
- package/lib/public/assets/clock-DcdeWBPr.js +6 -0
- package/lib/public/assets/cpu-DiSoXT9n.js +6 -0
- package/lib/public/assets/device-explorer-CajM63OJ.js +193 -0
- package/lib/public/assets/device-explorer-CxdUAoTL.css +1 -0
- package/lib/public/assets/index-ByQwMN5T.js +174 -0
- package/lib/public/assets/index-C1DBaoSh.js +1 -0
- package/lib/public/assets/index-qzCez_kk.css +1 -0
- package/lib/public/assets/lock-B23ibZmo.js +6 -0
- package/lib/public/assets/maintenance-settings-CirzA6yG.js +6 -0
- package/lib/public/assets/mouse-pointer-2-Cz76SHFb.js +6 -0
- package/lib/public/assets/plus-BBwlIevt.js +6 -0
- package/lib/public/assets/session-dashboard-C2k7FFv_.css +1 -0
- package/lib/public/assets/session-dashboard-HPDtwPOZ.js +62 -0
- package/lib/public/assets/settings-DrZsZwdc.js +1 -0
- package/lib/public/assets/trash-2-DQpvzJec.js +6 -0
- package/lib/public/assets/useSocket-Dxsqae2a.js +16 -0
- package/lib/public/assets/webhook-settings-CDPgsgkb.css +1 -0
- package/lib/public/assets/webhook-settings-Cp-B4Nrw.js +1 -0
- package/lib/public/assets/zap-DovP6iow.js +6 -0
- package/lib/public/favicon.ico +0 -0
- package/lib/public/favicon.png +0 -0
- package/lib/public/favicon.svg +9 -0
- package/lib/public/index.html +46 -0
- package/lib/public/logo.svg +17 -0
- package/lib/public/logo192.png +0 -0
- package/lib/public/logo512.png +0 -0
- package/lib/public/manifest.json +25 -0
- package/lib/public/robots.txt +3 -0
- package/lib/schema.json +348 -0
- package/lib/src/InternalHttpClient.js +212 -0
- package/lib/src/PluginContext.js +29 -0
- package/lib/src/XenonCapabilityManager.js +199 -0
- package/lib/src/app/index.js +167 -0
- package/lib/src/app/routers/apps.js +79 -0
- package/lib/src/app/routers/config.js +131 -0
- package/lib/src/app/routers/control.js +835 -0
- package/lib/src/app/routers/dashboard.js +301 -0
- package/lib/src/app/routers/grid.js +352 -0
- package/lib/src/app/routers/reservation.js +190 -0
- package/lib/src/app/routers/webhook.js +83 -0
- package/lib/src/app/swagger-docs.js +203 -0
- package/lib/src/app/swagger.js +366 -0
- package/lib/src/chromeUtils.js +148 -0
- package/lib/src/commands/handle.js +19 -0
- package/lib/src/commands/index.js +8 -0
- package/lib/src/config.js +73 -0
- package/lib/src/dashboard/asset-manager.js +84 -0
- package/lib/src/dashboard/commands.js +284 -0
- package/lib/src/dashboard/event-manager.js +699 -0
- package/lib/src/dashboard/services/app-service.js +134 -0
- package/lib/src/dashboard/services/failure-analysis-service.js +173 -0
- package/lib/src/dashboard/services/session-service.js +113 -0
- package/lib/src/data-service/CircuitBreaker.js +83 -0
- package/lib/src/data-service/config-service.js +155 -0
- package/lib/src/data-service/db.js +122 -0
- package/lib/src/data-service/device-service.js +320 -0
- package/lib/src/data-service/device-store.interface.js +2 -0
- package/lib/src/data-service/device-store.js +345 -0
- package/lib/src/data-service/pending-sessions-service.js +25 -0
- package/lib/src/data-service/pluginArgs.js +25 -0
- package/lib/src/data-service/prisma-service.js +31 -0
- package/lib/src/data-service/prisma-store.js +385 -0
- package/lib/src/data-service/queue-service.js +150 -0
- package/lib/src/data-service/web-config-service.js +130 -0
- package/lib/src/device-managers/AndroidDeviceManager.js +1155 -0
- package/lib/src/device-managers/ChromeDriverManager.js +68 -0
- package/lib/src/device-managers/HealthMonitorService.js +325 -0
- package/lib/src/device-managers/IOSDeviceManager.js +351 -0
- package/lib/src/device-managers/NodeDevices.js +82 -0
- package/lib/src/device-managers/android/AndroidStreamService.js +370 -0
- package/lib/src/device-managers/android/DeviceLockManager.js +45 -0
- package/lib/src/device-managers/cloud/CapabilityManager.js +26 -0
- package/lib/src/device-managers/cloud/Devices.js +86 -0
- package/lib/src/device-managers/iOSTracker.js +44 -0
- package/lib/src/device-managers/index.js +89 -0
- package/lib/src/device-managers/ios/IOSDiscoveryService.js +268 -0
- package/lib/src/device-managers/ios/IOSStreamService.js +893 -0
- package/lib/src/device-managers/ios/WDAClient.js +866 -0
- package/lib/src/device-utils.js +663 -0
- package/lib/src/enums/Capabilities.js +8 -0
- package/lib/src/enums/Cloud.js +11 -0
- package/lib/src/enums/Platform.js +9 -0
- package/lib/src/enums/SessionType.js +9 -0
- package/lib/src/enums/SocketEvents.js +15 -0
- package/lib/src/helpers/UniversalMjpegProxy.js +273 -0
- package/lib/src/helpers/index.js +229 -0
- package/lib/src/index.js +95 -0
- package/lib/src/interceptors/CommandInterceptor.js +524 -0
- package/lib/src/interfaces/ICloudManager.js +2 -0
- package/lib/src/interfaces/IDevice.js +2 -0
- package/lib/src/interfaces/IDeviceFilterOptions.js +2 -0
- package/lib/src/interfaces/IDeviceManager.js +2 -0
- package/lib/src/interfaces/IOptions.js +2 -0
- package/lib/src/interfaces/IPluginArgs.js +55 -0
- package/lib/src/interfaces/ISessionCapability.js +2 -0
- package/lib/src/logger.js +225 -0
- package/lib/src/plugin.js +244 -0
- package/lib/src/prisma.js +12 -0
- package/lib/src/profiling/AndroidAppProfiler.js +213 -0
- package/lib/src/proxy/wd-command-proxy.js +221 -0
- package/lib/src/scripts/generate-database-migration.js +59 -0
- package/lib/src/scripts/initialize-database.js +55 -0
- package/lib/src/scripts/install-go-ios.js +66 -0
- package/lib/src/scripts/prepare-prisma.js +89 -0
- package/lib/src/services/AICommandService.js +143 -0
- package/lib/src/services/AIService.js +466 -0
- package/lib/src/services/CleanupService.js +141 -0
- package/lib/src/services/EventBus.js +74 -0
- package/lib/src/services/InspectorService.js +395 -0
- package/lib/src/services/MetricsService.js +134 -0
- package/lib/src/services/NetworkConditioningService.js +173 -0
- package/lib/src/services/NotificationService.js +163 -0
- package/lib/src/services/RequestLogService.js +252 -0
- package/lib/src/services/ResourceIsolationService.js +122 -0
- package/lib/src/services/SecurityService.js +120 -0
- package/lib/src/services/ServerManager.js +284 -0
- package/lib/src/services/SessionHeartbeatService.js +158 -0
- package/lib/src/services/SessionLifecycleService.js +572 -0
- package/lib/src/services/SocketClient.js +71 -0
- package/lib/src/services/SocketServer.js +87 -0
- package/lib/src/services/TracingService.js +132 -0
- package/lib/src/services/VideoPipelineService.js +220 -0
- package/lib/src/services/healing/FuzzyXmlHealingProvider.js +333 -0
- package/lib/src/services/healing/HealEtalonService.js +98 -0
- package/lib/src/services/healing/HealedLocatorGenerator.js +132 -0
- package/lib/src/services/healing/HealingOrchestrator.js +165 -0
- package/lib/src/services/healing/LlmHealingProvider.js +77 -0
- package/lib/src/services/healing/OcrHealingProvider.js +119 -0
- package/lib/src/services/healing/ResilioTreeHealingProvider.js +100 -0
- package/lib/src/services/healing/VisualAiHealingProvider.js +90 -0
- package/lib/src/services/healing/types.js +12 -0
- package/lib/src/services/omni-vision/OmniVisionService.js +718 -0
- package/lib/src/services/omni-vision/VisionAssertionService.js +68 -0
- package/lib/src/sessions/CloudSession.js +42 -0
- package/lib/src/sessions/LocalSession.js +313 -0
- package/lib/src/sessions/RemoteSession.js +287 -0
- package/lib/src/sessions/SessionManager.js +238 -0
- package/lib/src/sessions/XenonSession.js +44 -0
- package/lib/src/types/CLIArgs.js +2 -0
- package/lib/src/types/CloudArgs.js +2 -0
- package/lib/src/types/CloudSchema.js +131 -0
- package/lib/src/types/DeviceType.js +2 -0
- package/lib/src/types/DeviceUpdate.js +2 -0
- package/lib/src/types/IOSDevice.js +2 -0
- package/lib/src/types/Platform.js +2 -0
- package/lib/src/types/SessionStatus.js +11 -0
- package/lib/src/validators/CapabilityValidator.js +93 -0
- package/lib/test/e2e/android/conf.spec.js +43 -0
- package/lib/test/e2e/android/conf2.spec.js +44 -0
- package/lib/test/e2e/android/conf3.spec.js +44 -0
- package/lib/test/e2e/e2ehelper.js +113 -0
- package/lib/test/e2e/hubnode/forward-request.spec.js +224 -0
- package/lib/test/e2e/hubnode/hubnode.spec.js +214 -0
- package/lib/test/e2e/ios/conf1.spec.js +39 -0
- package/lib/test/e2e/ios/conf2.spec.js +39 -0
- package/lib/test/e2e/plugin-harness.js +236 -0
- package/lib/test/e2e/plugin.spec.js +97 -0
- package/lib/test/e2e/telemetry_verification.spec.js +83 -0
- package/lib/test/e2e/video-recording-test.spec.js +63 -0
- package/lib/test/helpers/test-container.js +112 -0
- package/lib/test/integration/androidDevices.spec.js +137 -0
- package/lib/test/integration/cliArgs.js +73 -0
- package/lib/test/integration/ios/01iOSSimulator.spec.js +291 -0
- package/lib/test/integration/ios/02iOSDevices.spec.js +75 -0
- package/lib/test/integration/testHelpers.js +74 -0
- package/lib/test/unit/AndroidDeviceManager.spec.js +178 -0
- package/lib/test/unit/ChromeDriverManager.spec.js +26 -0
- package/lib/test/unit/CleanupService.spec.js +21 -0
- package/lib/test/unit/DeviceModel.spec.js +157 -0
- package/lib/test/unit/FuzzyXmlHealingProvider.test.js +294 -0
- package/lib/test/unit/GetAdbOriginal.js +42 -0
- package/lib/test/unit/HealingCascade.test.js +128 -0
- package/lib/test/unit/IOSDeviceManager.spec.js +261 -0
- package/lib/test/unit/RemoteIOs.spec.js +78 -0
- package/lib/test/unit/ResilioTreeHealingProvider.test.js +96 -0
- package/lib/test/unit/commands.spec.js +27 -0
- package/lib/test/unit/config.spec.js +27 -0
- package/lib/test/unit/device-service.spec.js +307 -0
- package/lib/test/unit/device-utils.spec.js +313 -0
- package/lib/test/unit/fixtures/device.config.js +4 -0
- package/lib/test/unit/fixtures/devices.js +89 -0
- package/lib/test/unit/helpers.spec.js +62 -0
- package/lib/test/unit/omni-vision.spec.js +100 -0
- package/lib/test/unit/plugin.spec.js +133 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +207 -0
- package/prisma/data.db +0 -0
- package/prisma/dev.db +0 -0
- package/prisma/dev.db-journal +0 -0
- package/prisma/migrations/20231011074725_initial_tables/migration.sql +47 -0
- package/prisma/migrations/20231226115334_update_session_log/migration.sql +2 -0
- package/prisma/migrations/20251204113710_add_video_recording_enabled/migration.sql +29 -0
- package/prisma/migrations/20251204132449_add_log_table/migration.sql +11 -0
- package/prisma/migrations/20251205050111_add_profiling_support/migration.sql +47 -0
- package/prisma/migrations/20251205050947_add_is_error_field/migration.sql +24 -0
- package/prisma/migrations/20260126201337_add_app_model/migration.sql +18 -0
- package/prisma/migrations/20260130115722_add_performance_trace_and_xenon_sync/migration.sql +2 -0
- package/prisma/migrations/20260130135114_add_device_models/migration.sql +57 -0
- package/prisma/migrations/20260130140655_make_systemport_optional/migration.sql +45 -0
- package/prisma/migrations/20260130140932_make_device_fields_optional/migration.sql +45 -0
- package/prisma/migrations/20260130141040_final_schema_fix/migration.sql +45 -0
- package/prisma/migrations/20260130143234_add_device_health_fields/migration.sql +4 -0
- package/prisma/migrations/20260130144921_add_failure_category/migration.sql +2 -0
- package/prisma/migrations/20260131151456_add_webhook_config/migration.sql +10 -0
- package/prisma/migrations/20260201094507_add_device_tags/migration.sql +11 -0
- package/prisma/migrations/20260201103410_add_managed_process/migration.sql +15 -0
- package/prisma/migrations/20260201140637_add_web_config/migration.sql +22 -0
- package/prisma/migrations/20260201162232_add_session_progress/migration.sql +2 -0
- package/prisma/migrations/20260201174231_add_total_healed_count/migration.sql +2 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +210 -0
- package/schema.json +348 -0
- package/scripts/build-xenon.sh +32 -0
- package/scripts/dev/debug-gemini.ts +44 -0
- package/scripts/generate-types-from-schema.js +86 -0
- package/scripts/install-compatible-driver.js +39 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import{c as I,r,a as Cs,j as e,X as Ke,C as Ss,u as us,b as Qe,R as Fe,S as Je,d as Ze,e as ps,T as $s,f as vs,L as We,g as ss}from"./index-ByQwMN5T.js";import{p as ts,H as Ds,C as xs,a as Ve,u as As}from"./useSocket-Dxsqae2a.js";import{X as D}from"./index-C1DBaoSh.js";import{C as gs}from"./clock-DcdeWBPr.js";import{P as fs}from"./plus-BBwlIevt.js";import{A as ys,T as js,C as qe,a as Xe,U as Ls,B as Ge}from"./button-CvLaGFYj.js";import{M as Ts}from"./mouse-pointer-2-Cz76SHFb.js";import{S as es,D as Es,B as Me}from"./badge-CSvl5xIU.js";import{Z as zs}from"./zap-DovP6iow.js";import{L as Is}from"./lock-B23ibZmo.js";import{T as _e}from"./trash-2-DQpvzJec.js";/**
|
|
2
|
+
* @license lucide-react v0.555.0 - ISC
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the ISC license.
|
|
5
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/const Rs=[["path",{d:"M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z",key:"hh9hay"}],["path",{d:"m3.3 7 8.7 5 8.7-5",key:"g66t2b"}],["path",{d:"M12 22V12",key:"d0xqtd"}]],Ms=I("box",Rs);/**
|
|
7
|
+
* @license lucide-react v0.555.0 - ISC
|
|
8
|
+
*
|
|
9
|
+
* This source code is licensed under the ISC license.
|
|
10
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
11
|
+
*/const _s=[["path",{d:"M16 19h6",key:"xwg31i"}],["path",{d:"M16 2v4",key:"4m81vk"}],["path",{d:"M19 16v6",key:"tddt3s"}],["path",{d:"M21 12.598V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8.5",key:"1glfrc"}],["path",{d:"M3 10h18",key:"8toen8"}],["path",{d:"M8 2v4",key:"1cmpym"}]],bs=I("calendar-plus",_s);/**
|
|
12
|
+
* @license lucide-react v0.555.0 - ISC
|
|
13
|
+
*
|
|
14
|
+
* This source code is licensed under the ISC license.
|
|
15
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
16
|
+
*/const Us=[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]],is=I("chevron-left",Us);/**
|
|
17
|
+
* @license lucide-react v0.555.0 - ISC
|
|
18
|
+
*
|
|
19
|
+
* This source code is licensed under the ISC license.
|
|
20
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
21
|
+
*/const Os=[["path",{d:"m18 15-6-6-6 6",key:"153udz"}]],Fs=I("chevron-up",Os);/**
|
|
22
|
+
* @license lucide-react v0.555.0 - ISC
|
|
23
|
+
*
|
|
24
|
+
* This source code is licensed under the ISC license.
|
|
25
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
26
|
+
*/const Hs=[["rect",{width:"8",height:"4",x:"8",y:"2",rx:"1",ry:"1",key:"tgr4d6"}],["path",{d:"M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2",key:"116196"}]],Ps=I("clipboard",Hs);/**
|
|
27
|
+
* @license lucide-react v0.555.0 - ISC
|
|
28
|
+
*
|
|
29
|
+
* This source code is licensed under the ISC license.
|
|
30
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
31
|
+
*/const Bs=[["path",{d:"m18 16 4-4-4-4",key:"1inbqp"}],["path",{d:"m6 8-4 4 4 4",key:"15zrgr"}],["path",{d:"m14.5 4-5 16",key:"e7oirm"}]],as=I("code-xml",Bs);/**
|
|
32
|
+
* @license lucide-react v0.555.0 - ISC
|
|
33
|
+
*
|
|
34
|
+
* This source code is licensed under the ISC license.
|
|
35
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
36
|
+
*/const Ws=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]],Vs=I("file-text",Ws);/**
|
|
37
|
+
* @license lucide-react v0.555.0 - ISC
|
|
38
|
+
*
|
|
39
|
+
* This source code is licensed under the ISC license.
|
|
40
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
41
|
+
*/const qs=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M3 9h18",key:"1pudct"}],["path",{d:"M3 15h18",key:"5xshup"}],["path",{d:"M9 3v18",key:"fh3hqa"}],["path",{d:"M15 3v18",key:"14nvp0"}]],Xs=I("grid-3x3",qs);/**
|
|
42
|
+
* @license lucide-react v0.555.0 - ISC
|
|
43
|
+
*
|
|
44
|
+
* This source code is licensed under the ISC license.
|
|
45
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
46
|
+
*/const Gs=[["path",{d:"M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8",key:"5wwlr5"}],["path",{d:"M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",key:"r6nss1"}]],Ys=I("house",Gs);/**
|
|
47
|
+
* @license lucide-react v0.555.0 - ISC
|
|
48
|
+
*
|
|
49
|
+
* This source code is licensed under the ISC license.
|
|
50
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
51
|
+
*/const Ks=[["path",{d:"M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z",key:"zw3jo"}],["path",{d:"M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12",key:"1wduqc"}],["path",{d:"M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17",key:"kqbvx6"}]],Js=I("layers",Ks);/**
|
|
52
|
+
* @license lucide-react v0.555.0 - ISC
|
|
53
|
+
*
|
|
54
|
+
* This source code is licensed under the ISC license.
|
|
55
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
56
|
+
*/const Zs=[["path",{d:"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5",key:"1gvzjb"}],["path",{d:"M9 18h6",key:"x1upvd"}],["path",{d:"M10 22h4",key:"ceow96"}]],Qs=I("lightbulb",Zs);/**
|
|
57
|
+
* @license lucide-react v0.555.0 - ISC
|
|
58
|
+
*
|
|
59
|
+
* This source code is licensed under the ISC license.
|
|
60
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
61
|
+
*/const et=[["rect",{width:"18",height:"11",x:"3",y:"11",rx:"2",ry:"2",key:"1w4ew1"}],["path",{d:"M7 11V7a5 5 0 0 1 9.9-1",key:"1mm8w8"}]],Ns=I("lock-open",et);/**
|
|
62
|
+
* @license lucide-react v0.555.0 - ISC
|
|
63
|
+
*
|
|
64
|
+
* This source code is licensed under the ISC license.
|
|
65
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
66
|
+
*/const st=[["path",{d:"M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0",key:"1r0f0z"}],["circle",{cx:"12",cy:"10",r:"3",key:"ilqhr7"}]],tt=I("map-pin",st);/**
|
|
67
|
+
* @license lucide-react v0.555.0 - ISC
|
|
68
|
+
*
|
|
69
|
+
* This source code is licensed under the ISC license.
|
|
70
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
71
|
+
*/const it=[["path",{d:"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z",key:"18887p"}]],at=I("message-square",it);/**
|
|
72
|
+
* @license lucide-react v0.555.0 - ISC
|
|
73
|
+
*
|
|
74
|
+
* This source code is licensed under the ISC license.
|
|
75
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
76
|
+
*/const nt=[["rect",{width:"20",height:"14",x:"2",y:"3",rx:"2",key:"48i651"}],["line",{x1:"8",x2:"16",y1:"21",y2:"21",key:"1svkeh"}],["line",{x1:"12",x2:"12",y1:"17",y2:"21",key:"vw1qmm"}]],ns=I("monitor",nt);/**
|
|
77
|
+
* @license lucide-react v0.555.0 - ISC
|
|
78
|
+
*
|
|
79
|
+
* This source code is licensed under the ISC license.
|
|
80
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
81
|
+
*/const rt=[["path",{d:"M12 2v20",key:"t6zp3m"}],["path",{d:"m15 19-3 3-3-3",key:"11eu04"}],["path",{d:"m19 9 3 3-3 3",key:"1mg7y2"}],["path",{d:"M2 12h20",key:"9i4pu4"}],["path",{d:"m5 9-3 3 3 3",key:"j64kie"}],["path",{d:"m9 5 3-3 3 3",key:"l8vdw6"}]],ct=I("move",rt);/**
|
|
82
|
+
* @license lucide-react v0.555.0 - ISC
|
|
83
|
+
*
|
|
84
|
+
* This source code is licensed under the ISC license.
|
|
85
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
86
|
+
*/const lt=[["path",{d:"M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z",key:"1a0edw"}],["path",{d:"M12 22V12",key:"d0xqtd"}],["polyline",{points:"3.29 7 12 12 20.71 7",key:"ousv84"}],["path",{d:"m7.5 4.27 9 5.15",key:"1c824w"}]],ot=I("package",lt);/**
|
|
87
|
+
* @license lucide-react v0.555.0 - ISC
|
|
88
|
+
*
|
|
89
|
+
* This source code is licensed under the ISC license.
|
|
90
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
91
|
+
*/const dt=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M3 9h18",key:"1pudct"}],["path",{d:"M9 21V9",key:"1oto5p"}]],ht=I("panels-top-left",dt);/**
|
|
92
|
+
* @license lucide-react v0.555.0 - ISC
|
|
93
|
+
*
|
|
94
|
+
* This source code is licensed under the ISC license.
|
|
95
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
96
|
+
*/const mt=[["path",{d:"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8",key:"1p45f6"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}]],Oe=I("rotate-cw",mt);/**
|
|
97
|
+
* @license lucide-react v0.555.0 - ISC
|
|
98
|
+
*
|
|
99
|
+
* This source code is licensed under the ISC license.
|
|
100
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
101
|
+
*/const ut=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"M12 8v4",key:"1got3b"}],["path",{d:"M12 16h.01",key:"1drbdi"}]],rs=I("shield-alert",ut);/**
|
|
102
|
+
* @license lucide-react v0.555.0 - ISC
|
|
103
|
+
*
|
|
104
|
+
* This source code is licensed under the ISC license.
|
|
105
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
106
|
+
*/const pt=[["path",{d:"M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",key:"1s2grr"}],["path",{d:"M20 2v4",key:"1rf3ol"}],["path",{d:"M22 4h-4",key:"gwowj6"}],["circle",{cx:"4",cy:"20",r:"2",key:"6kqj1y"}]],cs=I("sparkles",pt);/**
|
|
107
|
+
* @license lucide-react v0.555.0 - ISC
|
|
108
|
+
*
|
|
109
|
+
* This source code is licensed under the ISC license.
|
|
110
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
111
|
+
*/const vt=[["path",{d:"M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z",key:"vktsd0"}],["circle",{cx:"7.5",cy:"7.5",r:".5",fill:"currentColor",key:"kqv944"}]],xt=I("tag",vt);/**
|
|
112
|
+
* @license lucide-react v0.555.0 - ISC
|
|
113
|
+
*
|
|
114
|
+
* This source code is licensed under the ISC license.
|
|
115
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
116
|
+
*/const gt=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["circle",{cx:"12",cy:"12",r:"6",key:"1vlfrh"}],["circle",{cx:"12",cy:"12",r:"2",key:"1c9p78"}]],ls=I("target",gt);/**
|
|
117
|
+
* @license lucide-react v0.555.0 - ISC
|
|
118
|
+
*
|
|
119
|
+
* This source code is licensed under the ISC license.
|
|
120
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
121
|
+
*/const ft=[["path",{d:"M14 4v10.54a4 4 0 1 1-4 0V4a2 2 0 0 1 4 0Z",key:"17jzev"}]],yt=I("thermometer",ft);/**
|
|
122
|
+
* @license lucide-react v0.555.0 - ISC
|
|
123
|
+
*
|
|
124
|
+
* This source code is licensed under the ISC license.
|
|
125
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
126
|
+
*/const jt=[["rect",{width:"20",height:"16",x:"2",y:"4",rx:"2",key:"18n3k1"}],["path",{d:"M2 14h20",key:"myj16y"}],["path",{d:"M12 20v-6",key:"1rm09r"}]],bt=I("touchpad",jt);/**
|
|
127
|
+
* @license lucide-react v0.555.0 - ISC
|
|
128
|
+
*
|
|
129
|
+
* This source code is licensed under the ISC license.
|
|
130
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
131
|
+
*/const Nt=[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]],wt=I("user",Nt);/**
|
|
132
|
+
* @license lucide-react v0.555.0 - ISC
|
|
133
|
+
*
|
|
134
|
+
* This source code is licensed under the ISC license.
|
|
135
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
136
|
+
*/const kt=[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M2 8.82a15 15 0 0 1 20 0",key:"dnpr2z"}],["path",{d:"M5 12.859a10 10 0 0 1 14 0",key:"1x1e6c"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}]],ws=I("wifi",kt);/**
|
|
137
|
+
* @license lucide-react v0.555.0 - ISC
|
|
138
|
+
*
|
|
139
|
+
* This source code is licensed under the ISC license.
|
|
140
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
141
|
+
*/const Ct=[["path",{d:"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z",key:"1ngwbx"}]],St=I("wrench",Ct),$t=[{label:"1 Hour",value:"1h"},{label:"2 Hours",value:"2h"},{label:"4 Hours",value:"4h"},{label:"8 Hours",value:"8h"}],Dt=({device:n,onClose:s,onReserved:l})=>{const[u,p]=r.useState(""),[t,T]=r.useState("1h"),[v,x]=r.useState(""),[h,m]=r.useState(!1),[A,S]=r.useState(null),U=async()=>{if(!u.trim()){S("Please enter your name/ID");return}m(!0),S(null);try{const w=await D.reserveDevice(n.udid,n.host,u,t,v);w.success?(l(),s()):S(w.error||"Failed to reserve device")}catch(w){S(w.message||"An unexpected error occurred")}finally{m(!1)}};return Cs.createPortal(e.jsx("div",{className:"reservation-modal-overlay",onClick:s,children:e.jsxs("div",{className:"reservation-modal",onClick:w=>w.stopPropagation(),children:[e.jsx("div",{className:"scanline",style:{position:"absolute",inset:0,pointerEvents:"none",opacity:.05,zIndex:1001}}),e.jsxs("div",{className:"reservation-modal-header",children:[e.jsxs("div",{className:"reservation-modal-title",children:[e.jsx(bs,{size:18,className:"title-icon"}),"Reserve Device"]}),e.jsx("button",{className:"close-btn",onClick:s,children:e.jsx(Ke,{size:20})})]}),e.jsxs("div",{className:"reservation-modal-body",children:[e.jsxs("div",{className:"device-id-badge",children:[e.jsx("span",{className:"label",children:"Device:"}),e.jsx("span",{className:"value",children:n.udid})]}),e.jsxs("p",{children:["Reserve ",e.jsx("strong",{children:n.name||n.udid})," for exclusive use. This will prevent CI sessions from using this device."]}),e.jsxs("div",{className:"reservation-form-group",children:[e.jsxs("label",{children:[e.jsx(wt,{size:14,style:{marginRight:6,verticalAlign:"middle",color:"var(--color-primary)"}}),"Reserved By"]}),e.jsx("input",{type:"text",className:"reservation-input",placeholder:"Enter your name or ID",value:u,onChange:w=>p(w.target.value),disabled:h})]}),e.jsxs("div",{className:"reservation-form-group",children:[e.jsxs("label",{children:[e.jsx(gs,{size:14,style:{marginRight:6,verticalAlign:"middle",color:"var(--color-primary)"}}),"Duration"]}),e.jsx("div",{className:"duration-selector",children:$t.map(w=>e.jsx("div",{className:`duration-option ${t===w.value?"active":""}`,onClick:()=>T(w.value),children:w.label},w.value))})]}),e.jsxs("div",{className:"reservation-form-group",children:[e.jsxs("label",{children:[e.jsx(at,{size:14,style:{marginRight:6,verticalAlign:"middle",color:"var(--color-primary)"}}),"Reason (Optional)"]}),e.jsx("input",{type:"text",className:"reservation-input",placeholder:"e.g., Debugging flaky login test",value:v,onChange:w=>x(w.target.value),disabled:h})]}),A&&e.jsxs("div",{className:"error-message",children:[e.jsx(Ss,{size:14,style:{marginRight:6,verticalAlign:"middle"}}),A]})]}),e.jsxs("div",{className:"reservation-actions",children:[e.jsx("button",{className:"btn-cancel",onClick:s,disabled:h,children:"Cancel"}),e.jsx("button",{className:"btn-reserve",onClick:U,disabled:h||!u.trim(),children:h?"Reserving...":"Confirm Reservation"})]})]})}),document.body)},At=({device:n,onClose:s,onUpdated:l})=>{const{toast:u}=us(),[p,t]=r.useState(n.tags||[]),[T,v]=r.useState(""),[x,h]=r.useState(!1),m=r.useRef(null);r.useEffect(()=>{m.current&&m.current.focus()},[]);const A=()=>{const j=T.trim();j&&!p.includes(j)&&(t([...p,j]),v(""))},S=j=>{t(p.filter(E=>E!==j))},U=j=>{j.key==="Enter"?A():j.key==="Escape"&&s()},w=async()=>{h(!0);try{await D.updateDeviceTags(n.udid,n.host,p),l(),s()}catch(j){console.error("Failed to update tags",j),u("Error saving tags. Please try again.","error")}finally{h(!1)}};return e.jsx("div",{className:"tag-modal-overlay",onClick:s,children:e.jsxs("div",{className:"tag-modal-container",onClick:j=>j.stopPropagation(),children:[e.jsx("div",{className:"scanline",style:{position:"absolute",inset:0,pointerEvents:"none",opacity:.05,zIndex:1001}}),e.jsxs("div",{className:"tag-modal-header",children:[e.jsxs("div",{className:"tag-modal-title",children:[e.jsx(xt,{size:18,className:"title-icon"}),"Manage Device Tags"]}),e.jsx("button",{className:"close-btn",onClick:s,children:e.jsx(Ke,{size:20})})]}),e.jsxs("div",{className:"tag-modal-body",children:[e.jsxs("div",{className:"device-id-badge",children:[e.jsx("span",{className:"label",children:"Device:"}),e.jsx("span",{className:"value",children:n.udid})]}),e.jsxs("div",{className:"tag-input-section",children:[e.jsx("label",{htmlFor:"tag-input",children:"Add New Tag"}),e.jsxs("div",{className:"input-with-button",children:[e.jsx("input",{ref:m,id:"tag-input",type:"text",placeholder:"e.g. stable, team-a, ios-17",value:T,onChange:j=>v(j.target.value),onKeyDown:U}),e.jsx("button",{className:"add-inline-btn",onClick:A,disabled:!T.trim(),children:e.jsx(fs,{size:16})})]}),e.jsx("p",{className:"input-hint",children:"Press Enter to add multiple tags"})]}),e.jsxs("div",{className:"tags-display-section",children:[e.jsx("label",{children:"Current Tags"}),e.jsx("div",{className:"tags-list",children:p.length>0?p.map(j=>e.jsxs("div",{className:"tag-pill-editable",children:[j,e.jsx("button",{className:"remove-tag",onClick:()=>S(j),children:e.jsx(Ke,{size:12})})]},j)):e.jsx("div",{className:"empty-tags",children:"No tags assigned to this device."})})]})]}),e.jsxs("div",{className:"tag-modal-footer",children:[e.jsx("button",{className:"btn-cancel",onClick:s,children:"Cancel"}),e.jsx("button",{className:"btn-save",onClick:w,disabled:x,children:x?"Saving...":"Apply Changes"})]})]})})};class Lt extends Fe.Component{constructor(s){super(s),this.state={showReservation:!1,showTagManager:!1,showControl:!1}}getStatusClassName(){return this.props.device.offline?"disabled":this.props.device.busy?"busy":this.isReserved()?"reserved":""}getDeviceState(){return this.props.device.offline?"offline":this.props.device.userBlocked?"maintenance":this.props.device.busy?"busy":this.isReserved()?"reserved":"ready"}isReserved(){const{reservedUntil:s}=this.props.device;return s?Date.now()<s:!1}getRemainingReservationTime(){const{reservedUntil:s}=this.props.device;if(!s)return"";const l=s-Date.now();return l<=0?"":ts(l,{compact:!0})}async releaseReservation(s,l){await D.releaseReservation(s,l),this.props.reloadDevices()}async blockDevice(s,l){await D.blockDevice(s,l),this.props.reloadDevices()}async unblockDevice(s,l){await D.unblockDevice(s,l),this.props.reloadDevices()}async manageTags(){this.setState({showTagManager:!0})}render(){var H;const{name:s,sdk:l,deviceType:u,platform:p,udid:t,dashboard_link:T,total_session_count:v,host:x,totalUtilizationTimeMilliSec:h,userBlocked:m,busy:A,session_id:S,reservedBy:U,reservedUntil:w,reservationReason:j,batteryLevel:E,thermalStatus:O,storageFree:b,tags:k,sessionProgress:f,totalHealedCount:R}=this.props.device,M=this.getDeviceState();let _="";try{_=new URL(x).hostname}catch{_=x.split(":")[1].replace("//","")}const X=()=>A?null:this.isReserved()?e.jsx("button",{className:"tactical-btn reserved",onClick:()=>this.releaseReservation(t,x),title:`Reserved by ${U}${j?`: ${j}`:""}. Expires: ${w?new Date(w).toLocaleString():"Never"}`,children:e.jsx(Ns,{size:14,color:"#38bdf8"})}):m?e.jsx("button",{className:"tactical-btn exit-maintenance",onClick:()=>this.unblockDevice(t,x),title:"Exit Maintenance",children:e.jsx(Ze,{size:14})}):e.jsxs(e.Fragment,{children:[e.jsx("button",{className:"tactical-btn reserve",onClick:()=>this.setState({showReservation:!0}),title:"Reserve Device",children:e.jsx(bs,{size:14,color:"#38bdf8"})}),e.jsx("button",{className:"tactical-btn maintenance",onClick:()=>this.blockDevice(t,x),title:"Enter Maintenance",children:e.jsx(St,{size:14,color:"#fbbf24"})})]});return e.jsxs("div",{className:`device-info-card-container ${this.getStatusClassName()} group`,children:[e.jsx("div",{className:"scanline",style:{position:"absolute",inset:0,pointerEvents:"none",opacity:.1,zIndex:0}}),e.jsxs("div",{className:"card-header relative z-10",children:[e.jsxs("div",{className:"header-left",children:[e.jsx("div",{className:`platform-icon-wrapper ${p}`,children:["ios","tvos"].includes(p)?e.jsx(ys,{size:14}):e.jsx(Je,{size:14})}),e.jsx("div",{className:"device-id-mono",title:t,children:t})]}),e.jsx("div",{className:`device-status-badge ${M} ${M==="busy"&&f&&f!=="Session Active"?"pulse":""}`,children:M==="busy"&&f&&f!=="Session Active"?f:M})]}),e.jsxs("div",{className:"device-info-main relative z-10",children:[e.jsx("h3",{className:"device-name",title:s,children:s}),e.jsxs("p",{className:"device-subtext",children:[u.toUpperCase()," • ",l]}),this.props.device.tags&&this.props.device.tags.length>0&&e.jsxs("div",{className:"device-tags-inline",children:[this.props.device.tags.slice(0,3).map(se=>e.jsx("span",{className:"inline-tag",title:se,children:se},se)),this.props.device.tags.length>3&&e.jsxs("span",{className:"inline-tag-overflow",children:["+",this.props.device.tags.length-3]})]})]}),e.jsxs("div",{className:"metrics-grid relative z-10",children:[e.jsxs("div",{className:"metric-item",title:`Location: ${_}`,children:[e.jsx(ns,{size:10,className:"text-dim"}),e.jsx("span",{className:"truncate",children:_})]}),this.props.device.ip&&e.jsxs("div",{className:"metric-item",title:`IP: ${this.props.device.ip}`,children:[e.jsx(ws,{size:10,className:"text-dim"}),e.jsx("span",{className:"truncate",children:this.props.device.ip})]}),e.jsxs("div",{className:`metric-item health ${((H=this.props.device.healthStatus)==null?void 0:H.toLowerCase())||"healthy"}`,title:this.props.device.healthCheckError||"Device is healthy",children:[e.jsx("div",{className:"health-dot"}),e.jsx("span",{children:this.props.device.healthStatus||"Healthy"}),R&&R>0&&e.jsxs("span",{className:"heal-badge",children:[e.jsx(Ze,{size:8})," ",R]})]}),O&&O!=="Unknown"&&e.jsxs("div",{className:"metric-item thermal",title:`Thermal: ${O}`,children:[e.jsx(yt,{size:10,style:{color:O==="Nominal"?"var(--color-primary)":"var(--color-amber)"}}),e.jsx("span",{children:O})]}),E!==void 0&&e.jsxs("div",{className:"metric-item battery",title:`Battery: ${E}%`,children:[e.jsx("div",{className:`mini-battery ${E<20?"low":""}`,children:e.jsx("div",{className:"battery-fill",style:{width:`${E}%`}})}),e.jsxs("span",{children:[E,"%"]})]}),b&&b!=="Unknown"&&e.jsxs("div",{className:"metric-item storage",title:`Free Space: ${b}`,children:[e.jsx(Ds,{size:10,style:{color:"var(--color-sky)"}}),e.jsx("span",{children:b})]})]}),e.jsx("div",{className:"dynamic-data-layer relative z-10",children:this.isReserved()?e.jsxs("div",{className:"reservation-micro-banner",children:[e.jsx(gs,{size:10}),e.jsxs("span",{children:["RES: ",U||"Anon"," (",this.getRemainingReservationTime(),")"]})]}):S?e.jsxs("div",{className:"session-micro-banner",children:[e.jsx(js,{size:10}),e.jsxs("span",{children:["SID: ",S]})]}):e.jsx("div",{className:"utilization-micro-info",children:e.jsxs("span",{children:["UTIL: ",ts(h||0,{compact:!0})]})})}),e.jsxs("div",{className:"action-row relative z-10",children:[e.jsx("button",{className:"tactical-btn add-tag",onClick:()=>this.manageTags(),title:"Manage Tags",children:e.jsx(fs,{size:14})}),X(),e.jsxs("button",{className:`tactical-btn control-btn ${A&&S&&!S.toString().startsWith("manual_")?"disabled":""}`,onClick:()=>!(A&&S&&!S.toString().startsWith("manual_"))&&this.props.navigate(`/devices/${t}/control`),disabled:A&&!!S&&!S.toString().startsWith("manual_"),title:A&&S&&!S.toString().startsWith("manual_")?"Locked: Appium Session":"Take Control",children:[e.jsx(ns,{size:14}),e.jsx("span",{style:{fontSize:"10px",fontWeight:800,letterSpacing:"0.05em",fontFamily:"Outfit, sans-serif"},children:"CTRL"})]})]}),this.state.showReservation&&e.jsx(Dt,{device:this.props.device,onClose:()=>this.setState({showReservation:!1}),onReserved:()=>this.props.reloadDevices()}),this.state.showTagManager&&e.jsx(At,{device:this.props.device,onClose:()=>this.setState({showTagManager:!1}),onUpdated:()=>this.props.reloadDevices()})]})}}function Tt(n){const s=Qe();return e.jsx(Lt,{...n,navigate:s})}class Et extends Fe.Component{render(){return e.jsx("div",{className:"device-explorer-card-container",children:Fe.Children.toArray(this.props.devices.map(s=>e.jsx(Tt,{device:s,reloadDevices:this.props.reloadDevices})))})}}var Ue,zt=new Uint8Array(16);function It(){if(!Ue&&(Ue=typeof crypto<"u"&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||typeof msCrypto<"u"&&typeof msCrypto.getRandomValues=="function"&&msCrypto.getRandomValues.bind(msCrypto),!Ue))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return Ue(zt)}const Rt=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;function Mt(n){return typeof n=="string"&&Rt.test(n)}var Y=[];for(var Ye=0;Ye<256;++Ye)Y.push((Ye+256).toString(16).substr(1));function _t(n){var s=arguments.length>1&&arguments[1]!==void 0?arguments[1]:0,l=(Y[n[s+0]]+Y[n[s+1]]+Y[n[s+2]]+Y[n[s+3]]+"-"+Y[n[s+4]]+Y[n[s+5]]+"-"+Y[n[s+6]]+Y[n[s+7]]+"-"+Y[n[s+8]]+Y[n[s+9]]+"-"+Y[n[s+10]]+Y[n[s+11]]+Y[n[s+12]]+Y[n[s+13]]+Y[n[s+14]]+Y[n[s+15]]).toLowerCase();if(!Mt(l))throw TypeError("Stringified UUID is invalid");return l}function Ut(n,s,l){n=n||{};var u=n.random||(n.rng||It)();return u[6]=u[6]&15|64,u[8]=u[8]&63|128,_t(u)}const Ot=({onCommand:n,prompt:s="$",welcomeMessage:l="Interactive Shell (Restricted Mode)",platform:u})=>{const[p,t]=r.useState([{type:"system",content:l,timestamp:Date.now()},{type:"system",content:'Type "help" for allowed commands.',timestamp:Date.now()}]),[T,v]=r.useState(""),[x,h]=r.useState([]),[m,A]=r.useState(-1),[S,U]=r.useState(!1),w=r.useRef(null),j=r.useRef(null);r.useEffect(()=>{w.current&&(w.current.scrollTop=w.current.scrollHeight)},[p]);const E=b=>{const k=b.trim();if((k.startsWith("{")||k.startsWith("["))&&(k.endsWith("}")||k.endsWith("]")))try{const f=JSON.parse(k);return JSON.stringify(f,null,2)}catch{}return b},O=async b=>{if(b.key==="Enter"&&!S){const k=T.trim();if(!k)return;if(v(""),t(f=>[...f,{type:"command",content:`${s} ${k}`,timestamp:Date.now()}]),h(f=>[...f,k]),A(-1),U(!0),k==="clear"){t([]),U(!1);return}if(k==="help"){let f="";u==="android"?f=`
|
|
142
|
+
Android Allowed Commands:
|
|
143
|
+
• System Info: getprop, ip addr, date, uptime, cat /proc/meminfo, cat /proc/cpuinfo
|
|
144
|
+
• Process Mgmt: ps, top
|
|
145
|
+
• File System: ls
|
|
146
|
+
• Diagnostics: dumpsys [battery|wifi|power]
|
|
147
|
+
• Packages: pm list packages
|
|
148
|
+
`:(u==="ios"||u==="tvos")&&(f=`
|
|
149
|
+
iOS Allowed Commands:
|
|
150
|
+
• Simulator (xcrun simctl):
|
|
151
|
+
listapps, get_app_container, list, getenv
|
|
152
|
+
• Real Device (go-ios):
|
|
153
|
+
apps, info, syslog, list
|
|
154
|
+
`),t(R=>[...R,{type:"output",content:f.trim(),timestamp:Date.now()}]),U(!1);return}try{const f=await n(k),R=E(f||"(No output)");t(M=>[...M,{type:"output",content:R,timestamp:Date.now()}])}catch(f){t(R=>[...R,{type:"error",content:f.message||"Unknown error",timestamp:Date.now()}])}finally{U(!1),setTimeout(()=>{var f;return(f=j.current)==null?void 0:f.focus()},10)}}else if(b.key==="ArrowUp"){if(b.preventDefault(),x.length>0){const k=m===-1?x.length-1:Math.max(0,m-1);A(k),v(x[k])}}else if(b.key==="ArrowDown"&&(b.preventDefault(),m!==-1)){const k=m+1;k>=x.length?(A(-1),v("")):(A(k),v(x[k]))}};return e.jsxs("div",{className:"terminal-container",children:[e.jsx("div",{className:"scanline",style:{position:"absolute",inset:0,pointerEvents:"none",opacity:.05,zIndex:1001}}),e.jsxs("header",{className:"terminal-header",children:[e.jsxs("div",{className:"terminal-controls",children:[e.jsx("div",{className:"dot red"}),e.jsx("div",{className:"dot yellow"}),e.jsx("div",{className:"dot green"})]}),e.jsxs("div",{className:"terminal-title",children:[u.toUpperCase()," INTERNAL SHELL"]}),e.jsx("div",{className:"terminal-actions",children:e.jsx("button",{className:"terminal-action-btn",onClick:()=>t([]),title:"Clear Terminal",children:"CLEAR"})})]}),e.jsxs("div",{className:"terminal-history",ref:w,onClick:()=>{var b;return(b=j.current)==null?void 0:b.focus()},children:[p.map((b,k)=>e.jsx("div",{className:`terminal-line ${b.type}`,children:b.content},k)),S&&e.jsx("div",{className:"terminal-line system animate-pulse",children:"Executing command..."})]}),e.jsxs("div",{className:"terminal-input-area",children:[e.jsx("span",{className:"terminal-prompt",children:s}),e.jsx("input",{ref:j,className:"terminal-input",value:T,onChange:b=>v(b.target.value),onKeyDown:O,disabled:S,autoFocus:!0,spellCheck:!1,autoComplete:"off",placeholder:"Type a command..."})]})]})};function os(n,s){const l=n.toLowerCase();if(l==="accessibility id")return/[0-9a-f]{8}-[0-9a-f]{4}/i.test(s)?{level:"fragile",reason:"UUID in accessibility ID — dynamically generated, unreliable"}:{level:"stable",reason:"#1 recommended by Appium — portable across Android & iOS"};if(l==="id")return/[0-9a-f]{8}-[0-9a-f]{4}/i.test(s)?{level:"fragile",reason:"UUID in resource ID — dynamically generated"}:/\d{6,}/.test(s)&&!s.includes(":id/")?{level:"moderate",reason:"Long numeric ID without package prefix — may not be unique"}:/^[a-z][a-z0-9.]+:id\//.test(s)?{level:"stable",reason:"Android resource-id with package prefix — #2 by Appium priority"}:{level:"stable",reason:"Element ID — #2 by Appium 2.x recommended priority"};if(l==="xpath"){if(s.startsWith("/hierarchy")||s.startsWith("/")&&!s.startsWith("//"))return{level:"very-fragile",reason:"ABSOLUTE XPath — breaks on any layout change. Avoid entirely"};if(/\[\d+\]/.test(s))return{level:"very-fragile",reason:"Index-based XPath [n] — breaks when element order changes"};const u=(s.match(/\//g)||[]).length;return u>7?{level:"fragile",reason:`${u}-level deep XPath — brittle to layout changes, 10x slower on iOS`}:s.includes("@content-desc")||s.includes("@resource-id")||s.includes("@text")?{level:"moderate",reason:"XPath with semantic attribute — more stable, but still prefer ID/accessibility id"}:{level:"fragile",reason:"XPath is a LAST RESORT per Appium docs — 10x slower on iOS, breaks on UI changes"}}return l==="-ios predicate string"?{level:"stable",reason:"iOS NSPredicate — native engine, excellent performance on iOS"}:l==="-ios class chain"?{level:"stable",reason:"iOS Class Chain — native iOS, faster than XPath"}:l==="-android uiautomator"?s.includes("resourceId")||s.includes("description")?{level:"stable",reason:"UIAutomator2 with resourceId/description — Android native, very reliable"}:s.includes("textContains")||s.includes("text(")?{level:"moderate",reason:"UIAutomator2 with text matching — breaks if copy changes"}:{level:"stable",reason:"UIAutomator2 — Android native engine, preferred over XPath on Android"}:l==="class name"?{level:"fragile",reason:"Class name alone is almost never unique — use with explicit index or prefer accessibility id"}:l==="name"?{level:"fragile",reason:"⚠️ Deprecated in Appium 2.x — replace with accessibility id or id"}:l==="link text"?{level:"moderate",reason:"Text-based locator — breaks if copy/label changes"}:{level:"moderate",reason:"Verify reliability for your target platform"}}function ds(n,s,l,u){var b,k,f,R,M,_,X;const{strategy:p,value:t}=u,T=(n.text||n.name||((b=n.type)==null?void 0:b.split(".").pop())||"element").replace(/[^a-zA-Z0-9]/g,"_").replace(/^_+/,"").slice(0,24)||"element",v=T.charAt(0).toLowerCase()+T.slice(1),x=((k=n.type)==null?void 0:k.toLowerCase().includes("edit"))||((f=n.type)==null?void 0:f.toLowerCase().includes("input"))||((R=n.type)==null?void 0:R.toLowerCase().includes("field"))||((M=n.type)==null?void 0:M.toLowerCase().includes("textfield")),h=((_=n.attributes)==null?void 0:_.scrollable)==="true"||((X=n.attributes)==null?void 0:X.scrollable)===!0,m=p.toLowerCase().startsWith("-ios")&&s!=="ios"?`// ⚠️ -ios predicate/class chain ONLY work with XCUITest (iOS)
|
|
155
|
+
`:p.toLowerCase().startsWith("-android")&&s!=="android"?`// ⚠️ -android uiautomator ONLY works with UIAutomator2 (Android)
|
|
156
|
+
`:"",A={"accessibility id":`~${t}`,id:s==="ios"?`-ios predicate string:label == "${t}"`:`android=new UiSelector().resourceId("${t}")`,xpath:`${t}`,"-ios predicate string":`-ios predicate string:${t}`,"-ios class chain":`-ios class chain:${t}`,"-android uiautomator":`android=${t}`},S={"accessibility id":`AppiumBy.accessibilityId("${t}")`,id:`AppiumBy.id("${t}")`,xpath:`AppiumBy.xpath("${t}")`,"-ios predicate string":`AppiumBy.iOSNsPredicateString("${t}")`,"-ios class chain":`AppiumBy.iOSClassChain("${t}")`,"-android uiautomator":`AppiumBy.androidUIAutomator("${t}")`,"class name":`AppiumBy.className("${t}")`},U={"accessibility id":`AppiumBy.ACCESSIBILITY_ID, "${t}"`,id:`AppiumBy.ID, "${t}"`,xpath:`AppiumBy.XPATH, "${t}"`,"-ios predicate string":`AppiumBy.IOS_PREDICATE, "${t}"`,"-ios class chain":`AppiumBy.IOS_CLASS_CHAIN, "${t}"`,"-android uiautomator":`AppiumBy.ANDROID_UIAUTOMATOR, '${t}'`,"class name":`AppiumBy.CLASS_NAME, "${t}"`},w=S[p.toLowerCase()],j=U[p.toLowerCase()],E=A[p.toLowerCase()];return l==="java"?w?`${m}// Appium Java Client 9.x + Selenium 4 + TestNG
|
|
157
|
+
import io.appium.java_client.AppiumBy;
|
|
158
|
+
import io.appium.java_client.${s==="android"?"AndroidDriver":s==="ios"?"IOSDriver":"AppiumDriver"};
|
|
159
|
+
import org.openqa.selenium.WebElement;
|
|
160
|
+
import org.testng.annotations.Test;
|
|
161
|
+
|
|
162
|
+
@Test
|
|
163
|
+
public void test_${v}() {
|
|
164
|
+
WebElement element = driver.findElement(${w});
|
|
165
|
+
${h?'((Scrollable) element).scrollTo("target text");':x?`element.clear();
|
|
166
|
+
element.sendKeys("your text here");`:"element.click();"}
|
|
167
|
+
// Add assertions here via TestNG Assert or Hamcrest
|
|
168
|
+
}`:`// Strategy "${p}" not supported in Appium Java Client`:l==="python"?j?`${m}# Appium Python Client 4.x + pytest
|
|
169
|
+
from appium.webdriver.common.appiumby import AppiumBy
|
|
170
|
+
import pytest
|
|
171
|
+
|
|
172
|
+
def test_${v}(self):
|
|
173
|
+
element = self.driver.find_element(${j})
|
|
174
|
+
${x?`element.clear()
|
|
175
|
+
element.send_keys("your text here")`:"element.click()"}
|
|
176
|
+
# Add assertions here via assert or pytest.assert`:`# Strategy "${p}" not supported in Appium Python Client`:l==="javascript"?E?`${m}// WebdriverIO 9.x + @wdio/appium-service
|
|
177
|
+
describe('${v} test', () => {
|
|
178
|
+
it('should interact with ${v}', async () => {
|
|
179
|
+
const element = await $('${E}');
|
|
180
|
+
await element.waitForDisplayed({ timeout: 5000 });
|
|
181
|
+
${x?`await element.clearValue();
|
|
182
|
+
await element.addValue("your text here");`:"await element.click();"}
|
|
183
|
+
// Add assertions here via expect(element)
|
|
184
|
+
});
|
|
185
|
+
});`:`// Strategy "${p}" not supported in WebdriverIO mobile`:E?`${m}// WebdriverIO 9.x standalone
|
|
186
|
+
const element = await driver.$('${E}');
|
|
187
|
+
await element.waitForExist({ timeout: 5000 });
|
|
188
|
+
${x?`await driver.$('target').clearValue();
|
|
189
|
+
await element.addValue("your text here");`:"await element.click();"}
|
|
190
|
+
// Assert with expect(element).toBeDisplayed()`:`// Strategy "${p}" not supported in WebdriverIO mobile`}function Ft(n){var U,w,j,E,O,b,k,f,R,M,_;const s=(n.type||"").toLowerCase(),l=((U=n.attributes)==null?void 0:U.clickable)==="true"||((w=n.attributes)==null?void 0:w.clickable)===!0,u=((j=n.attributes)==null?void 0:j.enabled)!=="false"&&((E=n.attributes)==null?void 0:E.enabled)!==!1,p=((O=n.attributes)==null?void 0:O.scrollable)==="true"||((b=n.attributes)==null?void 0:b.scrollable)===!0,t=n.text||n.label||n.value||"",T=((k=n.children)==null?void 0:k.length)||0;let v="Element",x="📦";s.includes("button")||s.includes("btn")||l&&T===0?(v="Button",x="🔘"):s.includes("edit")||s.includes("input")||s.includes("field")?(v="Text Input",x="✏️"):s.includes("image")||s.includes("img")||s.includes("imageview")?(v="Image",x="🖼️"):s.includes("scroll")||s.includes("recyclerview")||s.includes("listview")||p?(v="Scrollable List",x="📜"):s.includes("text")||s.includes("label")?(v="Text Label",x="📝"):s.includes("switch")||s.includes("toggle")||s.includes("checkbox")?(v="Toggle / Checkbox",x="☑️"):s.includes("nav")||s.includes("toolbar")||s.includes("tabbar")?(v="Navigation Bar",x="🧭"):T>0&&(v=`Container (${T} children)`,x="🗂️");const h=((f=n.suggestedLocators)==null?void 0:f.find(X=>X.strategy==="accessibility id"||X.strategy==="id"))||((R=n.suggestedLocators)==null?void 0:R[0]),m=u?((M=n.rect)==null?void 0:M.width)===0||((_=n.rect)==null?void 0:_.height)===0?"⚠️ Zero-size element — may not be interactable":void 0:"⚠️ Element is disabled",A=t?` with text "${t.slice(0,30)}"`:"",S=`This is a ${v.toLowerCase()}${A}. ${l?"It can be tapped/clicked.":p?"It supports scrolling.":"It is a visual container."}${T>0?` Contains ${T} child element${T>1?"s":""}.`:""}`;return{role:v,description:S,interactable:l||u,bestLocator:h,warning:m,emoji:x}}function hs(n,s){if(!s)return!0;const l=s.toLowerCase().trim(),u={button:["button","btn","clickable","tapable"],input:["edittext","input","field","textfield","textinput","edit"],image:["image","imageview","img","picture","photo","icon"],text:["textview","label","text","statictext"],list:["listview","recyclerview","scrollview","tableview","collectionview","scroll"],toggle:["switch","checkbox","toggle","radiobutton"],nav:["toolbar","navigationbar","tabbar","actionbar","navbar"]},p=(n.type||"").toLowerCase(),t=(n.text||n.label||n.value||"").toLowerCase(),T=(n.name||"").toLowerCase(),v=Object.values(n.attributes||{}).join(" ").toLowerCase();for(const[x,h]of Object.entries(u))if(l.includes(x)&&h.some(m=>p.includes(m)))return!0;return p.includes(l)||t.includes(l)||T.includes(l)||v.includes(l)}const Ht=({sessionId:n,udid:s,streamUrl:l})=>{var pe,Se,ze,$e,ve,De,Ie;const[u,p]=r.useState(!0),[t,T]=r.useState(null),[v,x]=r.useState(null),[h,m]=r.useState(null),[A,S]=r.useState(null),[U,w]=r.useState(new Set(["/"])),[j,E]=r.useState(""),[O,b]=r.useState(null),[k,f]=r.useState("info"),[R,M]=r.useState("java"),[_,X]=r.useState(null),[H,se]=r.useState({width:0,height:0}),[be,xe]=r.useState({width:0,height:0}),[He,d]=r.useState(!1),[J,Ae]=r.useState("inspect"),Ne=r.useRef(null),ge=r.useRef(null),fe=r.useRef(null),oe=r.useRef(null),de=r.useCallback(()=>{var z,G,Q;if(!Ne.current)return;const i=Ne.current.getBoundingClientRect(),o=i.width,y=i.height,C=(z=t==null?void 0:t.hierarchy)==null?void 0:z.rect;let F=((G=t==null?void 0:t.metadata)==null?void 0:G.screenWidth)||H.width||1,W=((Q=t==null?void 0:t.metadata)==null?void 0:Q.screenHeight)||H.height||1;C&&C.width>0&&C.height>0&&(F=C.width,W=C.height);const V=F/W;let P,q;o/y>V?(q=y,P=q*V):(P=o,q=P/V),xe({width:P,height:q})},[t,H]);r.useEffect(()=>(de(),window.addEventListener("resize",de),()=>window.removeEventListener("resize",de)),[de]),r.useEffect(()=>{s&&re()},[s]),r.useEffect(()=>{var i;if((i=h==null?void 0:h.suggestedLocators)!=null&&i.length){const o=h.suggestedLocators.find(y=>y.strategy==="accessibility id"||y.strategy==="id")||h.suggestedLocators[0];X(o)}else X(null)},[h]);const re=async()=>{if(s){p(!0),x(null);try{const i=await D.getInspectorSnapshot(s);T(i);const o=new Set(["/"]),y=(C,F)=>{var W;F<2&&(o.add(C.xpath),(W=C.children)==null||W.forEach(V=>y(V,F+1)))};i.hierarchy&&y(i.hierarchy,0),w(o)}catch(i){x(i.message||"Failed to capture snapshot")}finally{p(!1)}}},Le=i=>{const{naturalWidth:o,naturalHeight:y}=i.currentTarget;se({width:o,height:y})},ce=()=>d(!0),Te=i=>{d(!1);const{naturalWidth:o,naturalHeight:y}=i.currentTarget;o>0&&y>0&&se({width:o,height:y})},Z=l&&!He,Ee=i=>{if(J!=="interact"||!s)return;const o=i.currentTarget.getBoundingClientRect();oe.current={x:i.clientX-o.left,y:i.clientY-o.top,time:Date.now()}},ye=async i=>{var c,g,$;if(J!=="interact"||!s||!oe.current)return;const o=oe.current,y=i.currentTarget.getBoundingClientRect(),C=i.clientX-y.left,F=i.clientY-y.top,W=Date.now()-o.time,V=be.width,P=be.height,q=(c=t==null?void 0:t.hierarchy)==null?void 0:c.rect;let z=((g=t==null?void 0:t.metadata)==null?void 0:g.screenWidth)||H.width,G=(($=t==null?void 0:t.metadata)==null?void 0:$.screenHeight)||H.height;if(q&&q.width>0&&q.height>0&&(z=q.width,G=q.height),!z||!G||V===0||P===0)return;const Q=(N,L)=>({x:Math.round(N/V*z),y:Math.round(L/P*G),px:N/V,py:L/P}),K=Q(o.x,o.y),le=Q(C,F),a=Math.sqrt(Math.pow(C-o.x,2)+Math.pow(F-o.y,2));if(!(K.px<0||K.px>1||K.py<0||K.py>1)){try{W<500&&a<10?await D.tap(s,K.x,K.y):W>=500&&a<10?await D.touchAndHold(s,K.x,K.y,W):a>=10&&await D.swipe(s,K.x,K.y,le.x,le.y)}catch(N){console.error("Interaction failed:",N)}oe.current=null}},Pe=i=>{const o=new Set(U);o.has(i)?o.delete(i):o.add(i),w(o)},je=()=>{const i=new Set,o=y=>{var C;i.add(y.xpath),(C=y.children)==null||C.forEach(o)};t!=null&&t.hierarchy&&o(t.hierarchy),w(i)},te=()=>w(new Set(["/"])),he=(i,o)=>{navigator.clipboard.writeText(i),b(o),setTimeout(()=>b(null),2e3)},we=i=>{var y;let o=1;return(y=i.children)==null||y.forEach(C=>o+=we(C)),o},Be=i=>i.xpath.split("/").filter(Boolean).slice(-3),me=(i,o=0)=>{var q;if(!i)return null;const y=U.has(i.xpath),C=((q=i.children)==null?void 0:q.length)>0,F=(h==null?void 0:h.xpath)===i.xpath,W=(A==null?void 0:A.xpath)===i.xpath,V=i.name||i.type.split(".").pop()||"Element",P=!j||hs(i,j);if(!P&&!C)return null;if(j&&!P){const z=G=>{var Q;return hs(G,j)?!0:((Q=G.children)==null?void 0:Q.some(z))||!1};if(!z(i))return null}return e.jsxs("div",{className:"tree-node",children:[e.jsxs("div",{className:`tree-item ${F?"selected":""} ${W&&!F?"hovered":""}`,onClick:()=>{m(i),f("info")},onMouseEnter:()=>S(i),onMouseLeave:()=>S(null),children:[e.jsx("div",{className:"tree-item-indent",style:{width:`${o*14}px`}}),C?e.jsx("button",{onClick:z=>{z.stopPropagation(),Pe(i.xpath)},className:"tree-toggle",children:y?e.jsx(ps,{size:11}):e.jsx(xs,{size:11})}):e.jsx("span",{className:"tree-toggle-spacer"}),e.jsx(Ms,{size:11,className:"tree-icon"}),e.jsx("span",{className:"tree-label",children:V}),i.text&&e.jsxs("span",{className:"tree-text-preview",children:['"',i.text.slice(0,20),'"']}),C&&e.jsx("span",{className:"tree-badge",children:i.children.length})]}),y&&C&&e.jsx("div",{className:"tree-children",children:i.children.map(z=>me(z,o+1))})]},i.xpath)},ke=i=>{var V,P,q;if(!H.width)return[];const o=[],y=(V=t==null?void 0:t.hierarchy)==null?void 0:V.rect;let C=((P=t==null?void 0:t.metadata)==null?void 0:P.screenWidth)||H.width,F=((q=t==null?void 0:t.metadata)==null?void 0:q.screenHeight)||H.height;y&&y.width>0&&y.height>0&&(C=y.width,F=y.height);const W=(z,G)=>{var K,le,a;const Q=!z.children||z.children.length===0;((K=z.rect)==null?void 0:K.width)>0&&((le=z.rect)==null?void 0:le.height)>0&&Q&&o.push(e.jsx("div",{className:"omni-hit-area",style:{left:`${z.rect.x/C*100}%`,top:`${z.rect.y/F*100}%`,width:`${z.rect.width/C*100}%`,height:`${z.rect.height/F*100}%`,zIndex:G},onClick:c=>{c.stopPropagation(),m(z),f("info")},onMouseEnter:()=>S(z),onMouseLeave:()=>S(null)},z.xpath)),(a=z.children)==null||a.forEach(c=>W(c,G+1))};return t!=null&&t.hierarchy&&W(t.hierarchy,1),o},ue=(i,o)=>{var W,V,P;if(!(i!=null&&i.rect)||!H.width)return null;const y=(W=t==null?void 0:t.hierarchy)==null?void 0:W.rect;let C=((V=t==null?void 0:t.metadata)==null?void 0:V.screenWidth)||H.width,F=((P=t==null?void 0:t.metadata)==null?void 0:P.screenHeight)||H.height;return y&&y.width>0&&y.height>0&&(C=y.width,F=y.height),e.jsx("div",{className:`omni-frame-${o}`,style:{left:`${i.rect.x/C*100}%`,top:`${i.rect.y/F*100}%`,width:`${i.rect.width/C*100}%`,height:`${i.rect.height/F*100}%`}})},ae=t!=null&&t.hierarchy?we(t.hierarchy):0,B=h?Ft(h):null,Ce={stable:{icon:e.jsx(Ze,{size:10}),cls:"stable"},moderate:{icon:e.jsx($s,{size:10}),cls:"moderate"},fragile:{icon:e.jsx(rs,{size:10}),cls:"fragile"},"very-fragile":{icon:e.jsx(rs,{size:10}),cls:"very-fragile"}};return e.jsx("div",{className:"omni-inspector-container",children:e.jsxs("div",{className:"omni-main-content",children:[e.jsxs("div",{className:"omni-screenshot-panel",children:[e.jsxs("div",{className:"omni-screenshot-header",children:[e.jsxs("div",{className:"omni-header-left",children:[e.jsx("span",{className:"omni-screenshot-title",children:"Device Preview"}),e.jsxs("div",{className:"omni-mode-toggle",children:[e.jsxs("button",{className:`omni-mode-btn ${J==="inspect"?"active":""}`,onClick:()=>Ae("inspect"),title:"Inspection Mode (Highlight Elements)",children:[e.jsx(Ts,{size:12}),e.jsx("span",{children:"Inspect"})]}),e.jsxs("button",{className:`omni-mode-btn ${J==="interact"?"active":""}`,onClick:()=>Ae("interact"),title:"Interaction Mode (Direct Control)",children:[e.jsx(bt,{size:12}),e.jsx("span",{children:"Interact"})]})]})]}),e.jsxs("button",{className:"omni-refresh-btn",onClick:re,disabled:u,children:[e.jsx(Oe,{size:12,className:u?"animate-spin":""}),u?"Capturing...":"Refresh"]})]}),e.jsxs("div",{className:"omni-screenshot-container",ref:Ne,children:[u&&!Z&&e.jsxs("div",{className:"omni-loading-overlay",children:[e.jsx("div",{className:"omni-spinner"}),e.jsx("span",{children:"Capturing screen..."})]}),!t&&!u&&!Z&&e.jsxs("div",{className:"omni-empty-state",children:[e.jsx(ls,{size:40}),e.jsx("span",{children:"Click Refresh to capture"})]}),Z&&e.jsxs("div",{className:`omni-screenshot-wrapper ${J==="interact"?"interactable":""}`,onMouseDown:Ee,onMouseUp:ye,children:[e.jsx("img",{ref:fe,src:l,onLoad:Te,onError:ce,className:"omni-screenshot-img",style:J==="interact"?{pointerEvents:"none"}:{},draggable:!1,alt:"Live Device Stream"}),(t==null?void 0:t.hierarchy)&&J==="inspect"&&e.jsxs("div",{className:"omni-overlay",children:[ke(t.hierarchy),ue(A,"hover"),ue(h,"select")]})]}),!Z&&(t==null?void 0:t.screenshot)&&e.jsxs("div",{className:`omni-screenshot-wrapper ${J==="interact"?"interactable":""}`,onMouseDown:Ee,onMouseUp:ye,children:[e.jsx("img",{ref:ge,src:`data:image/png;base64,${t.screenshot}`,onLoad:Le,className:"omni-screenshot-img",style:J==="interact"?{pointerEvents:"none"}:{},draggable:!1}),J==="inspect"&&e.jsxs("div",{className:"omni-overlay",children:[ke(t.hierarchy),ue(A,"hover"),ue(h,"select")]})]})]})]}),e.jsxs("div",{className:"omni-tree-panel",children:[e.jsxs("div",{className:"omni-tree-header",children:[e.jsxs("div",{className:"omni-tree-title",children:[e.jsx(Js,{size:14}),e.jsx("span",{children:"Source"}),ae>0&&e.jsxs("span",{className:"omni-count-badge",children:[ae," elements"]})]}),e.jsxs("div",{className:"omni-tree-actions",children:[e.jsx("button",{onClick:je,className:"omni-action-btn",title:"Expand All",children:e.jsx(Xs,{size:12})}),e.jsx("button",{onClick:te,className:"omni-action-btn",title:"Collapse All",children:e.jsx(ht,{size:12})})]})]}),e.jsxs("div",{className:"omni-tree-search",children:[e.jsx(es,{size:14}),e.jsx("input",{type:"text",placeholder:"Search elements... (try 'login button' or 'text field')",value:j,onChange:i=>E(i.target.value)}),j&&e.jsx("button",{onClick:()=>E(""),className:"omni-clear-btn",children:"×"})]}),j&&e.jsxs("div",{className:"omni-search-hint",children:[e.jsx(cs,{size:10}),' Smart search active — try "button", "input", "image"']}),e.jsx("div",{className:"omni-tree-content",children:t!=null&&t.hierarchy?me(t.hierarchy):e.jsx("div",{className:"omni-empty-state small",children:e.jsx("span",{children:"No hierarchy loaded"})})})]}),e.jsxs("div",{className:"omni-details-panel",children:[e.jsxs("div",{className:"omni-details-tabs",children:[e.jsxs("button",{className:`omni-details-tab ${k==="info"?"active":""}`,onClick:()=>f("info"),children:[e.jsx(tt,{size:12})," Info"]}),e.jsxs("button",{className:`omni-details-tab ${k==="insight"?"active":""}`,onClick:()=>f("insight"),disabled:!h,title:"AI Element Analysis",children:[e.jsx(Qs,{size:12})," AI Insight"]}),e.jsxs("button",{className:`omni-details-tab ${k==="code"?"active":""}`,onClick:()=>f("code"),disabled:!h,title:"Generate Test Code",children:[e.jsx(as,{size:12})," Code Gen"]})]}),e.jsx("div",{className:"omni-details-content",children:h?e.jsxs(e.Fragment,{children:[k==="info"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"omni-section",children:[e.jsx("div",{className:"omni-section-header",children:"Element Info"}),e.jsxs("div",{className:"omni-info-table",children:[e.jsxs("div",{className:"omni-info-row",children:[e.jsx("span",{className:"omni-info-key",children:"Type"}),e.jsx("span",{className:"omni-info-value mono",children:h.type})]}),h.text&&e.jsxs("div",{className:"omni-info-row",children:[e.jsx("span",{className:"omni-info-key",children:"Text"}),e.jsx("span",{className:"omni-info-value",children:h.text})]}),e.jsxs("div",{className:"omni-info-row",children:[e.jsx("span",{className:"omni-info-key",children:"Path"}),e.jsx("span",{className:"omni-info-value mono small",children:Be(h).join(" › ")})]})]})]}),e.jsxs("div",{className:"omni-section",children:[e.jsx("div",{className:"omni-section-header",children:"Layout"}),e.jsx("div",{className:"omni-layout-grid",children:["x","y","width","height"].map(i=>e.jsxs("div",{className:"omni-layout-item",children:[e.jsx("span",{className:"omni-layout-label",children:i.toUpperCase()}),e.jsx("span",{className:"omni-layout-value",children:h.rect[i]})]},i))})]}),e.jsxs("div",{className:"omni-section",children:[e.jsxs("div",{className:"omni-section-header",children:["Locators",e.jsx("span",{className:"omni-section-badge",children:"Stability Scored"})]}),e.jsx("div",{className:"omni-locators-list",children:(pe=h.suggestedLocators)==null?void 0:pe.map(i=>{const o=os(i.strategy,i.value),y=Ce[o.level];return e.jsxs("div",{className:`omni-locator-row ${(_==null?void 0:_.strategy)===i.strategy?"selected-for-code":""}`,onClick:()=>X(i),title:"Click to use in Code Generator",children:[e.jsxs("div",{className:"omni-locator-left",children:[e.jsxs("div",{className:"omni-locator-top",children:[e.jsx("span",{className:"omni-locator-strategy",children:i.strategy}),e.jsxs("span",{className:`omni-stability-badge ${y.cls}`,title:o.reason,children:[y.icon,o.level]})]}),e.jsx("code",{className:"omni-locator-value",children:i.value}),e.jsx("span",{className:"omni-stability-reason",children:o.reason})]}),e.jsx("button",{onClick:C=>{C.stopPropagation(),he(i.value,i.strategy)},className:`omni-copy-btn ${O===i.strategy?"copied":""}`,children:O===i.strategy?e.jsx(qe,{size:12}):e.jsx(Xe,{size:12})})]},i.strategy)})})]}),e.jsxs("div",{className:"omni-section",children:[e.jsx("div",{className:"omni-section-header",children:"Attributes"}),e.jsx("div",{className:"omni-attributes-table",children:Object.entries(h.attributes||{}).filter(([i,o])=>o!=null&&o!=="").map(([i,o])=>e.jsxs("div",{className:"omni-attr-row",children:[e.jsx("span",{className:"omni-attr-key",children:i}),e.jsx("span",{className:"omni-attr-value",children:String(o)})]},i))})]})]}),k==="insight"&&B&&e.jsxs("div",{className:"omni-insight-panel",children:[e.jsxs("div",{className:"omni-insight-role",children:[e.jsx("span",{className:"omni-insight-emoji",children:B.emoji}),e.jsxs("div",{children:[e.jsx("div",{className:"omni-insight-role-name",children:B.role}),e.jsx("div",{className:"omni-insight-interactable",children:B.interactable?e.jsxs("span",{className:"omni-badge-green",children:[e.jsx(zs,{size:10})," Interactable"]}):e.jsx("span",{className:"omni-badge-gray",children:"Visual Only"})})]})]}),B.warning&&e.jsx("div",{className:"omni-insight-warning",children:B.warning}),e.jsxs("div",{className:"omni-insight-description",children:[e.jsx(cs,{size:12,className:"omni-insight-icon"}),e.jsx("p",{children:B.description})]}),B.bestLocator&&e.jsxs("div",{className:"omni-insight-best-locator",children:[e.jsx("div",{className:"omni-section-header",children:"Recommended Locator"}),e.jsxs("div",{className:"omni-locator-row",children:[e.jsxs("div",{className:"omni-locator-left",children:[e.jsx("span",{className:"omni-locator-strategy",children:B.bestLocator.strategy}),e.jsx("code",{className:"omni-locator-value",children:B.bestLocator.value})]}),e.jsx("button",{onClick:()=>he(B.bestLocator.value,"best"),className:`omni-copy-btn ${O==="best"?"copied":""}`,children:O==="best"?e.jsx(qe,{size:12}):e.jsx(Xe,{size:12})})]})]}),e.jsxs("div",{className:"omni-insight-attributes",children:[e.jsx("div",{className:"omni-section-header",children:"Quick Facts"}),e.jsx("div",{className:"omni-quick-facts",children:[{label:"Clickable",value:(Se=h.attributes)==null?void 0:Se.clickable},{label:"Enabled",value:(ze=h.attributes)==null?void 0:ze.enabled},{label:"Scrollable",value:($e=h.attributes)==null?void 0:$e.scrollable},{label:"Focusable",value:(ve=h.attributes)==null?void 0:ve.focusable},{label:"Children",value:((De=h.children)==null?void 0:De.length)||0}].map(({label:i,value:o})=>e.jsxs("div",{className:"omni-quick-fact-row",children:[e.jsx("span",{className:"omni-quick-fact-label",children:i}),e.jsx("span",{className:`omni-quick-fact-value ${o==="true"||o===!0?"true":""}`,children:String(o??"—")})]},i))})]})]}),k==="code"&&e.jsxs("div",{className:"omni-codegen-panel",children:[e.jsx("div",{className:"omni-codegen-frameworks",children:["java","python","javascript","wdio"].map(i=>e.jsx("button",{className:`omni-fw-btn ${R===i?"active":""}`,onClick:()=>M(i),children:i==="java"?"☕ Java":i==="python"?"🐍 Python":i==="javascript"?"🟨 JS":"🔷 WD.io"},i))}),_?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"omni-codegen-locator-selector",children:[e.jsx("span",{className:"omni-codegen-label",children:"Locator:"}),e.jsx("select",{value:_.strategy,onChange:i=>{var y;const o=(y=h.suggestedLocators)==null?void 0:y.find(C=>C.strategy===i.target.value);o&&X(o)},className:"omni-fw-select",children:(Ie=h.suggestedLocators)==null?void 0:Ie.map(i=>e.jsxs("option",{value:i.strategy,children:[i.strategy," — ",os(i.strategy,i.value).level]},i.strategy))})]}),e.jsxs("div",{className:"omni-codegen-output",children:[e.jsxs("div",{className:"omni-codegen-header",children:[e.jsx("span",{className:"omni-codegen-lang",children:R==="java"?"Java / TestNG":R==="python"?"Python / unittest":R==="javascript"?"JavaScript / Mocha":"WebdriverIO"}),e.jsx("button",{className:"omni-copy-btn",onClick:()=>he(ds(h,(t==null?void 0:t.platform)==="android"?"android":(t==null?void 0:t.platform)==="ios"?"ios":"unknown",R,_),"code"),children:O==="code"?e.jsx(qe,{size:12}):e.jsx(Xe,{size:12})})]}),e.jsx("pre",{className:"omni-codegen-pre",children:e.jsx("code",{children:ds(h,(t==null?void 0:t.platform)==="android"?"android":(t==null?void 0:t.platform)==="ios"?"ios":"unknown",R,_)})})]})]}):e.jsxs("div",{className:"omni-empty-state small",children:[e.jsx(as,{size:24}),e.jsx("span",{children:"No locators available for this element"})]})]})]}):e.jsxs("div",{className:"omni-empty-state",children:[e.jsx(ls,{size:32}),e.jsx("span",{children:"Select an element from the tree or screenshot"})]})})]})]})})};function Pt({device:n,onClose:s}){var le;const{toast:l,removeToast:u}=us(),p=Qe(),{tab:t}=vs(),T=r.useRef(null),v=r.useRef(null),[x,h]=r.useState({width:0,height:0}),[m,A]=r.useState(t||"actions"),[S,U]=r.useState(""),[w,j]=r.useState(""),[E,O]=r.useState(""),[b,k]=r.useState(!0),[f,R]=r.useState([]),[M,_]=r.useState(null),[X,H]=r.useState(!1),[se,be]=r.useState(!1),[xe,He]=r.useState(0),[d,J]=r.useState(n),[Ae,Ne]=r.useState([]),[ge,fe]=r.useState(!1),[oe,de]=r.useState(!1),[re,Le]=r.useState(null),[ce,Te]=r.useState([]),[Z,Ee]=r.useState(!0),[ye,Pe]=r.useState(""),je=r.useRef(""),te=r.useRef(null),[he,we]=r.useState(!1);r.useEffect(()=>{m&&(!t||t!==m)&&p(`/devices/${n.udid}/control/${m}`,{replace:!0})},[m,t,n.udid,p]),r.useEffect(()=>{let a;if(m==="logs"){const c=async()=>{try{const g=await D.getLogs(d.udid);if(g&&g.logs){const $=g.logs.replace(/\\u[0-9a-fA-F]{4}/g,N=>JSON.parse(`"${N}"`)).replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,"").split(`
|
|
191
|
+
`).filter(N=>N.trim().length>0);Te(N=>{const L=N.slice(-20),ee=$.filter(ne=>!L.includes(ne));return[...N,...ee].slice(-1e3)})}}catch(g){console.error("Failed to fetch logs:",g)}};c(),a=setInterval(c,2e3)}return()=>clearInterval(a)},[m,d.udid]);const Be=()=>ce.length===0?e.jsx("div",{className:"log-line log-debug",children:e.jsx("span",{className:"log-content",children:"Establishing technical link... Waiting for heartbeat."})}):ce.filter(c=>!ye||c.toLowerCase().includes(ye.toLowerCase())).map((c,g)=>{let $="log-debug";const N=c.toLowerCase();return N.includes("error")||N.includes("fail")?$="log-error":N.includes("warning")||N.includes("warn")?$="log-warn":(N.includes("notice")||N.includes("info"))&&($="log-notice"),e.jsxs("div",{className:`log-line ${$}`,children:[e.jsx("span",{className:"log-index",children:g+1}),e.jsx("span",{className:"log-content",children:c})]},`${g}-${c.substring(0,10)}`)});r.useEffect(()=>{m==="logs"&&Z&&v.current&&(v.current.scrollTop=v.current.scrollHeight)},[ce,m,Z]),r.useEffect(()=>((async()=>{try{be(!0),await D.startStream(d.udid);const g=(await D.getDevices()).find($=>$.udid===d.udid);g&&J(g)}catch(c){console.error("Auto-start stream failed:",c)}finally{be(!1)}})(),()=>{D.stopStream(d.udid).catch(()=>{})}),[n.udid]);const me=r.useCallback(async()=>{try{fe(!0);const a=await D.listApps(d.udid);Array.isArray(a)&&Ne(a)}catch(a){console.error("Failed to load apps:",a)}finally{fe(!1)}},[d.udid]);r.useEffect(()=>{m==="actions"&&me()},[m,me]);const ke=parseInt(d.screenWidth||"1080",10),ue=parseInt(d.screenHeight||"1920",10),ae=Math.min(ke,ue),B=Math.max(ke,ue),Ce=ae/B,pe=r.useCallback(()=>{const a=!b,c=a?window.innerHeight*.55:window.innerHeight*.7,g=a?window.innerWidth*.8:window.innerWidth*.45,$=b?Ce:1/Ce;let N,L;b?(N=c,L=N*$,L>g&&(L=g,N=L/$)):(L=g,N=L/$,N>c&&(N=c,L=N*$)),h({width:L,height:N})},[Ce,b]);r.useEffect(()=>(pe(),window.addEventListener("resize",pe),()=>window.removeEventListener("resize",pe)),[pe]),r.useEffect(()=>{const a=async()=>{if(je.current.length>0){const g=je.current;je.current="";try{await D.typeText(d.udid,g)}catch($){console.error("Keyboard buffering flush failed:",$)}}},c=g=>{const $=document.activeElement;if($&&($.tagName==="INPUT"||$.tagName==="TEXTAREA"||$.isContentEditable)||!he&&m!=="terminal")return;const L=g.key;L==="Enter"?(te.current&&clearTimeout(te.current),a(),D.pressKey(d.udid,d.platform==="android"?66:"enter")):L==="Backspace"?(te.current&&clearTimeout(te.current),a(),D.pressKey(d.udid,d.platform==="android"?67:"backspace")):L.length===1&&(je.current+=L,te.current&&clearTimeout(te.current),te.current=setTimeout(()=>{a()},50))};return window.addEventListener("keydown",c),()=>{window.removeEventListener("keydown",c),te.current&&clearTimeout(te.current)}},[d.udid,d.platform,he,m]);const[Se,ze]=r.useState(Date.now()),$e=()=>{const a=xe>0?`r=${xe}&`:"";return d.session_id&&!String(d.session_id).startsWith("manual_")?`/xenon/api/session/${d.session_id}/live_video?${a}t=${Se}`:`/xenon/api/control/${d.udid}/stream?${a}t=${Se}`};r.useEffect(()=>{xe>0&&ze(Date.now())},[xe]);const ve=r.useRef(null),De=a=>{const c=a.currentTarget.getBoundingClientRect();return{x:a.clientX-c.left,y:a.clientY-c.top}},Ie=a=>{const c=De(a);ve.current={x:c.x,y:c.y,time:Date.now()}},i=async a=>{if(!ve.current)return;const c=ve.current,g=De(a),$=Date.now()-c.time;let N,L,ee,ie;b?(N=c.x/x.width*ae,L=c.y/x.height*B,ee=g.x/x.width*ae,ie=g.y/x.height*B):(N=c.x/x.width*B,L=c.y/x.height*ae,ee=g.x/x.width*B,ie=g.y/x.height*ae);const ne=Math.abs(ee-N),Re=Math.abs(ie-L);try{$<500&&ne<10&&Re<10?await D.tap(d.udid,Math.round(N),Math.round(L)):$>=500&&ne<10&&Re<10?await D.touchAndHold(d.udid,Math.round(N),Math.round(L),$):await D.swipe(d.udid,Math.round(N),Math.round(L),Math.round(ee),Math.round(ie))}catch(ks){console.error("Action failed:",ks)}ve.current=null},o=()=>D.pressKey(d.udid,d.platform==="android"?3:"home"),y=()=>D.lock(d.udid),C=()=>D.unlock(d.udid),F=async()=>{S.trim()&&(await D.typeText(d.udid,S),U(""))},W=async()=>{try{j("Fetching...");const a=await D.getClipboard(d.udid);a&&a.content!==void 0?j(a.content||"(Clipboard is empty)"):j("No content received")}catch{j("Error: Check Appium Settings app")}},V=async()=>{H(!0);try{const a=await D.getScreenshot(d.udid);if(a!=null&&a.screenshot){const c={id:Ut(),base64:a.screenshot,timestamp:Date.now()};R(g=>[c,...g]),_(0)}}catch(a){console.error("Failed to take screenshot:",a)}finally{H(!1)}},P=a=>{R(c=>{const g=c.filter($=>$.id!==a);return g.length===0?_(null):M!==null&&M>=g.length&&_(0),g})},q=()=>{R([]),_(null),l("Cleared all captured evidence.","success")},z=a=>{const c=document.createElement("a");c.href=`data:image/png;base64,${a}`,c.download=`screenshot-${d.udid}-${Date.now()}.png`,c.click()},G=async a=>{const c=ae/2,g=B/2,$=ae*.4,N=B*.4;let L,ee,ie,ne;switch(a){case"left":L=c+$,ee=g,ie=c-$,ne=g;break;case"right":L=c-$,ee=g,ie=c+$,ne=g;break;case"up":L=c,ee=g+N,ie=c,ne=g-N;break;case"down":L=c,ee=g-N,ie=c,ne=g+N;break}try{await D.swipe(d.udid,Math.round(L),Math.round(ee),Math.round(ie),Math.round(ne))}catch(Re){console.error(`Quick swipe ${a} failed:`,Re)}},Q=async()=>{if(E.trim()){const a=l(`Uninstalling ${E}...`,"loading",0);try{fe(!0),await D.uninstallApp(d.udid,E),O(""),l(`Request sent for ${E}`,"success"),setTimeout(me,3e3)}catch{l("Uninstall failed. Check logs.","error")}finally{fe(!1),u(a)}}},K=async()=>{if(!re)return;let a;try{de(!0),a=l(`Installing app to ${d.udid}...`,"loading",0);const c=await D.uploadAndInstallApp(d.udid,re);c.success?(l(c.message||"App installed successfully","success"),Le(null),setTimeout(me,5e3)):l("Installation failed: "+(c.error||"Unknown error"),"error")}catch(c){l("Installation failed: "+c.message,"error")}finally{a&&u(a),de(!1)}};return e.jsxs("div",{className:"device-control-view",children:[e.jsx("div",{className:"scanline",style:{position:"absolute",inset:0,pointerEvents:"none",opacity:.05,zIndex:1001}}),e.jsxs("header",{className:"control-view-top-bar",children:[e.jsxs("button",{className:"back-to-devices-btn",onClick:s,children:[e.jsx(is,{size:18})," DEVICES"]}),e.jsxs("div",{className:"device-info-mini",children:[e.jsx("span",{className:`device-pill platform-pill ${d.platform}`,children:d.platform==="ios"?"Apple":"Android"}),e.jsxs("span",{className:"device-pill version-pill",children:["v",d.sdk]}),d.reservedUntil&&Date.now()<d.reservedUntil&&e.jsxs("span",{className:"device-pill reserved-pill",title:`Reserved by ${d.reservedBy}${d.reservationReason?`: ${d.reservationReason}`:""}`,children:["RESERVED BY ",((le=d.reservedBy)==null?void 0:le.toUpperCase())||"ANONYMOUS"]}),e.jsx("h2",{className:"device-name-text",children:d.name}),e.jsx("span",{className:"code-font",style:{opacity:.5},children:d.udid})]})]}),e.jsxs("div",{className:`control-view-main ${b?"":"is-landscape"} ${m==="omni"?"omni-mode":""}`,children:[e.jsxs("div",{className:"device-preview-column",children:[e.jsx("div",{className:"device-screen-wrapper",children:e.jsxs("div",{ref:T,className:`device-stream-canvas ${b?"":"landscape"} ${he?"focused":""}`,style:{width:x.width,height:x.height,background:"#000"},tabIndex:0,onFocus:()=>we(!0),onBlur:()=>we(!1),onMouseDown:Ie,onMouseUp:i,children:[se&&e.jsxs("div",{className:"device-stream-placeholder",style:{position:"absolute",zIndex:10},children:[e.jsx(Oe,{size:40,className:"animate-spin",color:"var(--primary)"}),e.jsx("p",{style:{marginTop:16},children:"ESTABLISHING TRACE..."})]}),e.jsx("img",{src:$e(),alt:"Device Stream",className:"device-stream-image",style:{width:"100%",height:"100%",objectFit:"contain"},onError:()=>{console.warn("Stream failed to load, retrying..."),setTimeout(()=>He(a=>a+1),2e3)}})]})}),e.jsxs("aside",{className:"device-footer-actions",children:[e.jsxs("button",{className:`footer-action-btn ${b?"active":""}`,onClick:()=>k(!0),children:[e.jsx(Oe,{size:14,style:{transform:b?"none":"rotate(-90deg)"}})," ","PORTRAIT"]}),e.jsxs("button",{className:`footer-action-btn ${b?"":"active"}`,onClick:()=>k(!1),children:[e.jsx(Oe,{size:14,style:{transform:"rotate(90deg)"}})," LANDSCAPE"]}),e.jsx("div",{className:"footer-divider"}),e.jsxs("button",{className:"footer-action-btn",onClick:o,children:[e.jsx(Ys,{size:20})," HOME"]}),e.jsx("button",{className:"footer-action-btn",onClick:y,title:"Lock Device",children:e.jsx(Is,{size:20})}),e.jsx("button",{className:"footer-action-btn",onClick:C,title:"Unlock Device",children:e.jsx(Ns,{size:20})})]})]}),e.jsxs("div",{className:"device-interactions-column",children:[e.jsxs("div",{className:"interaction-tabs",children:[e.jsx("button",{className:`tab-btn ${m==="actions"?"active":""}`,onClick:()=>A("actions"),children:"ACTIONS"}),e.jsx("button",{className:`tab-btn ${m==="screenshot"?"active":""}`,onClick:()=>A("screenshot"),children:"SCREENSHOT"}),e.jsx("button",{className:`tab-btn ${m==="logs"?"active":""}`,onClick:()=>A("logs"),children:"DEBUG LOGS"}),e.jsxs("button",{className:`tab-btn ${m==="terminal"?"active":""}`,onClick:()=>A("terminal"),children:[e.jsx(js,{size:14,style:{marginRight:6}})," SHELL"]}),e.jsx("button",{className:`tab-btn ${m==="omni"?"active":""}`,onClick:()=>A("omni"),children:"OMNI-VISION"})]}),e.jsx("div",{className:`interactions-scroll-area ${m==="terminal"?"terminal-mode":""} ${m==="screenshot"||m==="logs"?"screenshot-mode":""}`,children:e.jsxs("div",{className:"tab-content",children:[m==="omni"&&e.jsx("div",{className:"omni-inspector-tab-wrapper animate-fade-in",style:{height:"calc(100vh - 266px)"},children:e.jsx(Ht,{sessionId:d.session_id?String(d.session_id):null,udid:d.udid,streamUrl:$e()})}),m==="actions"&&e.jsxs("div",{className:"actions-grid",children:[e.jsxs("div",{className:"action-card",children:[e.jsxs("h4",{className:"action-card-title",children:[e.jsx(ct,{size:18,color:"var(--primary)"})," Directional Gestures"]}),e.jsxs("div",{className:"gestures-grid-container",children:[e.jsxs("div",{className:"gestures-dpad",children:[e.jsx("div",{}),e.jsx("button",{className:"dpad-btn",onClick:()=>G("up"),children:e.jsx(Fs,{size:24})}),e.jsx("div",{}),e.jsx("button",{className:"dpad-btn",onClick:()=>G("left"),children:e.jsx(is,{size:24})}),e.jsx("div",{className:"dpad-center"}),e.jsx("button",{className:"dpad-btn",onClick:()=>G("right"),children:e.jsx(xs,{size:24})}),e.jsx("div",{}),e.jsx("button",{className:"dpad-btn",onClick:()=>G("down"),children:e.jsx(ps,{size:24})}),e.jsx("div",{})]}),e.jsx("p",{className:"compact-label",style:{opacity:.5},children:"Directional Glide"})]})]}),e.jsxs("div",{className:"action-card",children:[e.jsxs("h4",{className:"action-card-title",children:[e.jsx(Vs,{size:18,color:"var(--primary)"})," Smart Input"]}),e.jsx("input",{type:"text",className:"type-input-field compact",placeholder:"Relay keystrokes...",value:S,onChange:a=>U(a.target.value),onKeyDown:a=>a.key==="Enter"&&F()})]}),e.jsxs("div",{className:"action-card full-width",children:[e.jsxs("h4",{className:"action-card-title",children:[e.jsx(ot,{size:18,color:"var(--primary)"})," App Management"]}),e.jsxs("div",{className:"app-mgmt-content",children:[e.jsxs("div",{className:"install-section",children:[e.jsx("p",{className:"compact-label",children:"Install Package (.apk, .ipa, .app)"}),e.jsxs("div",{className:"upload-box-row",children:[e.jsxs("label",{className:"file-upload-launcher",children:[e.jsx(Ls,{size:14}),e.jsx("span",{children:re?re.name:"Select File"}),e.jsx("input",{type:"file",accept:".apk,.ipa,.app",onChange:a=>{var c;return Le(((c=a.target.files)==null?void 0:c[0])||null)},hidden:!0})]}),e.jsx("button",{className:"btn-premium btn-sm",disabled:!re||oe,onClick:K,children:oe?e.jsx(We,{className:"animate-spin",size:14}):"INSTALL"})]})]}),e.jsx("div",{className:"divider-v"}),e.jsxs("div",{className:"uninstall-section",children:[e.jsx("p",{className:"compact-label",children:"Quick Uninstall"}),e.jsxs("div",{className:"uninstall-controls-row",children:[e.jsxs("div",{className:"select-wrapper",children:[e.jsxs("select",{className:"app-select-dropdown compact",value:E,onChange:a=>O(a.target.value),disabled:ge,children:[e.jsx("option",{value:"",children:ge?"Loading apps...":"-- Select App to Remove --"}),Ae.map(a=>e.jsx("option",{value:a,children:a},a))]}),ge&&e.jsx(We,{className:"animate-spin select-loader",size:12})]}),e.jsxs("button",{className:"btn-destructive btn-sm",onClick:Q,disabled:!E||ge,children:[e.jsx(_e,{size:14})," UNINSTALL"]})]}),e.jsxs("div",{className:"manual-input-box",children:[e.jsx("p",{className:"hint-text",children:"Or enter manually:"}),e.jsx("input",{type:"text",className:"type-input-field tiny",placeholder:"com.example.app",value:E,onChange:a=>O(a.target.value)})]})]})]})]}),e.jsxs("div",{className:"action-card full-width",children:[e.jsxs("h4",{className:"action-card-title",children:[e.jsx(Ps,{size:18,color:"var(--primary)"})," Clipboard"]}),e.jsxs("div",{style:{display:"flex",gap:"12px",alignItems:"flex-start"},children:[e.jsx("button",{className:"btn-premium btn-sm",style:{width:"140px",flexShrink:0},onClick:W,children:"FETCH VALUE"}),e.jsx("div",{className:"clipboard-display compact",style:{marginTop:0,flex:1},children:w})]})]})]}),m==="screenshot"&&e.jsxs("div",{className:"action-card screenshot-card",children:[e.jsxs("header",{className:"action-card-header",children:[e.jsxs("div",{className:"title-group",children:[e.jsxs("h4",{className:"action-card-title",children:[e.jsx(Ve,{size:20,color:"var(--primary)"})," Captured Evidence"]}),e.jsx("p",{className:"hint-text",children:"Relay screenshots from device to host."})]}),f.length>0&&e.jsx("button",{className:"btn-text-only",onClick:q,children:"CLEAR ALL"})]}),e.jsxs("div",{className:"screenshot-workspace",children:[e.jsxs("div",{className:"screenshot-gallery-sidebar",children:[e.jsxs("button",{className:"btn-premium take-screenshot-btn",onClick:V,disabled:X,children:[X?e.jsx(We,{className:"animate-spin",size:16}):e.jsx(Ve,{size:16}),e.jsx("span",{children:X?"CAPTURING...":"NEW CAPTURE"})]}),e.jsxs("div",{className:"screenshot-thumbnails-list",children:[f.length===0&&!X&&e.jsx("div",{className:"empty-gallery-state",children:e.jsx("p",{children:"No captures yet"})}),f.map((a,c)=>e.jsxs("div",{className:`screenshot-thumb-item ${M===c?"active":""}`,onClick:()=>_(c),children:[e.jsx("img",{src:`data:image/png;base64,${a.base64}`,alt:"Thumb"}),e.jsx("span",{className:"thumb-time",children:new Date(a.timestamp).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}),e.jsx("button",{className:"thumb-delete-btn",onClick:g=>{g.stopPropagation(),P(a.id)},children:e.jsx(_e,{size:12})})]},a.id))]})]}),e.jsx("div",{className:"screenshot-main-preview",children:M!==null&&f[M]?e.jsxs("div",{className:"preview-container",children:[e.jsx("div",{className:"preview-image-wrapper",children:e.jsx("img",{src:`data:image/png;base64,${f[M].base64}`,alt:"Selected Evidence"})}),e.jsxs("footer",{className:"preview-footer",children:[e.jsxs("div",{className:"preview-meta",children:[e.jsx("span",{className:"meta-label",children:"ID:"}),e.jsx("span",{className:"meta-value",children:f[M].id.substring(0,8)}),e.jsx("span",{className:"meta-divider",children:"|"}),e.jsx("span",{className:"meta-value",children:new Date(f[M].timestamp).toLocaleString()})]}),e.jsxs("div",{className:"preview-actions",children:[e.jsx("button",{className:"btn-premium btn-sm",onClick:()=>z(f[M].base64),children:"DOWNLOAD PNG"}),e.jsxs("button",{className:"btn-destructive btn-sm",onClick:()=>P(f[M].id),children:[e.jsx(_e,{size:14})," DELETE"]})]})]})]}):e.jsxs("div",{className:"preview-empty-placeholder",children:[e.jsx(Ve,{size:48,style:{opacity:.1,marginBottom:16}}),e.jsx("p",{children:"Capture a screenshot to begin analysis"})]})})]})]}),m==="logs"&&e.jsxs("div",{className:"action-card screenshot-card",style:{padding:0,gap:0},children:[e.jsxs("div",{className:"log-toolbar",children:[e.jsxs("div",{className:"log-filter-group",children:[e.jsx("div",{className:"log-stat-pill",children:"LIVE"}),e.jsxs("div",{className:"log-stat-pill",style:{opacity:.6},children:[ce.length," LINES"]}),e.jsxs("div",{className:"log-search-box",children:[e.jsx(es,{size:14,className:"search-icon-inline"}),e.jsx("input",{type:"text",className:"type-input-field tiny",placeholder:"Filter trace...",value:ye,onChange:a=>Pe(a.target.value)})]})]}),e.jsxs("div",{className:"log-actions-group",children:[e.jsxs("button",{className:`btn-secondary btn-sm ${Z?"active":""}`,onClick:()=>Ee(!Z),title:Z?"Freeze Logs":"Follow Logs",children:[e.jsx(ws,{size:14,className:Z?"animate-pulse":""}),Z?"FREEZE":"FOLLOW"]}),e.jsxs("button",{className:"btn-premium btn-sm",onClick:()=>{const a=new Blob([ce.join(`
|
|
192
|
+
`)],{type:"text/plain"}),c=URL.createObjectURL(a),g=document.createElement("a");g.href=c,g.download=`logs-${d.udid}-${Date.now()}.txt`,g.click(),URL.revokeObjectURL(c)},disabled:ce.length===0,children:[e.jsx(Es,{size:14}),"EXPORT"]}),e.jsxs("button",{className:"btn-secondary btn-sm",onClick:()=>Te([]),title:"Clear Logs",children:[e.jsx(_e,{size:14}),"CLEAR"]})]})]}),e.jsx("div",{className:"log-display-area",ref:v,style:{flex:1},children:Be()})]}),m==="terminal"&&e.jsx("div",{className:"action-card full-height",children:e.jsx(Ot,{platform:(d.platform||"").toLowerCase(),prompt:`${(d.platform||"").toLowerCase()==="ios"?"ios":"adb"} $`,welcomeMessage:`Connected to ${d.name} (${d.udid}).
|
|
193
|
+
Internal Shell Environment.`,onCommand:async a=>{const c=await D.executeShell(d.udid,a);if(c.error)throw new Error(c.error);return c.output}})})]})})]})]})]})}const ms={platform:{ios:!0,android:!0},state:{ready:!0,offline:!0,busy:!0},name:""};class Bt extends Fe.Component{constructor(s){super(s),this.socketCleanups=[],this.refreshTimeout=null,this.state={devices:[],activeSessionsCount:0,pendingSessionsCount:0,queueSummary:null,filter:ms}}componentDidMount(){this.fetchDevices(),this.devicePolling=setInterval(()=>{this.fetchDevices()},1e4);const s=this.props.onSocketEvent("device_unblocked",()=>{console.info("Real-time: Device unblocked, triggering debounced refresh"),this.fetchDevicesDebounced()}),l=this.props.onSocketEvent("device_blocked",()=>{console.info("Real-time: Device blocked, triggering debounced refresh"),this.fetchDevicesDebounced()});this.socketCleanups.push(s,l)}componentWillUnmount(){this.devicePolling&&(clearInterval(this.devicePolling),this.devicePolling=void 0),this.refreshTimeout&&(clearTimeout(this.refreshTimeout),this.refreshTimeout=null),this.socketCleanups.forEach(s=>s())}fetchDevicesDebounced(){this.refreshTimeout&&clearTimeout(this.refreshTimeout),this.refreshTimeout=setTimeout(()=>{this.refreshTimeout=null,this.fetchDevices()},500)}getBusyDevicesCount(s){return[u=>u.busy].reduce((u,p)=>u.filter(p),s).length}async fetchDevices(){try{const s=await D.getDevices(),l=this.getBusyDevicesCount(s),u=await D.getPendingSessionsCount(),p=await D.getQueueSummary();console.log(s),this.setState({devices:s,activeSessionsCount:l,pendingSessionsCount:u,queueSummary:p})}catch(s){console.log(s)}}getFilteredDevice(){const{ready:s,busy:l,offline:u}=this.state.filter.state,{ios:p,android:t}=this.state.filter.platform,T=[v=>p&&(v.platform=="ios"||v.platform=="tvos")||t&&v.platform=="android",v=>s&&!v.busy&&!v.offline||l&&v.busy||u&&v.offline];return this.state.filter.name!=""&&T.push(v=>v.name.toLowerCase().includes(this.state.filter.name.toLowerCase())||v.udid.toLowerCase().includes(this.state.filter.name.toLowerCase())),T.reduce((v,x)=>v.filter(x),this.state.devices)}setFilter(s){this.setState({filter:{...this.state.filter,...s}})}getPlatformFilterComponent(){const{ios:s,android:l}=this.state.filter.platform;return e.jsxs("div",{className:"device-explorer-header-value",children:[e.jsxs("button",{className:`device-explorer-header__platform-btn ${l&&"selected"}`,onClick:()=>this.setFilter({platform:{...this.state.filter.platform,android:!this.state.filter.platform.android}}),children:[e.jsx(Je,{size:20,color:"currentColor"}),"Android"]}),e.jsxs("button",{className:`device-explorer-header__platform-btn ${s&&"selected"}`,onClick:()=>this.setFilter({platform:{...this.state.filter.platform,ios:!this.state.filter.platform.ios}}),children:[e.jsx(ys,{size:20,color:"currentColor"}),"iOS"]})]})}getDeviceStateFilterComponent(){const{ready:s,busy:l,offline:u}=this.state.filter.state;return e.jsxs("div",{className:"device-explorer-header-value",children:[e.jsx("div",{className:`device-explorer-header__device-state ready ${s&&"selected"}`,onClick:()=>this.setFilter({state:{...this.state.filter.state,ready:!this.state.filter.state.ready}}),children:"Ready"}),e.jsx("div",{className:`device-explorer-header__device-state busy ${l&&"selected"}`,onClick:()=>this.setFilter({state:{...this.state.filter.state,busy:!this.state.filter.state.busy}}),children:"Busy"}),e.jsx("div",{className:`device-explorer-header__device-state offline ${u&&"selected"}`,onClick:()=>this.setFilter({state:{...this.state.filter.state,offline:!this.state.filter.state.offline}}),children:"Offline"})]})}render(){const s=this.getFilteredDevice(),{udid:l}=this.props.params,u=l?this.state.devices.find(p=>p.udid===l):null;return e.jsxs("div",{className:"device-explorer-container",children:[e.jsxs("div",{className:"device-explorer-header-container",children:[e.jsxs("div",{className:"device-explorer-header-left-container",children:[e.jsxs("div",{className:"device-explorer-header-entry",children:[e.jsx("div",{className:"device-explorer-header-entry-header",children:"Platform"}),this.getPlatformFilterComponent()]}),e.jsxs("div",{className:"device-explorer-header-entry",children:[e.jsx("div",{className:"device-explorer-header-entry-header",children:"Device state"}),this.getDeviceStateFilterComponent()]}),e.jsxs("div",{className:"device-explorer-header-entry search-entry",children:[e.jsx("div",{className:"device-explorer-header-entry-header",children:"Search by name or udid"}),e.jsx("div",{className:"device-explorer-header-value",children:e.jsxs("div",{className:"device-explorer-search-wrapper",children:[e.jsx(es,{size:16,color:"#94a3b8",className:"device-explorer-search-icon"}),e.jsx("input",{type:"text",className:"device-explorer-header-text-filter",placeholder:"Search devices...",onChange:p=>{this.setState({filter:{...this.state.filter,name:p.target.value}})}})]})})]})]}),e.jsx("div",{className:"device-explorer-header-filter-count",children:e.jsxs(Me,{variant:"secondary",children:[e.jsx("span",{className:"font-bold",children:s.length})," of"," ",e.jsx("span",{className:"font-bold",children:this.state.devices.length})," ",this.state.devices.length===1?"device":"devices"]})}),e.jsxs("div",{className:"device-explorer-header-right-container",children:[this.state.queueSummary&&this.state.pendingSessionsCount>0&&e.jsxs(Me,{variant:"secondary",className:"mr-2",children:[e.jsx("span",{className:"font-bold",children:"Queue Insights:"})," ",Object.entries(this.state.queueSummary.byPlatform).map(([p,t])=>e.jsxs("span",{className:"ml-1",children:[p==="any"?"Mixed":p.toUpperCase(),":"," ",Math.ceil(t.avgDurationMs/6e4),"m ETA"]},p))]}),e.jsxs(Me,{variant:"success",children:[e.jsx("span",{className:"font-bold",children:this.state.activeSessionsCount})," Active session",this.state.activeSessionsCount!==1?"s":""]}),e.jsxs(Me,{variant:"warning",children:[e.jsx("span",{className:"font-bold",children:this.state.pendingSessionsCount})," Pending session",this.state.pendingSessionsCount!==1?"s":""]}),e.jsxs(Ge,{size:"sm",variant:"default",onClick:()=>this.fetchDevices(),children:[e.jsx(ss,{size:14,color:"currentColor",className:"mr-1"}),"Refresh"]})]})]}),s.length>0?e.jsx(Et,{devices:s,reloadDevices:()=>this.fetchDevices()}):e.jsxs("div",{className:"device-explorer-empty stagger-1",children:[e.jsx("div",{className:"device-explorer-empty-icon",children:e.jsx(Je,{size:32})}),this.state.devices.length===0?e.jsxs(e.Fragment,{children:[e.jsx("h3",{className:"brand-font",children:"Global Device Registry Empty"}),e.jsx("p",{children:"Xenon hasn't detected any active device nodes in your infrastructure. Ensure your device farm is connected and heartbeat signals are active."}),e.jsxs(Ge,{variant:"default",onClick:()=>this.fetchDevices(),children:[e.jsx(ss,{size:14,className:"mr-2"}),"Manual Sync"]})]}):e.jsxs(e.Fragment,{children:[e.jsx("h3",{className:"brand-font",children:"No Devices Found"}),e.jsx("p",{children:"Deployment configuration mismatch. Adjust your platform or state filters to find the appropriate testing target."}),e.jsx(Ge,{variant:"outline",onClick:()=>this.setState({filter:ms}),children:"Reset All Filters"})]})]}),u&&e.jsx("div",{className:"device-control-modal-overlay",children:e.jsx("div",{className:"device-control-modal",children:e.jsx(Pt,{device:u,onClose:()=>this.props.navigate("/devices")})})})]})}}function si(){const n=vs(),s=Qe(),{on:l}=As();return e.jsx(Bt,{params:n,navigate:s,onSocketEvent:l})}export{Bt as DeviceExplorer,si as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import"https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap";.device-info-card-container{background:var(--bg-card);min-height:180px;width:100%;display:flex;flex-direction:column;padding:12px;border-radius:8px;position:relative;box-shadow:0 4px 20px #0006;border:1px solid var(--border-visible);transition:all .2s cubic-bezier(.4,0,.2,1);overflow:hidden;background-image:radial-gradient(circle at 50% 50%,rgba(255,255,255,.02) 0%,transparent 100%)}.device-info-card-container:hover{border-color:#0f86;box-shadow:0 0 25px #00ff8814;transform:translateY(-2px);background:var(--bg-card-hover)}.card-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.header-left{display:flex;align-items:center;gap:8px}.platform-icon-wrapper{padding:4px;border-radius:4px;background:#ffffff08;color:var(--text-dim);display:flex;align-items:center;justify-content:center}.platform-icon-wrapper.ios{color:#88a}.platform-icon-wrapper.android{color:#3ddc84}.device-id-mono{font-family:JetBrains Mono,monospace;font-size:10px;color:var(--text-muted);background:#0000004d;padding:2px 6px;border-radius:4px;border:1px solid var(--border-subtle);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.device-status-badge{font-family:JetBrains Mono,monospace;font-size:var(--fs-xs);font-weight:700;text-transform:uppercase;padding:2px 8px;border-radius:4px;border:1px solid transparent}.device-status-badge.ready{color:var(--color-primary);background:#00ff880d;border-color:#0f83}.device-status-badge.busy{color:var(--color-amber);background:#ffb8000d;border-color:#ffb80033}.device-status-badge.maintenance{color:#fb923c;background:#fb923c0d;border-color:#fb923c33}.device-status-badge.offline{color:var(--text-dim);background:#ffffff08;border-color:var(--border-visible)}.device-info-main{margin-bottom:12px}.device-name{font-family:Outfit,sans-serif;font-size:14px;font-weight:700;color:var(--text-bright);margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.device-subtext{font-size:10px;color:var(--text-dim);margin-top:2px;font-weight:500}.device-tags-inline{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px;min-height:16px}.inline-tag{background:#00ff880d;color:var(--color-primary);border:1px solid rgba(0,255,136,.2);padding:2px 6px;border-radius:4px;font-size:8px;font-weight:800;font-family:JetBrains Mono,monospace;text-transform:uppercase;letter-spacing:.05em;white-space:nowrap;max-width:80px;overflow:hidden;text-overflow:ellipsis}.inline-tag-overflow{background:#ffffff0d;color:var(--text-dim);border:1px dashed var(--border-visible);padding:2px 6px;border-radius:4px;font-size:8px;font-weight:800;font-family:JetBrains Mono,monospace;display:flex;align-items:center;justify-content:center}.metrics-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-bottom:12px}.metric-item{display:flex;align-items:center;gap:4px;font-size:9px;color:var(--text-muted);font-family:JetBrains Mono,monospace;background:#0003;padding:4px;border-radius:4px;white-space:nowrap;overflow:hidden}.metric-item span.truncate{overflow:hidden;text-overflow:ellipsis}.metric-item.health.healthy{color:var(--color-primary)}.metric-item.health.unhealthy{color:var(--color-red)}.health-dot{width:4px;height:4px;border-radius:50%;background:currentColor}.heal-badge{margin-left:auto;font-size:8px;background:#ffffff1a;padding:0 4px;border-radius:2px;display:flex;align-items:center;gap:2px}.mini-battery{width:14px;height:8px;border:1px solid rgba(255,255,255,.2);border-radius:1px;padding:1px;position:relative}.mini-battery:after{content:"";position:absolute;right:-2px;top:2px;width:1.5px;height:2px;background:#fff3}.battery-fill{height:100%;background:var(--color-primary);border-radius:.5px}.mini-battery.low .battery-fill{background:var(--color-red)}.dynamic-data-layer{margin-top:auto;margin-bottom:10px;height:18px}.reservation-micro-banner,.session-micro-banner,.utilization-micro-info{font-size:9px;font-weight:700;display:flex;align-items:center;gap:6px;padding:2px 8px;border-radius:4px}.reservation-micro-banner{color:var(--color-sky);background:#38bdf81a;border-left:2px solid var(--color-sky)}.session-micro-banner{color:var(--color-amber);background:#ffb8001a;border-left:2px solid var(--color-amber)}.utilization-micro-info{color:var(--text-muted)}.action-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(0,1fr));grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);gap:6px;border-top:1px solid var(--border-subtle);padding-top:10px;width:100%}.tactical-btn{flex:1;min-width:0;height:30px;padding:0;display:flex;align-items:center;justify-content:center;gap:6px;border-radius:4px;background:#ffffff08;border:1px solid var(--border-visible);color:var(--text-muted);cursor:pointer;transition:all .2s ease;overflow:hidden}.tactical-btn:hover{background:#ffffff1a;color:var(--text-bright)}.tactical-btn.maintenance{border-color:#fbbf2433;background:#fbbf240d}.tactical-btn.maintenance:hover{background:#fbbf2426;border-color:#fbbf24}.tactical-btn.reserve{border-color:#38bdf833;background:#38bdf80d}.tactical-btn.reserve:hover,.tactical-btn.reserved:hover{background:#38bdf826;border-color:#38bdf8}.tactical-btn.exit-maintenance{color:var(--color-red);background:#ff44441a;border-color:var(--color-red)}.tactical-btn.control-btn{background:#00ff8814;border-color:var(--color-primary);color:var(--color-primary)}.tactical-btn.control-btn:hover:not(:disabled){background:var(--color-primary);color:#000;box-shadow:0 0 15px #00ff884d}.tactical-btn.control-btn:disabled{opacity:.3;cursor:not-allowed;filter:grayscale(1)}.device-info-card__body_block-device,.device-info-card__body_unblock-device{width:auto!important;height:28px!important;min-width:28px!important;padding:0 4px!important}.device-info-card__body_block-device-icon{margin:0!important}.reservation-modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background-color:#020617f2;display:flex;justify-content:center;align-items:center;z-index:100000;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}.reservation-modal{background-color:var(--bg-surface);border:1px solid var(--border-visible);border-radius:6px;width:450px;max-width:90%;box-shadow:0 20px 50px #00000080;animation:modal-enter .3s cubic-bezier(.16,1,.3,1);position:relative;overflow:hidden}@keyframes modal-enter{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.reservation-modal-header{padding:24px;display:flex;align-items:center;justify-content:space-between;border-bottom:2px solid var(--border-visible);background:#0006}.reservation-modal-title{display:flex;align-items:center;gap:12px;font-size:1.25rem;font-weight:800;color:var(--text-bright);text-transform:uppercase;font-family:Outfit,sans-serif;letter-spacing:-.01em}.reservation-modal-body{padding:24px;display:flex;flex-direction:column;gap:20px}.device-id-badge{display:inline-flex;align-items:center;gap:8px;background:#0006;padding:8px 16px;border-radius:6px;border:1px solid var(--border-visible);font-family:JetBrains Mono,monospace;font-size:11px;width:fit-content;margin-bottom:12px}.reservation-modal p{color:var(--text-dim);font-size:13px;line-height:1.6;margin:0}.reservation-form-group{margin-bottom:0}.reservation-form-group label{display:block;color:var(--text-dim);font-size:var(--fs-xs);font-weight:800;margin-bottom:8px;text-transform:uppercase;letter-spacing:.1em;font-family:JetBrains Mono,monospace}.reservation-input{width:100%;background-color:#0000004d;border:1px solid var(--border-visible);border-radius:6px;padding:12px 16px;color:var(--text-bright);font-size:13px;box-sizing:border-box;transition:all .2s;font-family:JetBrains Mono,monospace}.reservation-input:focus{outline:none;border-color:var(--color-primary);box-shadow:0 0 10px #00ff881a}.duration-selector{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-bottom:8px}.duration-option{background-color:#0000004d;border:1px solid var(--border-visible);color:var(--text-dim);padding:10px;border-radius:6px;font-size:11px;cursor:pointer;text-align:center;transition:all .2s;font-weight:800;font-family:JetBrains Mono,monospace}.duration-option:hover{border-color:var(--text-muted);background-color:#ffffff05}.duration-option.active{background-color:#00ff880d;border-color:var(--color-primary);color:var(--color-primary);box-shadow:0 0 10px #00ff881a}.reservation-actions{padding:24px;display:flex;justify-content:flex-end;gap:12px;background:#0006;border-top:2px solid var(--border-visible)}.btn-cancel{background:transparent;border:1px solid var(--border-visible);color:var(--text-dim);padding:10px 24px;border-radius:6px;font-size:12px;font-weight:700;cursor:pointer;transition:all .2s;text-transform:uppercase;font-family:JetBrains Mono,monospace}.btn-reserve{background:var(--color-primary);color:var(--bg-page);border:none;padding:10px 24px;border-radius:6px;font-size:12px;font-weight:800;cursor:pointer;transition:all .2s;text-transform:uppercase;font-family:JetBrains Mono,monospace;box-shadow:0 0 15px #0f83}.btn-reserve:hover:not(:disabled){background:#00e67a;box-shadow:0 0 25px #0f86}.btn-reserve:disabled{background-color:var(--border-visible);color:var(--text-dim);cursor:not-allowed;box-shadow:none;filter:grayscale(1);opacity:.5}.error-message{color:#ff4d4d;font-size:11px;margin-top:12px;background-color:#ff4d4d0d;padding:8px 12px;border-radius:6px;border:1px solid rgba(255,77,77,.2);font-family:JetBrains Mono,monospace}.tag-modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:#020617f2;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);display:flex;align-items:center;justify-content:center;z-index:100000}.tag-modal-container{background:var(--bg-surface);width:100%;max-width:450px;border-radius:6px;border:1px solid var(--border-visible);box-shadow:0 20px 50px #00000080;overflow:hidden;animation:slideUp .3s cubic-bezier(.16,1,.3,1);position:relative}@keyframes slideUp{0%{transform:translateY(10px);opacity:0}to{transform:translateY(0);opacity:1}}.tag-modal-header{padding:24px;display:flex;align-items:center;justify-content:space-between;border-bottom:2px solid var(--border-visible);background:#0006}.tag-modal-title{display:flex;align-items:center;gap:12px;font-size:1.25rem;font-weight:800;color:var(--text-bright);text-transform:uppercase;font-family:Outfit,sans-serif;letter-spacing:-.01em}.title-icon{color:var(--color-primary)}.close-btn{background:transparent;border:none;color:var(--text-dim);cursor:pointer;padding:4px;border-radius:6px;transition:all .2s;display:flex;align-items:center;justify-content:center}.close-btn:hover{background:#ffffff0d;color:var(--text-bright)}.tag-modal-body{padding:24px;display:flex;flex-direction:column;gap:20px}.device-id-badge{display:inline-flex;align-items:center;gap:8px;background:#0006;padding:8px 16px;border-radius:6px;border:1px solid var(--border-visible);font-family:JetBrains Mono,monospace;font-size:11px}.device-id-badge .label{color:var(--text-dim);text-transform:uppercase;font-weight:800;font-size:10px}.device-id-badge .value{color:var(--color-primary);font-weight:800}.tag-input-section label,.tags-display-section label{display:block;font-size:var(--fs-xs);font-weight:800;color:var(--text-dim);text-transform:uppercase;letter-spacing:.1em;margin-bottom:8px;font-family:JetBrains Mono,monospace}.tag-input-section input{flex:1;background:#0000004d;border:1px solid var(--border-visible);border-radius:6px;padding:10px 14px;color:var(--text-bright);font-size:13px;transition:all .2s;font-family:JetBrains Mono,monospace}.tag-input-section input:focus{outline:none;border-color:var(--color-primary);box-shadow:0 0 15px #0f83}.add-inline-btn{background:var(--color-primary);color:var(--bg-page);border:none;border-radius:6px;width:40px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s}.add-inline-btn:hover:not(:disabled){background:#00e67a;box-shadow:0 0 15px #00ff884d}.add-inline-btn:disabled{background:var(--border-visible);color:var(--text-dim);cursor:not-allowed;filter:grayscale(1);opacity:.5}.tags-list{display:flex;flex-wrap:wrap;gap:8px;min-height:48px;padding:12px;background:#0006;border-radius:6px;border:1px dashed var(--border-visible)}.tag-pill-editable{display:flex;align-items:center;gap:6px;background:#00ff880d;color:var(--color-primary);padding:6px 12px;border-radius:6px;font-size:11px;font-weight:800;border:1px solid rgba(0,255,136,.3);font-family:JetBrains Mono,monospace;text-transform:uppercase;letter-spacing:.05em;box-shadow:0 0 10px #00ff880d}.remove-tag{background:transparent;border:none;color:var(--color-primary);cursor:pointer;padding:2px;border-radius:4px;display:flex;align-items:center;justify-content:center;transition:all .2s;opacity:.7}.remove-tag:hover{background:#0f83;opacity:1}.tag-modal-footer{padding:24px;display:flex;gap:12px;justify-content:flex-end;background:#0006;border-top:2px solid var(--border-visible)}.btn-cancel{padding:10px 24px;border-radius:6px;background:transparent;border:1px solid var(--border-visible);color:var(--text-dim);font-weight:700;cursor:pointer;transition:all .2s;text-transform:uppercase;font-size:12px;font-family:JetBrains Mono,monospace}.btn-cancel:hover{color:var(--text-bright);border-color:var(--text-muted)}.btn-save{padding:10px 24px;border-radius:6px;background:var(--color-primary);border:none;color:var(--bg-page);font-weight:800;cursor:pointer;transition:all .2s;box-shadow:0 0 15px #0f83;text-transform:uppercase;font-size:12px;font-family:JetBrains Mono,monospace}.btn-save:hover:not(:disabled){background:#00e67a;box-shadow:0 0 25px #0f86}.btn-save:disabled{background-color:var(--border-visible);color:var(--text-dim);cursor:not-allowed;box-shadow:none;filter:grayscale(1);opacity:.5}.device-explorer-card-container{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px;padding:16px;flex:1}.device-explorer-card-container::-webkit-scrollbar{width:6px}.device-explorer-card-container::-webkit-scrollbar-thumb{background:var(--border-medium);border-radius:8px}.device-explorer-container{display:flex;flex-direction:column;width:100%;gap:var(--space-md)}.device-explorer-header-container{display:flex;align-items:center;justify-content:space-between;padding:4px 24px;background:#0f0f1ae6;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border-bottom:2px solid var(--border-visible);position:sticky;top:0;z-index:1002;gap:var(--space-xl);flex-wrap:nowrap;box-shadow:0 10px 30px #0006}.device-explorer-header-left-container{display:flex;align-items:center;gap:24px;flex:1;min-width:0}.device-explorer-header-entry{display:flex;flex-direction:column;gap:4px;min-width:0}.device-explorer-header-entry-header{font-size:var(--fs-xs);font-weight:700;color:var(--text-dim);text-transform:uppercase;letter-spacing:.1em;font-family:JetBrains Mono,monospace}.device-explorer-header-value{display:flex;align-items:center;gap:8px}.device-explorer-header__platform-btn,.device-explorer-header__device-state{display:flex;align-items:center;gap:6px;padding:6px 12px;border-radius:6px;background:#0006;border:1px solid var(--border-visible);color:var(--text-muted);font-size:var(--fs-sm);font-weight:600;text-transform:uppercase;letter-spacing:.05em;cursor:pointer;transition:all .2s ease}.device-explorer-header__platform-btn:hover,.device-explorer-header__device-state:hover{background:#ffffff08;color:var(--text-bright);border-color:var(--border-subtle)}.device-explorer-header__platform-btn.selected,.device-explorer-header__device-state.selected{background:#00ff880d;color:var(--color-primary);border-color:#00ff884d;box-shadow:0 0 10px #00ff881a}.device-explorer-header__device-state.ready.selected{border-color:var(--color-primary);box-shadow:0 0 15px #0f83}.device-explorer-header__device-state.busy.selected{background:#ffb8000d;color:var(--color-amber);border-color:#ffb8004d;box-shadow:0 0 15px #ffb8001a}.device-explorer-header__device-state.offline.selected{background:#4a4a6a1a;color:var(--text-dim);border-color:var(--text-dim)}.device-explorer-search-wrapper{position:relative;width:320px}.device-explorer-search-icon{position:absolute;left:12px;top:50%;transform:translateY(-50%);pointer-events:none;opacity:.5}.device-explorer-header-text-filter{width:100%;height:32px;padding:0 12px 0 36px;border-radius:6px;border:1px solid var(--border-visible);background:#0006;font-family:JetBrains Mono,monospace;font-size:var(--fs-sm);color:var(--text-bright);transition:all .2s ease}.device-explorer-header-text-filter:focus{outline:none;border-color:var(--color-primary);background:#0009;box-shadow:0 0 15px #00ff881a}.device-explorer-header-text-filter::placeholder{color:var(--text-dim);text-transform:uppercase;font-size:var(--fs-xs);letter-spacing:.1em}.device-explorer-header-right-container{display:flex;align-items:center;gap:12px}.device-explorer-header-filter-count{display:flex;align-items:center;gap:8px;padding-right:16px;border-right:1px solid var(--border-subtle)}@media (max-width: 1024px){.device-explorer-header-container{flex-direction:column;align-items:stretch;gap:var(--space-md);padding:var(--space-md)}.device-explorer-header-left-container{flex-wrap:wrap;gap:var(--space-md)}.device-explorer-header-entry{flex:1;min-width:120px}.device-explorer-search-wrapper{width:100%}.device-explorer-header-right-container{justify-content:space-between;width:100%}}@media (max-width: 640px){.device-explorer-header-left-container{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-sm)}.device-explorer-header-right-container{flex-direction:column;align-items:stretch;gap:var(--space-sm)}.device-explorer-header-filter-count{justify-content:space-between;padding-right:0}}.device-explorer-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:80px 40px;background:#0f0f1a66;border:1px dashed var(--border-visible);border-radius:var(--radius-md);text-align:center;margin:60px auto 40px;max-width:600px;gap:var(--space-md)}.device-explorer-empty-icon{width:64px;height:64px;background:#00ff880d;border-radius:50%;display:flex;align-items:center;justify-content:center;color:var(--color-primary);margin-bottom:8px;border:1px solid rgba(0,255,136,.1)}.device-explorer-empty h3{font-size:1.5rem;font-weight:700;color:var(--text-bright);margin:0;font-family:Outfit,sans-serif}.device-explorer-empty p{color:var(--text-muted);font-size:14px;max-width:400px;line-height:1.6;margin:0}.device-explorer-empty .Button{margin-top:8px}.device-control-modal-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:var(--bg-app);z-index:6000;display:flex;flex-direction:column;padding:0;margin:0;animation:modal-fade-in .25s ease-out}.device-control-modal{flex:1;width:100%;height:100%;overflow:hidden;display:flex;flex-direction:column;background:var(--bg-app)}@keyframes modal-fade-in{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.device-control-view{display:flex;flex-direction:column;height:100%;width:100%;background:var(--bg-app);color:var(--text-main);overflow:hidden;font-family:Inter,sans-serif}*{scrollbar-width:thin;scrollbar-color:var(--border-medium) transparent}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border-medium);border-radius:8px;transition:background .2s}::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}.control-view-top-bar{display:flex;align-items:center;padding:0 24px;height:64px;background:var(--bg-surface);border-bottom:2px solid var(--border-visible);gap:24px;z-index:100;position:relative}.device-info-mini{display:flex;align-items:center;gap:16px}.device-pill{font-size:var(--fs-xs);font-weight:800;text-transform:uppercase;padding:2px 10px;border-radius:6px;letter-spacing:.1em;font-family:JetBrains Mono,monospace}.platform-pill{background:#00ff880d;color:var(--color-primary);border:1px solid rgba(0,255,136,.2)}.version-pill{background:#ffb8000d;color:var(--color-amber);border:1px solid rgba(255,184,0,.2)}.reserved-pill{background:#38bdf81a;color:#38bdf8;border:1px solid rgba(56,189,248,.3);animation:pulse-reserved-pill 2s infinite ease-in-out}.device-name-text{font-family:Outfit,sans-serif;font-weight:800;font-size:var(--fs-md);color:var(--text-bright);letter-spacing:.02em;text-transform:uppercase}.code-font{font-family:JetBrains Mono,monospace;font-size:var(--fs-xs);color:var(--text-dim);background:#0006;padding:4px 10px;border-radius:6px;border:1px solid var(--border-visible)}.back-to-devices-btn{background:#0006;color:var(--text-dim);border:1px solid var(--border-visible);padding:8px 16px;border-radius:6px;font-size:var(--fs-xs);font-weight:800;text-transform:uppercase;letter-spacing:.1em;display:flex;align-items:center;gap:8px;transition:all .2s;cursor:pointer}.back-to-devices-btn:hover{background:#ffffff08;border-color:var(--color-primary);color:var(--color-primary)}.control-view-main{display:flex;flex-direction:row;flex:1;overflow:hidden;padding:24px;gap:32px;background:var(--bg-page);justify-content:center;align-items:stretch;min-height:0}.control-view-main.is-landscape{align-items:flex-start}.control-view-main.omni-mode .device-preview-column{display:none}.control-view-main.omni-mode .interaction-tabs{margin-bottom:var(--space-md);border-radius:var(--radius-sm)}.control-view-main.omni-mode .device-interactions-column{max-width:100%;padding:0 0 var(--space-md) 0}.device-preview-column{display:flex;flex-direction:column;align-items:center;gap:24px;flex-shrink:0;min-width:400px}.device-screen-wrapper{position:relative;padding:12px;background:#000;border-radius:48px;box-shadow:0 0 0 2px #334155,0 20px 50px #0009,0 0 80px #10b9810d;border:1px solid rgba(255,255,255,.1);transition:all .5s cubic-bezier(.16,1,.3,1)}.device-screen-wrapper:hover{transform:translateY(-4px) scale(1.005);box-shadow:0 0 0 2px var(--primary),0 30px 60px #000c,0 0 100px #10b9811a}.device-stream-canvas{position:relative;background:#000;border-radius:28px;overflow:hidden;cursor:crosshair;transition:box-shadow .3s ease,border-color .3s ease;outline:none;border:2px solid transparent}.device-stream-canvas.focused{border-color:var(--primary);box-shadow:0 0 20px var(--primary-glow)}.device-stream-image{pointer-events:none;-webkit-user-select:none;user-select:none;-webkit-user-drag:none}.device-stream-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;width:100%;color:var(--text-muted);gap:16px;background:radial-gradient(circle at center,#0f172a,#020617)}.device-footer-actions{display:flex;width:100%;background:#0f172acc;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-radius:16px;border:1px solid rgba(255,255,255,.08);padding:6px;gap:6px;box-shadow:0 10px 25px -5px #0006,0 0 15px #10b9810d}.footer-action-btn{flex:1;display:flex;align-items:center;justify-content:center;gap:8px;padding:12px;color:var(--text-muted);font-size:11px;text-transform:uppercase;font-weight:700;letter-spacing:.05em;border:none;background:transparent;border-radius:var(--radius-sm);transition:all .2s ease}.footer-action-btn:hover{background:#ffffff0d;color:var(--text-main)}.footer-action-btn.active{background:var(--primary);color:var(--text-inverse);box-shadow:0 0 10px var(--primary-glow)}.footer-divider{width:1px;height:24px;background:var(--border-medium);margin:auto 4px}.hint-text{font-size:var(--fs-xs);color:var(--text-muted);font-style:italic;margin-top:4px}.device-interactions-column{flex:1;display:flex;flex-direction:column;gap:0;min-width:450px;max-width:1200px;height:100%;overflow:hidden;min-height:0}.interaction-tabs{display:flex;gap:4px;background:var(--bg-surface);padding:4px;border-radius:6px;border:1px solid var(--border-visible);margin-bottom:16px;flex-shrink:0}.tab-btn{flex:1;padding:8px 12px;background:transparent;border:none;font-size:var(--fs-xs);font-weight:800;color:var(--text-dim);text-transform:uppercase;letter-spacing:.1em;border-radius:4px;cursor:pointer;transition:all .2s;font-family:JetBrains Mono,monospace}.tab-btn:hover{color:var(--text-bright);background:#ffffff05}.tab-btn.active{color:var(--bg-page);background:var(--color-primary);box-shadow:0 0 15px #00ff884d}.interactions-scroll-area{flex:1;overflow-y:auto;overflow-x:hidden;padding-right:8px;display:flex;flex-direction:column}.action-card{background:#0003;border-radius:6px;padding:20px;border:1px solid var(--border-visible);transition:all .2s;display:flex;flex-direction:column;gap:16px}.action-card:hover{background:#ffffff03;border-color:var(--color-primary);box-shadow:0 4px 20px #0006}.action-card-title{font-family:Outfit,sans-serif;font-size:13px;font-weight:800;color:var(--text-bright);display:flex;align-items:center;gap:12px;text-transform:uppercase;letter-spacing:.1em;opacity:.9}.compact-label{font-size:11px;color:var(--text-muted);font-weight:600;text-transform:uppercase;letter-spacing:.05em}.btn-sm{padding:8px 16px;font-size:11px}.type-input-field.compact,.app-select-dropdown.compact{padding:10px;font-size:13px}.file-select-box.compact{padding:var(--space-md);margin-bottom:8px}.clipboard-display.compact{min-height:48px;max-height:80px;overflow-y:auto;padding:8px;font-size:11px;background:#0006}.actions-row{display:flex;gap:var(--space-xl)}.install-app-section,.uninstall-app-section{flex:1;display:flex;flex-direction:column;gap:12px;min-width:0}.file-select-box{background:#ffffff08;border:2px dashed var(--border-medium);border-radius:var(--radius-md);padding:var(--space-xl);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-md);transition:all .3s ease}.file-select-box:hover{background:#10b9810d;border-color:var(--primary)}.btn-premium,.btn-secondary{padding:10px 20px;border-radius:var(--radius-sm);font-weight:700;font-size:11px;text-transform:uppercase;letter-spacing:.05em;cursor:pointer;transition:all .2s cubic-bezier(.16,1,.3,1);display:flex;align-items:center;justify-content:center;gap:8px;border:none}.btn-premium{background:var(--primary);color:#000}.btn-premium:hover:not(:disabled){background:var(--primary-hover);transform:translateY(-1px);box-shadow:0 4px 12px var(--primary-glow)}.btn-secondary{background:#ffffff0d;color:var(--text-secondary);border:1px solid var(--border-medium)}.btn-secondary:hover:not(:disabled){background:#ffffff1a;color:var(--text-main);border-color:var(--text-muted)}.btn-secondary.active{background:var(--primary-soft);color:var(--primary);border-color:var(--primary)}.btn-sm{padding:6px 12px!important;font-size:var(--fs-xs)!important}.type-input-field,.app-select-dropdown{width:100%;padding:10px 14px;border-radius:var(--radius-sm);border:1px solid var(--border-medium);background:#0003;font-size:13px;color:var(--text-main);transition:all .2s ease}.type-input-field:focus{outline:none;border-color:var(--primary);background:#0006;box-shadow:0 0 0 3px var(--primary-soft)}.clipboard-display{background:var(--bg-glass);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border-radius:var(--radius-md);border:1px solid var(--border-medium);padding:var(--space-md);margin-top:var(--space-md);font-family:Fira Code,monospace;font-size:12px;color:#38bdf8;min-height:80px;box-shadow:inset 0 2px 10px #00000080}.log-display-area{flex:1;min-height:0;overflow-y:auto;font-family:Fira Code,monospace;font-size:11px;line-height:1.5;background:var(--bg-glass);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);padding:16px;border-radius:0 0 var(--radius-md) var(--radius-md);color:var(--text-muted);box-shadow:inset 0 2px 20px #00000080;border:1px solid var(--border-medium);border-top:none;scrollbar-width:thin;scrollbar-color:var(--primary) transparent}.log-line{display:flex;gap:8px;margin-bottom:2px;white-space:pre-wrap;word-break:break-all;border-left:2px solid transparent;padding-left:8px;transition:background .2s ease}.log-line:hover{background:#ffffff08}.log-index{color:var(--text-muted);opacity:.3;-webkit-user-select:none;user-select:none;min-width:32px;text-align:right;font-size:var(--fs-xs)}.log-content{flex:1}.log-notice{border-left-color:#38bdf8;color:#e2e8f0}.log-error{border-left-color:#f43f5e;color:#fecdd3;background:#f43f5e0d}.log-warn{border-left-color:#fbbf24;color:#fef3c7}.log-debug{border-left-color:transparent;color:var(--text-muted)}.log-toolbar{display:flex;justify-content:space-between;align-items:center;background:#0f172a99;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);padding:8px 16px;border-radius:var(--radius-md) var(--radius-md) 0 0;border:1px solid var(--border-medium);border-bottom:none}.log-filter-group,.log-actions-group{display:flex;gap:8px;align-items:center}.log-search-box{position:relative;display:flex;align-items:center}.search-icon-inline{position:absolute;left:8px;color:var(--text-muted);pointer-events:none;opacity:.6}.log-search-box .type-input-field.tiny{padding-left:28px!important;width:140px;background:#0003;border-color:var(--border-subtle)}.log-stat-pill{font-size:var(--fs-xs);background:#10b9811a;color:var(--primary);padding:3px 8px;border-radius:4px;font-weight:700;text-transform:uppercase;letter-spacing:.05em}.animate-pulse{animation:pulse-op 1.5s infinite}@keyframes pulse-op{0%,to{opacity:1}50%{opacity:.4}}.tab-content{animation:slideUpFade .4s cubic-bezier(.16,1,.3,1);display:flex;flex-direction:column;flex:1;min-height:0}@keyframes slideUpFade{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.gestures-grid-container{display:flex;flex-direction:column;align-items:center;gap:12px}.gestures-dpad{display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(3,1fr);gap:8px;width:140px;height:140px;padding:12px;background:#0003;border-radius:50%;border:1px solid rgba(255,255,255,.05)}.dpad-btn{display:flex;align-items:center;justify-content:center;background:#ffffff08;border:1px solid rgba(255,255,255,.05);border-radius:8px;color:var(--text-muted);cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1)}.dpad-btn:hover{background:var(--primary);border-color:var(--primary);color:#fff;transform:scale(1.1);box-shadow:0 0 20px var(--primary-glow);z-index:2}.dpad-btn:active{transform:scale(.95)}.dpad-center{background:radial-gradient(circle,var(--primary-glow) 0%,transparent 70%);border-radius:50%;opacity:.2}.app-mgmt-content{display:flex;flex-direction:row;gap:var(--space-xl);align-items:flex-start}.upload-box-row,.uninstall-controls-row{display:flex;gap:12px;align-items:center;margin-top:8px}.file-upload-launcher{flex:1;display:flex;align-items:center;gap:12px;padding:10px 16px;background:#ffffff08;border:1px dashed var(--border-medium);border-radius:var(--radius-md);cursor:pointer;font-size:13px;color:var(--text-muted);transition:all .2s ease}.file-upload-launcher:hover{background:#10b9810d;border-color:var(--primary);color:var(--text-main)}.divider-v{width:1px;align-self:stretch;background:linear-gradient(180deg,transparent,var(--border-medium),transparent)}.select-wrapper{flex:1;position:relative;display:flex;align-items:center}.select-loader{position:absolute;right:32px;color:var(--primary)}.btn-destructive{background:#ef444433;color:#ef4444;border:1px solid rgba(239,68,68,.3);padding:10px 20px;border-radius:var(--radius-md);font-weight:700;font-size:12px;display:flex;align-items:center;gap:8px;transition:all .3s ease}.btn-destructive:hover:not(:disabled){background:var(--color-red);color:#fff;box-shadow:0 4px 15px #ef444466}.manual-input-box{margin-top:8px;padding-top:8px;border-top:1px solid rgba(255,255,255,.05)}.type-input-field.tiny{padding:8px 12px;font-size:12px;opacity:.6}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.action-card-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:12px}.screenshot-workspace{display:flex;gap:20px;flex:1;min-height:0;overflow:hidden}.screenshot-gallery-sidebar{width:180px;display:flex;flex-direction:column;gap:16px;flex-shrink:0;min-height:0}.take-screenshot-btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%}.screenshot-thumbnails-list{flex:1;overflow-y:auto;display:flex;flex-direction:column;gap:10px;padding-right:4px;min-height:0}.screenshot-thumb-item{position:relative;border-radius:8px;overflow:hidden;aspect-ratio:9/16;background:#0006;border:2px solid transparent;cursor:pointer;transition:all .2s ease;flex-shrink:0}.screenshot-thumb-item:hover{border-color:#10b98166}.screenshot-thumb-item.active{border-color:var(--primary);box-shadow:0 0 12px var(--primary-glow)}.screenshot-thumb-item img{width:100%;height:100%;object-fit:cover;opacity:.7;transition:opacity .2s ease}.screenshot-thumb-item:hover img,.screenshot-thumb-item.active img{opacity:1}.thumb-time{position:absolute;bottom:0;left:0;right:0;background:#000000b3;color:#fff;font-size:var(--fs-xs);padding:2px 4px;text-align:center;font-family:JetBrains Mono,monospace}.thumb-delete-btn{position:absolute;top:4px;right:4px;width:20px;height:20px;border-radius:4px;background:#ef4444cc;color:#fff;border:none;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s ease}.screenshot-thumb-item:hover .thumb-delete-btn{opacity:1}.thumb-delete-btn:hover{background:var(--color-red)}.screenshot-main-preview{flex:1;background:#0000004d;border-radius:8px;display:flex;align-items:center;justify-content:center;overflow:hidden;position:relative;border:1px solid rgba(255,255,255,.05);min-height:0}.preview-container{display:flex;flex-direction:column;width:100%;height:100%;position:relative}.preview-image-wrapper{flex:1;position:relative;min-height:0}.preview-image-wrapper img{position:absolute;top:20px;bottom:20px;left:20px;right:20px;max-width:calc(100% - 40px);max-height:calc(100% - 40px);object-fit:contain;margin:auto;border-radius:4px;box-shadow:0 10px 40px #00000080}.preview-footer{padding:16px 24px;background:#0006;border-top:1px solid rgba(255,255,255,.05);display:flex;justify-content:space-between;align-items:center}.preview-meta{display:flex;align-items:center;gap:8px;font-size:11px;color:var(--text-muted)}.meta-label{text-transform:uppercase;font-weight:700;opacity:.5}.meta-divider{opacity:.2}.preview-actions{display:flex;gap:12px}.btn-text-only{background:transparent;border:none;color:var(--text-muted);font-size:var(--fs-xs);font-weight:700;letter-spacing:.05em;cursor:pointer;padding:4px 8px;border-radius:4px}.btn-text-only:hover{color:#ef4444;background:#ef44440d}.preview-empty-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;color:var(--text-muted);font-size:13px;opacity:.6}.empty-gallery-state{display:flex;align-items:center;justify-content:center;height:100px;color:var(--text-muted);font-size:11px;font-style:italic;opacity:.5}.interactions-scroll-area.terminal-mode{overflow:hidden;padding:0;display:flex;flex-direction:column;height:100%;min-height:0}.interactions-scroll-area.terminal-mode .action-card.full-height{height:100%;min-height:0;border-radius:0;border:none}.interactions-scroll-area.screenshot-mode{overflow:hidden;height:100%;min-height:0;display:flex;flex-direction:column;padding:0}.interactions-scroll-area.screenshot-mode .tab-content{display:flex;flex-direction:column;flex:1 1 0%;min-height:0;padding:0}.interactions-scroll-area.screenshot-mode .action-card.screenshot-card{display:flex;flex-direction:column;flex:1;min-height:0;margin-bottom:0;border-radius:0;border:none;padding:0;overflow:hidden}.terminal-container{display:flex;flex-direction:column;background-color:var(--bg-page);color:var(--text-bright);font-family:JetBrains Mono,monospace;border-radius:6px;overflow:hidden;height:100%;max-height:100%;width:100%;min-height:0;border:1px solid var(--border-visible);box-shadow:0 20px 50px #00000080;position:relative}.terminal-header{display:flex;align-items:center;justify-content:space-between;padding:12px 20px;background-color:#0006;border-bottom:2px solid var(--border-visible)}.terminal-controls{display:flex;gap:8px;width:60px}.dot{width:8px;height:8px;border-radius:4px;border:1px solid rgba(255,255,255,.1)}.dot.red{background-color:#ff4d4d}.dot.yellow{background-color:#fc0}.dot.green{background-color:var(--color-primary)}.terminal-title{font-size:var(--fs-xs);font-weight:800;color:var(--text-dim);text-transform:uppercase;letter-spacing:.15em;font-family:JetBrains Mono,monospace}.terminal-actions{display:flex;justify-content:flex-end;width:60px}.terminal-action-btn{background:transparent;border:1px solid var(--border-visible);color:var(--text-dim);font-size:var(--fs-xs);font-weight:800;padding:4px 10px;border-radius:6px;cursor:pointer;transition:all .2s;text-transform:uppercase;font-family:JetBrains Mono,monospace}.terminal-action-btn:hover{color:var(--text-bright);background:#ffffff0d;border-color:var(--text-muted)}.terminal-history{flex:1;overflow-y:auto;overflow-x:hidden;padding:20px;font-size:12px;line-height:1.6;scrollbar-width:thin;scrollbar-color:var(--color-primary) var(--bg-page);min-height:0}.terminal-history::-webkit-scrollbar{width:6px}.terminal-history::-webkit-scrollbar-track{background:transparent}.terminal-history::-webkit-scrollbar-thumb{background-color:var(--border-visible);border-radius:4px}.terminal-history::-webkit-scrollbar-thumb:hover{background-color:var(--color-primary)}.terminal-line{margin-bottom:6px;white-space:pre-wrap;word-break:normal;overflow-wrap:anywhere}.terminal-line.command{color:var(--color-primary);font-weight:600}.terminal-line.output{color:var(--text-body)}.terminal-line.error{color:#ff4d4d}.terminal-line.system{color:var(--text-dim);font-style:italic;border-bottom:1px dashed var(--border-visible);padding-bottom:6px;margin-bottom:12px}.terminal-input-area{display:flex;align-items:center;padding:16px 20px;background-color:#0006;border-top:2px solid var(--border-visible)}.terminal-prompt{color:var(--color-primary);margin-right:12px;font-weight:800;-webkit-user-select:none;user-select:none}.terminal-input{flex:1;background:transparent;border:none;color:var(--text-bright);font-family:inherit;font-size:13px;outline:none;font-weight:500}.terminal-input::placeholder{color:#ffffff1a}.terminal-loading-indicator{display:inline-block;width:8px;height:16px;background-color:var(--color-primary);animation:blink 1s step-end infinite;vertical-align:middle;margin-left:8px;border-radius:4px}@keyframes blink{0%,to{opacity:1}50%{opacity:0}}.omni-inspector-container{display:flex;flex-direction:column;height:100%;background:var(--bg-page);color:var(--text-main);font-family:Inter,sans-serif;overflow:hidden;position:relative}.omni-main-content{flex:1;display:flex;gap:16px;padding:16px;overflow:hidden;height:100%}.omni-screenshot-panel{width:380px;min-width:320px;flex-shrink:0;display:flex;flex-direction:column;background:var(--bg-surface);border-radius:6px;border:1px solid var(--border-visible);overflow:hidden}.omni-screenshot-header{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;background:#0006;border-bottom:2px solid var(--border-visible)}.omni-screenshot-title{font-size:var(--fs-xs);font-weight:800;text-transform:uppercase;letter-spacing:.1em;color:var(--text-bright);opacity:.9;font-family:JetBrains Mono,monospace}.omni-mode-toggle{display:flex;background:#0000004d;padding:2px;border-radius:6px;border:1px solid var(--border-visible)}.omni-mode-btn{display:flex;align-items:center;gap:6px;padding:4px 10px;background:transparent;border:none;border-radius:4px;color:var(--text-dim);font-size:var(--fs-xs);font-weight:800;cursor:pointer;transition:all .2s;text-transform:uppercase;letter-spacing:.05em;font-family:JetBrains Mono,monospace}.omni-mode-btn.active{background:var(--color-primary);color:var(--bg-page);box-shadow:0 0 10px #00ff884d}.omni-refresh-btn{display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--color-primary);color:var(--bg-page);border:none;border-radius:6px;font-size:var(--fs-xs);font-weight:800;text-transform:uppercase;letter-spacing:.1em;cursor:pointer;transition:all .2s;font-family:JetBrains Mono,monospace}.omni-refresh-btn:hover:not(:disabled){background:#00e67a;box-shadow:0 0 15px #0f86}.omni-refresh-btn:disabled{opacity:.5;cursor:not-allowed}.omni-screenshot-container{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;padding:12px;background:var(--bg-glass);position:relative;overflow:hidden}.omni-screenshot-wrapper{position:relative;max-width:100%;max-height:100%;height:100%;display:flex;align-items:center;justify-content:center;-webkit-user-select:none;user-select:none}.omni-screenshot-wrapper.interactable{cursor:crosshair}.omni-screenshot-img{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;border-radius:4px;display:block}.omni-overlay{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}.omni-overlay>*{pointer-events:auto}.omni-hit-area{position:absolute;cursor:pointer;background:transparent;transition:background .15s ease}.omni-hit-area:hover{background:#10b98133}.omni-frame-hover{position:absolute;border:2px solid var(--primary);background:#10b9811a;pointer-events:none;border-radius:6px}.omni-frame-select{position:absolute;border:2px solid var(--primary);background:#10b98133;pointer-events:none;box-shadow:0 0 20px var(--primary-glow);border-radius:6px}.omni-loading-overlay{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;background:#000c;color:var(--text-muted);font-size:11px}.omni-spinner{width:24px;height:24px;border:2px solid var(--border-medium);border-top-color:var(--primary);border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.omni-empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;color:var(--text-muted);text-align:center;padding:32px;font-size:12px}.omni-empty-state svg{opacity:.3}.omni-empty-state.small{padding:24px;font-size:11px}.omni-tree-panel{flex:1;min-width:0;display:flex;flex-direction:column;background:#0003;border-radius:6px;border:1px solid var(--border-visible);overflow:hidden;min-height:0}.omni-tree-content{flex:1;min-height:0;overflow-y:auto;padding:8px;scrollbar-width:thin;scrollbar-color:var(--border-medium) transparent}.omni-tree-header{display:flex;align-items:center;justify-content:space-between;padding:12px;background:#0006;border-bottom:2px solid var(--border-visible)}.omni-tree-title{display:flex;align-items:center;gap:8px;font-size:var(--fs-xs);font-weight:800;text-transform:uppercase;letter-spacing:.1em;color:var(--text-bright);opacity:.9;font-family:JetBrains Mono,monospace}.omni-count-badge{font-size:var(--fs-xs);background:#00ff880d;color:var(--color-primary);padding:2px 8px;border-radius:6px;font-weight:800;text-transform:uppercase;font-family:JetBrains Mono,monospace}.omni-action-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;background:#ffffff05;border:1px solid var(--border-visible);border-radius:6px;color:var(--text-dim);cursor:pointer;transition:all .2s}.omni-action-btn:hover{background:#ffffff0d;color:var(--color-primary);border-color:var(--color-primary)}.omni-tree-search{display:flex;align-items:center;gap:8px;margin:12px;padding:8px 12px;background:#0006;border:1px solid var(--border-visible);border-radius:6px;transition:all .2s}.omni-tree-search:focus-within{border-color:var(--color-primary);box-shadow:0 0 10px #00ff881a}.omni-tree-search input{flex:1;background:transparent;border:none;color:var(--text-bright);font-size:11px;outline:none;font-family:JetBrains Mono,monospace}.tree-item{display:flex;align-items:center;gap:8px;padding:8px 12px;margin-bottom:2px;border-radius:4px;cursor:pointer;font-size:12px;color:var(--text-dim);transition:all .15s;border:1px solid transparent;min-height:36px;background:#0000001a}.tree-item:hover{background:#ffffff05;color:var(--text-bright)}.tree-item.selected{background:#00ff8814;color:var(--color-primary);border-color:#0f86;box-shadow:inset 0 0 0 1px #0f83}.tree-item.hovered:not(.selected){background:#ffffff0a;border-color:#ffffff1a;color:var(--text-bright)}.tree-node{display:flex;flex-direction:column}.tree-children{margin-left:0}.tree-toggle{display:flex;align-items:center;justify-content:center;width:18px;height:18px;border:none;background:transparent;color:var(--text-muted);cursor:pointer;border-radius:3px;flex-shrink:0;padding:0;transition:color .15s,background .15s}.tree-toggle:hover{color:var(--color-primary);background:#00ff881a}.tree-toggle-spacer{display:inline-block;width:18px;flex-shrink:0}.tree-item-indent{flex-shrink:0}.tree-icon{color:var(--text-muted);flex-shrink:0;opacity:.6}.tree-label{flex:1;font-size:12px;font-family:JetBrains Mono,Fira Code,monospace;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tree-badge{font-size:10px;font-weight:700;background:#ffffff0f;color:var(--text-muted);padding:1px 5px;border-radius:4px;flex-shrink:0;font-family:JetBrains Mono,monospace}.omni-details-panel{flex:1;min-width:280px;max-width:360px;display:flex;flex-direction:column;background:var(--bg-surface);border-radius:6px;border:1px solid var(--border-visible);overflow:hidden;min-height:0}.omni-details-content{flex:1;min-height:0;overflow-y:auto;padding:16px;scrollbar-width:thin;scrollbar-color:var(--border-medium) transparent}.omni-header-left{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.omni-tree-actions{display:flex;gap:6px;align-items:center}.omni-clear-btn{background:transparent;border:none;color:var(--text-muted);cursor:pointer;font-size:16px;padding:0 4px;line-height:1;border-radius:3px}.omni-clear-btn:hover{color:var(--text-bright);background:#ffffff14}.omni-info-table,.omni-locators-list{display:flex;flex-direction:column;gap:6px}.omni-details-header{display:flex;align-items:center;gap:8px;padding:12px 16px;background:#0006;border-bottom:2px solid var(--border-visible);font-size:var(--fs-xs);font-weight:800;text-transform:uppercase;letter-spacing:.1em;color:var(--text-bright);opacity:.9;font-family:JetBrains Mono,monospace}.omni-section{margin-bottom:24px}.omni-section-header{font-size:var(--fs-xs);font-weight:800;text-transform:uppercase;letter-spacing:.1em;color:var(--text-dim);margin-bottom:12px;padding-bottom:8px;border-bottom:1px solid var(--border-visible);font-family:JetBrains Mono,monospace}.omni-info-row{display:flex;gap:16px;padding:12px 16px;background:#0006;border-radius:6px;border:1px solid var(--border-visible);min-height:44px;align-items:center}.omni-info-key{width:60px;flex-shrink:0;font-size:var(--fs-xs);font-weight:800;text-transform:uppercase;color:var(--text-dim);font-family:JetBrains Mono,monospace}.omni-info-value{flex:1;font-size:11px;color:var(--text-bright);word-break:break-all}.omni-layout-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}.omni-layout-item{display:flex;flex-direction:column;gap:6px;padding:12px 8px;background:#0006;border-radius:6px;border:1px solid var(--border-visible);text-align:center;min-height:60px;justify-content:center}.omni-layout-label{font-size:var(--fs-xs);font-weight:800;text-transform:uppercase;color:var(--text-dim);font-family:JetBrains Mono,monospace}.omni-layout-value{font-size:12px;font-weight:800;color:var(--color-primary);font-family:JetBrains Mono,monospace}.omni-locator-row{display:flex;align-items:center;gap:12px;padding:12px 16px;background:#0009;border-radius:6px;border:1px solid var(--border-visible);border-left:3px solid var(--color-primary);transition:all .2s;min-height:48px}.omni-locator-strategy{flex-shrink:0;font-size:var(--fs-xs);font-weight:800;text-transform:uppercase;background:#00ff880d;color:var(--color-primary);padding:2px 6px;border-radius:6px;letter-spacing:.05em;font-family:JetBrains Mono,monospace}.omni-locator-value{flex:1;font-family:JetBrains Mono,monospace;font-size:11px;color:var(--text-muted);word-break:break-all;line-height:1.5}.omni-copy-btn{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:24px;height:24px;background:#ffffff08;border:1px solid var(--border-medium);border-radius:var(--radius-sm);color:var(--text-muted);cursor:pointer;transition:all .2s ease}.omni-copy-btn:hover,.omni-copy-btn.copied{background:var(--primary);border-color:var(--primary);color:#000}.omni-attributes-table{display:flex;flex-direction:column;gap:4px;background:var(--bg-glass);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border-radius:var(--radius-sm);border:1px solid var(--border-medium);padding:8px;max-height:200px;overflow-y:auto}.omni-attr-row{display:flex;gap:8px;padding:6px 8px;border-radius:4px;transition:background .2s ease}.omni-attr-row:hover{background:#ffffff08}.omni-attr-key{width:120px;flex-shrink:0;font-size:var(--fs-xs);font-weight:600;color:var(--text-muted);font-family:Fira Code,monospace}.omni-attr-value{flex:1;font-size:11px;color:#e2e8f0;font-family:Fira Code,monospace;word-break:break-all}.omni-tree-content::-webkit-scrollbar,.omni-details-content::-webkit-scrollbar,.omni-attributes-table::-webkit-scrollbar{width:6px}.omni-tree-content::-webkit-scrollbar-track,.omni-details-content::-webkit-scrollbar-track,.omni-attributes-table::-webkit-scrollbar-track{background:transparent}.omni-tree-content::-webkit-scrollbar-thumb,.omni-details-content::-webkit-scrollbar-thumb,.omni-attributes-table::-webkit-scrollbar-thumb{background:var(--border-medium);border-radius:8px}.omni-tree-content::-webkit-scrollbar-thumb:hover,.omni-details-content::-webkit-scrollbar-thumb:hover,.omni-attributes-table::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}.omni-quick-actions{display:flex;flex-direction:column;gap:16px}.omni-input-group{display:flex;flex-direction:column;gap:8px}.omni-input-field{width:100%;background:#0000004d;border:1px solid var(--border-medium);border-radius:var(--radius-sm);padding:8px 12px;color:var(--text-main);font-size:12px;outline:none;transition:all .2s ease}.omni-input-field:focus{border-color:var(--primary);background:#00000080}.omni-gestures-container{display:flex;flex-direction:column;align-items:center;gap:12px;padding:16px;background:#0003;border-radius:var(--radius-md);border:1px solid var(--border-subtle)}.omni-dpad{display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(3,1fr);gap:8px;width:120px;height:120px}.omni-dpad-btn{display:flex;align-items:center;justify-content:center;background:#ffffff08;border:1px solid rgba(255,255,255,.05);border-radius:8px;color:var(--text-muted);cursor:pointer;transition:all .2s ease}.omni-dpad-btn:hover{background:var(--primary);color:#000;transform:scale(1.1)}.omni-clipboard-box{display:flex;gap:8px;align-items:center}.omni-clipboard-val{flex:1;background:var(--bg-glass);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border:1px solid var(--border-medium);border-radius:4px;padding:8px;font-family:Fira Code,monospace;font-size:11px;color:#38bdf8;min-height:32px;overflow-x:auto;white-space:nowrap}.omni-details-tabs{display:flex;background:#00000080;border-bottom:1px solid var(--border-visible);flex-shrink:0}.omni-details-tab{display:flex;align-items:center;gap:5px;flex:1;padding:10px 8px;border:none;background:transparent;color:var(--text-muted);font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;cursor:pointer;border-bottom:2px solid transparent;transition:all .15s ease;font-family:JetBrains Mono,monospace;justify-content:center}.omni-details-tab:hover:not(:disabled){color:var(--text-bright);background:#ffffff08}.omni-details-tab.active{color:var(--color-primary);border-bottom-color:var(--color-primary);background:#00ff880a}.omni-details-tab:disabled{opacity:.3;cursor:not-allowed}.omni-locator-row{display:flex;align-items:flex-start;gap:10px;padding:10px 14px;background:#0006;border-radius:6px;border:1px solid var(--border-visible);border-left:3px solid var(--color-primary);transition:all .15s;cursor:pointer}.omni-locator-row:hover{background:#ffffff05;border-color:var(--color-primary)}.omni-locator-row.selected-for-code{border-color:var(--color-primary);background:#00ff880f;box-shadow:0 0 12px #00ff8814}.omni-locator-left{flex:1;display:flex;flex-direction:column;gap:4px;min-width:0}.omni-locator-top{display:flex;align-items:center;gap:6px;flex-wrap:wrap}.omni-stability-badge{display:inline-flex;align-items:center;gap:3px;font-size:9px;font-weight:800;padding:2px 6px;border-radius:4px;text-transform:uppercase;letter-spacing:.05em;font-family:JetBrains Mono,monospace}.omni-stability-badge.stable{background:#10b9811f;color:#10b981;border:1px solid rgba(16,185,129,.25)}.omni-stability-badge.moderate{background:#fbbf241a;color:#fbbf24;border:1px solid rgba(251,191,36,.25)}.omni-stability-badge.fragile{background:#f43f5e1a;color:#f43f5e;border:1px solid rgba(244,63,94,.25)}.omni-stability-reason{font-size:10px;color:var(--text-muted);font-style:italic;line-height:1.3}.omni-section-badge{font-size:9px;font-weight:600;background:#00ff8814;color:var(--color-primary);padding:2px 6px;border-radius:4px;margin-left:6px;vertical-align:middle;text-transform:uppercase;letter-spacing:.05em}.tree-text-preview{font-size:10px;color:var(--text-muted);font-style:italic;max-width:80px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0}.omni-search-hint{display:flex;align-items:center;gap:5px;padding:4px 14px;font-size:10px;color:var(--color-primary);opacity:.7;font-style:italic;background:#00ff8808;border-bottom:1px solid rgba(0,255,136,.08)}.omni-insight-panel{display:flex;flex-direction:column;gap:16px}.omni-insight-role{display:flex;align-items:center;gap:14px;padding:16px;background:#00ff880a;border-radius:8px;border:1px solid rgba(0,255,136,.12)}.omni-insight-emoji{font-size:28px;line-height:1}.omni-insight-role-name{font-size:14px;font-weight:700;color:var(--text-bright);font-family:JetBrains Mono,monospace}.omni-insight-interactable{margin-top:4px;display:flex;gap:6px}.omni-badge-green{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:700;color:#10b981;background:#10b9811a;padding:2px 8px;border-radius:4px;border:1px solid rgba(16,185,129,.2)}.omni-badge-gray{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:700;color:var(--text-muted);background:#ffffff0a;padding:2px 8px;border-radius:4px;border:1px solid var(--border-medium)}.omni-insight-warning{padding:10px 12px;background:#fbbf240f;border:1px solid rgba(251,191,36,.2);border-radius:6px;font-size:11px;color:#fbbf24}.omni-insight-description{display:flex;gap:10px;align-items:flex-start;padding:12px;background:#0000004d;border-radius:6px;border:1px solid var(--border-visible)}.omni-insight-icon{color:var(--color-primary);flex-shrink:0;margin-top:2px}.omni-insight-description p{font-size:12px;color:var(--text-main);line-height:1.6;margin:0}.omni-insight-best-locator,.omni-insight-attributes{display:flex;flex-direction:column;gap:8px}.omni-quick-facts{display:flex;flex-direction:column;gap:4px}.omni-quick-fact-row{display:flex;justify-content:space-between;align-items:center;padding:6px 10px;border-radius:4px;background:#0003}.omni-quick-fact-label{font-size:11px;color:var(--text-muted);font-weight:600}.omni-quick-fact-value{font-size:11px;color:var(--text-main);font-family:JetBrains Mono,monospace}.omni-quick-fact-value.true{color:#10b981;font-weight:700}.omni-codegen-panel{display:flex;flex-direction:column;gap:12px}.omni-codegen-frameworks{display:flex;gap:4px;flex-wrap:wrap}.omni-fw-btn{flex:1;padding:6px 4px;background:#ffffff08;border:1px solid var(--border-visible);border-radius:6px;color:var(--text-muted);font-size:10px;font-weight:700;cursor:pointer;transition:all .15s;white-space:nowrap}.omni-fw-btn:hover{background:#ffffff0f;color:var(--text-bright)}.omni-fw-btn.active{background:#00ff8814;border-color:#0f86;color:var(--color-primary)}.omni-codegen-locator-selector{display:flex;align-items:center;gap:8px}.omni-codegen-label{font-size:10px;font-weight:700;text-transform:uppercase;color:var(--text-muted);white-space:nowrap;letter-spacing:.05em}.omni-fw-select{flex:1;padding:6px 8px;background:#0000004d;border:1px solid var(--border-visible);border-radius:6px;color:var(--text-bright);font-size:11px;outline:none;cursor:pointer}.omni-fw-select:focus{border-color:var(--color-primary)}.omni-codegen-output{display:flex;flex-direction:column;border-radius:8px;border:1px solid var(--border-visible);overflow:hidden}.omni-codegen-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;background:#00000080;border-bottom:1px solid var(--border-visible)}.omni-codegen-lang{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--color-primary);font-family:JetBrains Mono,monospace}.omni-codegen-pre{margin:0;padding:14px;background:var(--bg-glass);color:#e2e8f0;font-family:Fira Code,JetBrains Mono,monospace;font-size:11px;line-height:1.6;overflow-x:auto;white-space:pre}.omni-codegen-pre code{font-family:inherit;font-size:inherit;color:inherit}
|