Spaces:
No application file
No application file
Update browser_automation_ui.html
Browse files- browser_automation_ui.html +39 -68
browser_automation_ui.html
CHANGED
|
@@ -1,5 +1,7 @@
|
|
| 1 |
<!-- ========================= Browser Automation UI =========================
|
| 2 |
-
|
|
|
|
|
|
|
| 3 |
============================================================================ -->
|
| 4 |
<!DOCTYPE html>
|
| 5 |
<html lang="en">
|
|
@@ -16,13 +18,14 @@
|
|
| 16 |
/* โโโโโโโโโ Side panel */
|
| 17 |
.side-panel{position:fixed;left:0;top:0;width:var(--panel-w);height:100%;background:var(--bg);box-shadow:2px 0 6px rgba(0,0,0,.12);transition:transform .3s ease;z-index:900;overflow-y:auto}
|
| 18 |
.side-panel.closed{transform:translateX(-100%)}
|
| 19 |
-
.panel-toggle{position:absolute;right:-24px;top:12px;width:24px;height:24px;border:none;border-radius:4px;background:var(--accent);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px
|
| 20 |
.panel-content{padding:14px 16px 40px 16px}
|
| 21 |
h3{font-size:16px;margin-bottom:6px;color:var(--dark)}
|
| 22 |
.btn{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border:none;border-radius:6px;font-size:13px;cursor:pointer}
|
| 23 |
.btn-primary{background:var(--accent);color:#fff}
|
| 24 |
.btn-secondary{background:#e2e8f0;color:#334155}
|
| 25 |
.btn-danger{background:#ef4444;color:#fff}
|
|
|
|
| 26 |
.form-group{display:flex;flex-direction:column;margin-bottom:8px}
|
| 27 |
.form-group input,.form-group select{padding:6px 8px;border:1px solid #cbd5e1;border-radius:4px;font-size:13px}
|
| 28 |
/* โโโโโโโโโ Main screenshot area */
|
|
@@ -32,6 +35,17 @@
|
|
| 32 |
/* โโโโโโโโโ Log overlay */
|
| 33 |
#logOverlay{position:fixed;left:0;bottom:0;width:100%;height:20vh;background:rgba(30,41,59,0.7);color:#f1f5f9;font-size:12px;overflow-y:auto;padding:6px 10px;z-index:950;backdrop-filter:blur(3px)}
|
| 34 |
#logOverlay pre{margin:0;white-space:pre-wrap;word-break:break-word}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
</style>
|
| 36 |
</head>
|
| 37 |
<body>
|
|
@@ -45,7 +59,10 @@
|
|
| 45 |
<div class="form-group"><button class="btn btn-primary" onclick="launchBrowser()"><i class="lucide lucide-rocket"></i>Launch</button></div>
|
| 46 |
<div class="form-group"><input id="navUrl" placeholder="https://example.com"/></div>
|
| 47 |
<div class="form-group"><button class="btn btn-secondary" onclick="navigate()"><i class="lucide lucide-globe"></i>Navigate</button></div>
|
| 48 |
-
<div class="form-group"
|
|
|
|
|
|
|
|
|
|
| 49 |
<div class="form-group"><button class="btn btn-danger" onclick="closeAllSessions()"><i class="lucide lucide-trash-2"></i>Closeย All</button></div>
|
| 50 |
</section>
|
| 51 |
<hr style="margin:12px 0;border:none;border-top:1px solid #e2e8f0"/>
|
|
@@ -60,13 +77,14 @@
|
|
| 60 |
</select></div>
|
| 61 |
<div class="form-group" id="typeTextGroup" style="display:none"><input id="typeText" placeholder="text to type"/></div>
|
| 62 |
<button class="btn btn-primary" onclick="elementAction()"><i class="lucide lucide-mouse-pointer-click"></i>Run</button>
|
|
|
|
| 63 |
</section>
|
| 64 |
<hr style="margin:12px 0;border:none;border-top:1px solid #e2e8f0"/>
|
| 65 |
<!-- Session Manager -->
|
| 66 |
<section>
|
| 67 |
<h3>Sessions</h3>
|
| 68 |
<button class="btn btn-secondary btn-sm" style="margin-bottom:6px" onclick="refreshSessions()"><i class="lucide lucide-refresh-ccw"></i>Refresh</button>
|
| 69 |
-
<ul id="sessionList"
|
| 70 |
</section>
|
| 71 |
</div>
|
| 72 |
</aside>
|
|
@@ -79,6 +97,13 @@
|
|
| 79 |
<!-- โญโโโโโโโโโโโโโโโโโโโโโโโโ Log Overlay โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ -->
|
| 80 |
<div id="logOverlay"><pre id="logText"></pre></div>
|
| 81 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
<!-- โญโโโโโโโโโโโโโโโโโโโโโโโโ Scripts โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ -->
|
| 83 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/lucide/0.263.1/lucide.min.js"></script>
|
| 84 |
<script>
|
|
@@ -88,76 +113,22 @@
|
|
| 88 |
function log(msg){const pre=document.getElementById('logText');pre.textContent+=`\n${new Date().toLocaleTimeString()} ${msg}`;pre.parentElement.scrollTop=pre.parentElement.scrollHeight}
|
| 89 |
|
| 90 |
/* โโโโโโโโโโ Global state โโโโโโโโโโ */
|
| 91 |
-
let currentSessionId=null;
|
| 92 |
|
| 93 |
/* โโโโโโโโโโ Side panel toggle โโโโโโโโโโ */
|
| 94 |
const panel=document.getElementById('sidePanel');
|
| 95 |
const mainArea=document.getElementById('mainArea');
|
| 96 |
document.getElementById('togglePanel').onclick=()=>{
|
| 97 |
-
panel.classList.toggle('closed');
|
| 98 |
-
|
| 99 |
-
document.getElementById('togglePanel').textContent=panel.classList.contains('closed')?'โฏ':'โฎ';
|
| 100 |
-
};
|
| 101 |
|
| 102 |
/* โโโโโโโโโโ Browser controls โโโโโโโโโโ */
|
| 103 |
-
async function launchBrowser(){
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
}
|
| 107 |
-
async function
|
| 108 |
-
if(!currentSessionId)return alert('No session');
|
| 109 |
-
const url=document.getElementById('navUrl').value.trim();
|
| 110 |
-
if(!url)return;
|
| 111 |
-
await api('/api/browser/navigate',{session_id:currentSessionId,url});
|
| 112 |
-
log(`Navigated to ${url}`);
|
| 113 |
-
captureScreenshot();
|
| 114 |
-
}
|
| 115 |
-
async function captureScreenshot(){
|
| 116 |
-
if(!currentSessionId)return;
|
| 117 |
-
const res=await api('/api/browser/screenshot',{session_id:currentSessionId,full_page:false});
|
| 118 |
-
if(res.screenshot){document.getElementById('screenshot').src=`data:image/png;base64,${res.screenshot}`;log('Screenshot updated');}
|
| 119 |
-
}
|
| 120 |
-
async function closeAllSessions(){
|
| 121 |
-
const items=[...document.querySelectorAll('.session-item')];
|
| 122 |
-
if (items.length === 0) return;
|
| 123 |
-
if (!confirm(`Close ALL ${items.length} sessions?`)) return;
|
| 124 |
-
for(const li of items){await api(`/api/browser/close/${li.dataset.id}`,{});}
|
| 125 |
-
currentSessionId=null;refreshSessions();log('Closed all sessions');document.getElementById('screenshot').src='';
|
| 126 |
-
}
|
| 127 |
|
| 128 |
/* โโโโโโโโโโ Element interaction โโโโโโโโโโ */
|
| 129 |
-
document.getElementById('action').addEventListener('change',e=>{
|
| 130 |
-
|
| 131 |
-
});
|
| 132 |
-
async function elementAction(){
|
| 133 |
-
if(!currentSessionId)return;
|
| 134 |
-
const selector=document.getElementById('selector').value.trim();
|
| 135 |
-
if(!selector)return;
|
| 136 |
-
const action=document.getElementById('action').value;
|
| 137 |
-
const value=action==='type'?document.getElementById('typeText').value:'';
|
| 138 |
-
const res=await api('/api/elements/action',{session_id:currentSessionId,selector,action,value});
|
| 139 |
-
log(`Action ${action} on ${selector} โ ${JSON.stringify(res)}`);
|
| 140 |
-
if(action==='textContent'&&res.text)alert(`Text: ${res.text}`);
|
| 141 |
-
captureScreenshot();
|
| 142 |
-
}
|
| 143 |
-
|
| 144 |
-
/* โโโโโโโโโโ Session manager โโโโโโโโโโ */
|
| 145 |
-
async function refreshSessions(){
|
| 146 |
-
const listEl=document.getElementById('sessionList');
|
| 147 |
-
listEl.innerHTML='';
|
| 148 |
-
const {sessions=[]}=await apiGet('/api/sessions');
|
| 149 |
-
sessions.forEach(s=>{
|
| 150 |
-
const li=document.createElement('li');li.className='session-item';li.textContent=s.session_id;li.dataset.id=s.session_id;
|
| 151 |
-
li.style.cursor='pointer';li.style.padding='4px 6px';li.style.borderBottom='1px solid #e2e8f0';
|
| 152 |
-
if(s.session_id===currentSessionId){li.style.background='#dbeafe';}
|
| 153 |
-
li.onclick=()=>{currentSessionId=s.session_id;refreshSessions();captureScreenshot();log(`Switched to session ${s.session_id}`);} ;
|
| 154 |
-
listEl.appendChild(li);
|
| 155 |
-
});
|
| 156 |
-
}
|
| 157 |
-
|
| 158 |
-
// initial icon replacement
|
| 159 |
-
lucide.createIcons();
|
| 160 |
-
refreshSessions();
|
| 161 |
-
</script>
|
| 162 |
-
</body>
|
| 163 |
-
</html>
|
|
|
|
| 1 |
<!-- ========================= Browser Automation UI =========================
|
| 2 |
+
Fullโscreen screenshot | overlay logs | collapsible side panel
|
| 3 |
+
Added: download screenshot, perโsession close, confirm on mass close,
|
| 4 |
+
Inspect overlay listing selectors with hover details
|
| 5 |
============================================================================ -->
|
| 6 |
<!DOCTYPE html>
|
| 7 |
<html lang="en">
|
|
|
|
| 18 |
/* โโโโโโโโโ Side panel */
|
| 19 |
.side-panel{position:fixed;left:0;top:0;width:var(--panel-w);height:100%;background:var(--bg);box-shadow:2px 0 6px rgba(0,0,0,.12);transition:transform .3s ease;z-index:900;overflow-y:auto}
|
| 20 |
.side-panel.closed{transform:translateX(-100%)}
|
| 21 |
+
.panel-toggle{position:absolute;right:-24px;top:12px;width:24px;height:24px;border:none;border-radius:4px;background:var(--accent);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px}
|
| 22 |
.panel-content{padding:14px 16px 40px 16px}
|
| 23 |
h3{font-size:16px;margin-bottom:6px;color:var(--dark)}
|
| 24 |
.btn{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border:none;border-radius:6px;font-size:13px;cursor:pointer}
|
| 25 |
.btn-primary{background:var(--accent);color:#fff}
|
| 26 |
.btn-secondary{background:#e2e8f0;color:#334155}
|
| 27 |
.btn-danger{background:#ef4444;color:#fff}
|
| 28 |
+
.btn-sm{padding:4px 8px;font-size:11px}
|
| 29 |
.form-group{display:flex;flex-direction:column;margin-bottom:8px}
|
| 30 |
.form-group input,.form-group select{padding:6px 8px;border:1px solid #cbd5e1;border-radius:4px;font-size:13px}
|
| 31 |
/* โโโโโโโโโ Main screenshot area */
|
|
|
|
| 35 |
/* โโโโโโโโโ Log overlay */
|
| 36 |
#logOverlay{position:fixed;left:0;bottom:0;width:100%;height:20vh;background:rgba(30,41,59,0.7);color:#f1f5f9;font-size:12px;overflow-y:auto;padding:6px 10px;z-index:950;backdrop-filter:blur(3px)}
|
| 37 |
#logOverlay pre{margin:0;white-space:pre-wrap;word-break:break-word}
|
| 38 |
+
/* โโโโโโโโโ Session list */
|
| 39 |
+
.session-item{display:flex;align-items:center;justify-content:space-between;padding:4px 6px;border-bottom:1px solid #e2e8f0;font-family:"Source Code Pro",monospace;font-size:12px}
|
| 40 |
+
.session-id{cursor:pointer;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
| 41 |
+
.session-item.active{background:#dbeafe}
|
| 42 |
+
.session-close{background:none;border:none;color:#ef4444;cursor:pointer;font-size:14px;width:18px;height:18px;display:flex;align-items:center;justify-content:center}
|
| 43 |
+
/* โโโโโโโโโ Inspect overlay */
|
| 44 |
+
#inspectOverlay{position:fixed;right:0;top:0;width:300px;height:100%;background:rgba(15,23,42,0.9);color:#f8fafc;z-index:940;transform:translateX(100%);transition:transform .3s ease;overflow-y:auto;padding:10px;font-size:12px}
|
| 45 |
+
#inspectOverlay.open{transform:translateX(0)}
|
| 46 |
+
#inspectList li{padding:4px 6px;border-bottom:1px solid rgba(255,255,255,.08);cursor:pointer}
|
| 47 |
+
#inspectList li:hover{background:rgba(255,255,255,.08)}
|
| 48 |
+
#inspectDetail{margin-top:6px;font-size:11px;color:#cbd5e1;white-space:pre-wrap}
|
| 49 |
</style>
|
| 50 |
</head>
|
| 51 |
<body>
|
|
|
|
| 59 |
<div class="form-group"><button class="btn btn-primary" onclick="launchBrowser()"><i class="lucide lucide-rocket"></i>Launch</button></div>
|
| 60 |
<div class="form-group"><input id="navUrl" placeholder="https://example.com"/></div>
|
| 61 |
<div class="form-group"><button class="btn btn-secondary" onclick="navigate()"><i class="lucide lucide-globe"></i>Navigate</button></div>
|
| 62 |
+
<div class="form-group" style="display:flex;gap:6px">
|
| 63 |
+
<button class="btn btn-secondary" onclick="captureScreenshot()"><i class="lucide lucide-camera"></i>Capture</button>
|
| 64 |
+
<button class="btn btn-secondary" onclick="downloadCurrentScreenshot()"><i class="lucide lucide-download"></i>Download</button>
|
| 65 |
+
</div>
|
| 66 |
<div class="form-group"><button class="btn btn-danger" onclick="closeAllSessions()"><i class="lucide lucide-trash-2"></i>Closeย All</button></div>
|
| 67 |
</section>
|
| 68 |
<hr style="margin:12px 0;border:none;border-top:1px solid #e2e8f0"/>
|
|
|
|
| 77 |
</select></div>
|
| 78 |
<div class="form-group" id="typeTextGroup" style="display:none"><input id="typeText" placeholder="text to type"/></div>
|
| 79 |
<button class="btn btn-primary" onclick="elementAction()"><i class="lucide lucide-mouse-pointer-click"></i>Run</button>
|
| 80 |
+
<button class="btn btn-secondary btn-sm" style="margin-left:6px" onclick="inspectPage()"><i class="lucide lucide-list"></i>Inspect</button>
|
| 81 |
</section>
|
| 82 |
<hr style="margin:12px 0;border:none;border-top:1px solid #e2e8f0"/>
|
| 83 |
<!-- Session Manager -->
|
| 84 |
<section>
|
| 85 |
<h3>Sessions</h3>
|
| 86 |
<button class="btn btn-secondary btn-sm" style="margin-bottom:6px" onclick="refreshSessions()"><i class="lucide lucide-refresh-ccw"></i>Refresh</button>
|
| 87 |
+
<ul id="sessionList"></ul>
|
| 88 |
</section>
|
| 89 |
</div>
|
| 90 |
</aside>
|
|
|
|
| 97 |
<!-- โญโโโโโโโโโโโโโโโโโโโโโโโโ Log Overlay โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ -->
|
| 98 |
<div id="logOverlay"><pre id="logText"></pre></div>
|
| 99 |
|
| 100 |
+
<!-- โญโโโโโโโโโโโโโโโโโโโโโโโโ Inspect Overlay โโโโโโโโโโโโโโโโโโโโโโโโโโฎ -->
|
| 101 |
+
<aside id="inspectOverlay">
|
| 102 |
+
<h3 style="color:#38bdf8;margin-bottom:8px">Selectors</h3>
|
| 103 |
+
<ul id="inspectList"></ul>
|
| 104 |
+
<div id="inspectDetail"></div>
|
| 105 |
+
</aside>
|
| 106 |
+
|
| 107 |
<!-- โญโโโโโโโโโโโโโโโโโโโโโโโโ Scripts โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ -->
|
| 108 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/lucide/0.263.1/lucide.min.js"></script>
|
| 109 |
<script>
|
|
|
|
| 113 |
function log(msg){const pre=document.getElementById('logText');pre.textContent+=`\n${new Date().toLocaleTimeString()} ${msg}`;pre.parentElement.scrollTop=pre.parentElement.scrollHeight}
|
| 114 |
|
| 115 |
/* โโโโโโโโโโ Global state โโโโโโโโโโ */
|
| 116 |
+
let currentSessionId=null;let lastScreenshotData=null;
|
| 117 |
|
| 118 |
/* โโโโโโโโโโ Side panel toggle โโโโโโโโโโ */
|
| 119 |
const panel=document.getElementById('sidePanel');
|
| 120 |
const mainArea=document.getElementById('mainArea');
|
| 121 |
document.getElementById('togglePanel').onclick=()=>{
|
| 122 |
+
panel.classList.toggle('closed');mainArea.classList.toggle('with-panel');
|
| 123 |
+
document.getElementById('togglePanel').textContent=panel.classList.contains('closed')?'โฏ':'โฎ';};
|
|
|
|
|
|
|
| 124 |
|
| 125 |
/* โโโโโโโโโโ Browser controls โโโโโโโโโโ */
|
| 126 |
+
async function launchBrowser(){const res=await api('/api/browser/launch',{});if(res.session_id){currentSessionId=res.session_id;log(`Launched session ${res.session_id}`);refreshSessions();captureScreenshot();}}
|
| 127 |
+
async function navigate(){if(!currentSessionId)return alert('No session');const url=document.getElementById('navUrl').value.trim();if(!url)return;await api('/api/browser/navigate',{session_id:currentSessionId,url});log(`Navigated to ${url}`);captureScreenshot();}
|
| 128 |
+
async function captureScreenshot(){if(!currentSessionId)return;const res=await api('/api/browser/screenshot',{session_id:currentSessionId,full_page:false});if(res.screenshot){lastScreenshotData=res.screenshot;document.getElementById('screenshot').src=`data:image/png;base64,${res.screenshot}`;log('Screenshot updated');}}
|
| 129 |
+
function downloadCurrentScreenshot(){if(!lastScreenshotData)return alert('No screenshot');const a=document.createElement('a');a.href=`data:image/png;base64,${lastScreenshotData}`;a.download=`screenshot_${Date.now()}.png`;a.click();}
|
| 130 |
+
async function closeAllSessions(){const items=[...document.querySelectorAll('.session-item')];if(items.length===0)return alert('No sessions');if(!confirm(`Close ALL ${items.length} sessions?`))return;for(const li of items){await api(`/api/browser/close/${li.dataset.id}`,{});}currentSessionId=null;refreshSessions();log('Closed all sessions');document.getElementById('screenshot').src='';lastScreenshotData=null;}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
|
| 132 |
/* โโโโโโโโโโ Element interaction โโโโโโโโโโ */
|
| 133 |
+
document.getElementById('action').addEventListener('change',e=>{document.getElementById('typeTextGroup').style.display=e.target.value==='type'?'block':'none';});
|
| 134 |
+
async function elementAction(){if(!currentSessionId)return;const selector=document.getElementById('selector').
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|