Mukrii commited on
Commit
6df7019
·
verified ·
1 Parent(s): 3f37b5c

---Product Requirements Document (PRD): Autonomous Web Interaction Agent (AWIA)Dokumen DetailNama Proyek Autonomous Web Interaction Agent (AWIA)Versi 1.0 (Draft)Status Draft untuk PersetujuanPemilik P

Browse files
Files changed (4) hide show
  1. README.md +9 -6
  2. components/styles.css +109 -0
  3. index.html +848 -19
  4. script.js +332 -0
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Awia Mission Dashboard Ojsh6
3
- emoji: 💻
4
- colorFrom: pink
5
- colorTo: red
6
  sdk: static
7
- pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
1
  ---
2
+ title: AWIA Mission Dashboard 🤖
3
+ colorFrom: yellow
4
+ colorTo: gray
 
5
  sdk: static
6
+ emoji: 🚀
7
+ tags:
8
+ - deepsite-v4
9
  ---
10
 
11
+ # AWIA Mission Dashboard 🤖
12
+
13
+ This project has been created with [DeepSite](https://deepsite.hf.co) AI Vibe Coding.
components/styles.css ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ AWIA Dashboard - Additional Styles
3
+ This file contains extra customizations that complement Tailwind CSS
4
+ */
5
+
6
+ /* Scrollbar Styling */
7
+ ::-webkit-scrollbar {
8
+ width: 8px;
9
+ height: 8px;
10
+ }
11
+
12
+ ::-webkit-scrollbar-track {
13
+ background: #1e293b;
14
+ border-radius: 4px;
15
+ }
16
+
17
+ ::-webkit-scrollbar-thumb {
18
+ background: #475569;
19
+ border-radius: 4px;
20
+ }
21
+
22
+ ::-webkit-scrollbar-thumb:hover {
23
+ background: #64748b;
24
+ }
25
+
26
+ /* Loading Animation */
27
+ @keyframes spin {
28
+ 0% { transform: rotate(0deg); }
29
+ 100% { transform: rotate(360deg); }
30
+ }
31
+
32
+ .loading-spinner {
33
+ border: 3px solid rgba(255, 255, 255, 0.3);
34
+ border-radius: 50%;
35
+ border-top: 3px solid #3b82f6;
36
+ width: 24px;
37
+ height: 24px;
38
+ animation: spin 1s linear infinite;
39
+ }
40
+
41
+ /* Card Hover Effects */
42
+ .card-hover:hover {
43
+ transform: scale(1.02);
44
+ transition: transform 0.2s ease;
45
+ }
46
+
47
+ /* Responsive Utilities */
48
+ @media (max-width: 768px) {
49
+ .mobile-stack {
50
+ flex-direction: column;
51
+ }
52
+
53
+ .mobile-text-center {
54
+ text-align: center;
55
+ }
56
+ }
57
+
58
+ /* Gradient Text */
59
+ .gradient-text {
60
+ background: linear-gradient(90deg, #3b82f6, #8b5cf6);
61
+ -webkit-background-clip: text;
62
+ -webkit-text-fill-color: transparent;
63
+ background-clip: text;
64
+ }
65
+
66
+ /* Custom Checkbox */
67
+ .custom-checkbox {
68
+ width: 16px;
69
+ height: 16px;
70
+ border: 2px solid #475569;
71
+ border-radius: 4px;
72
+ position: relative;
73
+ cursor: pointer;
74
+ }
75
+
76
+ .custom-checkbox:checked {
77
+ background-color: #3b82f6;
78
+ border-color: #3b82f6;
79
+ }
80
+
81
+ .custom-checkbox:checked::after {
82
+ content: '✓';
83
+ position: absolute;
84
+ color: white;
85
+ top: -2px;
86
+ left: 2px;
87
+ font-size: 12px;
88
+ }
89
+
90
+ /* Custom Select */
91
+ .custom-select {
92
+ appearance: none;
93
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%2394a3b8' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
94
+ background-repeat: no-repeat;
95
+ background-position: right 0.5rem center;
96
+ background-size: 1rem;
97
+ }
98
+
99
+ /* Focus Utilities */
100
+ .focus-ring:focus {
101
+ outline: none;
102
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.5);
103
+ }
104
+
105
+ /* Placeholder Styling */
106
+ ::placeholder {
107
+ color: #64748b;
108
+ opacity: 0.8;
109
+ }
index.html CHANGED
@@ -1,19 +1,848 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>AWIA Mission Dashboard 🤖</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://unpkg.com/lucide@latest"></script>
9
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap">
10
+ <style>
11
+ body {
12
+ font-family: 'Inter', sans-serif;
13
+ background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
14
+ min-height: 100vh;
15
+ }
16
+
17
+ .card {
18
+ background: rgba(30, 41, 59, 0.7);
19
+ backdrop-filter: blur(10px);
20
+ border: 1px solid rgba(255, 255, 255, 0.1);
21
+ border-radius: 12px;
22
+ }
23
+
24
+ .mission-card {
25
+ transition: all 0.3s ease;
26
+ }
27
+
28
+ .mission-card:hover {
29
+ transform: translateY(-2px);
30
+ box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
31
+ }
32
+
33
+ .btn-primary {
34
+ background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
35
+ }
36
+
37
+ .btn-success {
38
+ background: linear-gradient(135deg, #10b981 0%, #059669 100%);
39
+ }
40
+
41
+ .btn-danger {
42
+ background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
43
+ }
44
+
45
+ .status-pending {
46
+ background: #fbbf24;
47
+ color: #fff;
48
+ }
49
+
50
+ .status-running {
51
+ background: #3b82f6;
52
+ color: #fff;
53
+ }
54
+
55
+ .status-success {
56
+ background: #10b981;
57
+ color: #fff;
58
+ }
59
+
60
+ .status-failed {
61
+ background: #ef4444;
62
+ color: #fff;
63
+ }
64
+
65
+ .status-timeout {
66
+ background: #8b5cf6;
67
+ color: #fff;
68
+ }
69
+
70
+ .progress-bar {
71
+ transition: width 0.5s ease;
72
+ }
73
+
74
+ .code-block {
75
+ background: #1e293b;
76
+ color: #e2e8f0;
77
+ font-family: 'Courier New', monospace;
78
+ }
79
+
80
+ .log-entry {
81
+ animation: fadeIn 0.3s ease;
82
+ }
83
+
84
+ @keyframes fadeIn {
85
+ from { opacity: 0; transform: translateY(5px); }
86
+ to { opacity: 1; transform: translateY(0); }
87
+ }
88
+ </style>
89
+ </head>
90
+ <body class="text-white">
91
+ <!-- Header -->
92
+ <header class="sticky top-0 z-50 shadow-lg">
93
+ <div class="container mx-auto px-4 py-4">
94
+ <div class="flex items-center justify-between">
95
+ <div class="flex items-center space-x-3">
96
+ <i data-lucide="cpu" class="text-3xl text-blue-400"></i>
97
+ <div>
98
+ <h1 class="text-2xl font-bold">AWIA Dashboard</h1>
99
+ <p class="text-sm text-gray-300">Autonomous Web Interaction Agent</p>
100
+ </div>
101
+ </div>
102
+
103
+ <div class="flex items-center space-x-4">
104
+ <div class="hidden md:flex items-center space-x-2 bg-blue-900/30 px-3 py-1 rounded-full">
105
+ <i data-lucide="server" class="text-blue-400"></i>
106
+ <span class="text-sm text-blue-200">System Status: <span class="text-green-400 font-medium">Active</span></span>
107
+ </div>
108
+
109
+ <button id="createMissionBtn" class="flex items-center space-x-2 bg-gradient-to-r from-blue-500 to-purple-500 hover:from-blue-600 hover:to-purple-600 text-white px-4 py-2 rounded-lg transition-all">
110
+ <i data-lucide="plus-circle"></i>
111
+ <span>New Mission</span>
112
+ </button>
113
+ </div>
114
+ </div>
115
+ </div>
116
+ </header>
117
+
118
+ <!-- Main Content -->
119
+ <main class="container mx-auto px-4 py-8">
120
+ <!-- Dashboard Stats -->
121
+ <div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
122
+ <div class="card p-6">
123
+ <div class="flex items-start justify-between">
124
+ <div>
125
+ <p class="text-gray-400 text-sm">Total Missions</p>
126
+ <p class="text-3xl font-bold mt-2" id="totalMissions">0</p>
127
+ </div>
128
+ <i data-lucide="target" class="text-blue-400 text-2xl"></i>
129
+ </div>
130
+ <div class="mt-4 text-xs text-gray-500">
131
+ All missions ever created
132
+ </div>
133
+ </div>
134
+
135
+ <div class="card p-6">
136
+ <div class="flex items-start justify-between">
137
+ <div>
138
+ <p class="text-gray-400 text-sm">Success Rate</p>
139
+ <p class="text-3xl font-bold mt-2" id="successRate">0%</p>
140
+ </div>
141
+ <i data-lucide="circle-check" class="text-green-400 text-2xl"></i>
142
+ </div>
143
+ <div class="mt-4 text-xs text-gray-500">
144
+ Successful missions / Total missions
145
+ </div>
146
+ </div>
147
+
148
+ <div class="card p-6">
149
+ <div class="flex items-start justify-between">
150
+ <div>
151
+ <p class="text-gray-400 text-sm">Active Agents</p>
152
+ <p class="text-3xl font-bold mt-2" id="activeAgents">0</p>
153
+ </div>
154
+ <i data-lucide="bot" class="text-purple-400 text-2xl"></i>
155
+ </div>
156
+ <div class="mt-4 text-xs text-gray-500">
157
+ Currently running agents
158
+ </div>
159
+ </div>
160
+
161
+ <div class="card p-6">
162
+ <div class="flex items-start justify-between">
163
+ <div>
164
+ <p class="text-gray-400 text-sm">Avg. Completion</p>
165
+ <p class="text-3xl font-bold mt-2" id="avgCompletion">0s</p>
166
+ </div>
167
+ <i data-lucide="clock" class="text-yellow-400 text-2xl"></i>
168
+ </div>
169
+ <div class="mt-4 text-xs text-gray-500">
170
+ Average mission duration
171
+ </div>
172
+ </div>
173
+ </div>
174
+
175
+ <!-- Recent Missions -->
176
+ <div class="card p-6 mb-8">
177
+ <div class="flex items-center justify-between mb-6">
178
+ <h2 class="text-xl font-semibold flex items-center">
179
+ <i data-lucide="list" class="mr-2 text-blue-400"></i>
180
+ Recent Missions
181
+ </h2>
182
+ <div class="flex space-x-2">
183
+ <input type="text" placeholder="Search missions..." class="bg-gray-800 border border-gray-700 text-white px-3 py-2 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
184
+ </div>
185
+ </div>
186
+
187
+ <div class="space-y-4" id="missionsContainer">
188
+ <!-- Missions will be rendered here -->
189
+ </div>
190
+ </div>
191
+
192
+ <!-- AI Tools & Features -->
193
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
194
+ <div class="card p-6">
195
+ <div class="flex items-center mb-4">
196
+ <div class="p-2 bg-blue-900/30 rounded-lg mr-3">
197
+ <i data-lucide="brain" class="text-blue-400"></i>
198
+ </div>
199
+ <h3 class="font-medium">AI Reasoning</h3>
200
+ </div>
201
+ <p class="text-sm text-gray-300">
202
+ Advanced LLM-powered decision making for complex web interactions and element detection.
203
+ </p>
204
+ <div class="mt-4 flex items-center space-x-2">
205
+ <div class="h-1.5 w-full bg-gray-700 rounded-full overflow-hidden">
206
+ <div class="h-full bg-blue-500 rounded-full" style="width: 85%"></div>
207
+ </div>
208
+ <span class="text-xs text-gray-400">85%</span>
209
+ </div>
210
+ </div>
211
+
212
+ <div class="card p-6">
213
+ <div class="flex items-center mb-4">
214
+ <div class="p-2 bg-purple-900/30 rounded-lg mr-3">
215
+ <i data-lucide="zap" class="text-purple-400"></i>
216
+ </div>
217
+ <h3 class="font-medium">Smart Selectors</h3>
218
+ </div>
219
+ <p class="text-sm text-gray-300">
220
+ Multiple selector strategies (CSS, XPath, text-based) for resilient element targeting.
221
+ </p>
222
+ <div class="mt-4 flex items-center space-x-2">
223
+ <div class="h-1.5 w-full bg-gray-700 rounded-full overflow-hidden">
224
+ <div class="h-full bg-purple-500 rounded-full" style="width: 90%"></div>
225
+ </div>
226
+ <span class="text-xs text-gray-400">90%</span>
227
+ </div>
228
+ </div>
229
+
230
+ <div class="card p-6">
231
+ <div class="flex items-center mb-4">
232
+ <div class="p-2 bg-green-900/30 rounded-lg mr-3">
233
+ <i data-lucide="image" class="text-green-400"></i>
234
+ </div>
235
+ <h3 class="font-medium">Visual Verification</h3>
236
+ </div>
237
+ <p class="text-sm text-gray-300">
238
+ Screenshot capture and visual comparison for testing visual consistency and correctness.
239
+ </p>
240
+ <div class="mt-4 flex items-center space-x-2">
241
+ <div class="h-1.5 w-full bg-gray-700 rounded-full overflow-hidden">
242
+ <div class="h-full bg-green-500 rounded-full" style="width: 78%"></div>
243
+ </div>
244
+ <span class="text-xs text-gray-400">78%</span>
245
+ </div>
246
+ </div>
247
+ </div>
248
+ </main>
249
+
250
+ <!-- Create Mission Modal -->
251
+ <div id="missionModal" class="fixed inset-0 bg-black/60 hidden overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true">
252
+ <div class="flex items-center justify-center min-h-screen px-4 py-12">
253
+ <div class="card w-full max-w-2xl">
254
+ <div class="flex items-center justify-between p-6 border-b border-gray-700">
255
+ <h3 class="text-xl font-semibold" id="modal-title">New Mission</h3>
256
+ <button id="closeModal" class="text-gray-400 hover:text-white">
257
+ <i data-lucide="x" class="w-6 h-6"></i>
258
+ </button>
259
+ </div>
260
+
261
+ <div class="p-6">
262
+ <div class="space-y-6">
263
+ <!-- Target URL -->
264
+ <div>
265
+ <label class="block text-sm font-medium text-gray-300 mb-2">Target URL</label>
266
+ <input type="url" id="missionUrl" placeholder="https://example.com" class="w-full bg-gray-800 border border-gray-700 rounded-lg px-4 py-3 text-white focus:outline-none focus:ring-2 focus:ring-blue-500">
267
+ <p class="mt-2 text-xs text-gray-500">Enter the website URL you want to automate</p>
268
+ </div>
269
+
270
+ <!-- Workflow -->
271
+ <div>
272
+ <label class="block text-sm font-medium text-gray-300 mb-2">Workflow (JSON)</label>
273
+ <div class="relative">
274
+ <textarea id="missionWorkflow" rows="8" class="w-full code-block p-4 rounded-lg font-mono text-sm" spellcheck="false">
275
+ [
276
+ {
277
+ "action": "navigate_to",
278
+ "value": "https://example.com/products"
279
+ },
280
+ {
281
+ "action": "scroll_to_bottom",
282
+ "value": 3
283
+ },
284
+ {
285
+ "action": "click",
286
+ "selector": "#load-more-btn",
287
+ "strategy": "css"
288
+ },
289
+ {
290
+ "action": "extract",
291
+ "type": "screenshot"
292
+ }
293
+ ]</textarea>
294
+ <div class="absolute top-3 right-3">
295
+ <button id="workflowHelp" class="text-xs bg-blue-600/20 hover:bg-blue-600/30 text-blue-200 px-2 py-1 rounded">
296
+ Help
297
+ </button>
298
+ </div>
299
+ </div>
300
+ <p class="mt-2 text-xs text-gray-500">Define the automated actions in JSON format</p>
301
+ </div>
302
+
303
+ <!-- Max Duration -->
304
+ <div>
305
+ <label class="block text-sm font-medium text-gray-300 mb-2">Max Duration (seconds)</label>
306
+ <input type="number" id="missionDuration" value="300" min="10" max="3600" class="w-full bg-gray-800 border border-gray-700 rounded-lg px-4 py-3 text-white focus:outline-none focus:ring-2 focus:ring-blue-500">
307
+ <p class="mt-2 text-xs text-gray-500">Maximum time allowed for this mission</p>
308
+ </div>
309
+
310
+ <!-- Priority -->
311
+ <div>
312
+ <label class="block text-sm font-medium text-gray-300 mb-2">Priority</label>
313
+ <select id="missionPriority" class="w-full bg-gray-800 border border-gray-700 rounded-lg px-4 py-3 text-white focus:outline-none focus:ring-2 focus:ring-blue-500">
314
+ <option value="normal">Normal</option>
315
+ <option value="high">High</option>
316
+ <option value="critical">Critical</option>
317
+ </select>
318
+ </div>
319
+ </div>
320
+
321
+ <div class="flex justify-end space-x-3 mt-8">
322
+ <button id="cancelMission" class="px-5 py-3 bg-gray-700 hover:bg-gray-600 text-white rounded-lg transition-colors">
323
+ Cancel
324
+ </button>
325
+ <button id="createMission" class="btn-primary px-6 py-3 rounded-lg font-medium flex items-center space-x-2">
326
+ <i data-lucide="play-circle"></i>
327
+ <span>Start Mission</span>
328
+ </button>
329
+ </div>
330
+ </div>
331
+ </div>
332
+ </div>
333
+ </div>
334
+
335
+ <!-- Mission Details Modal -->
336
+ <div id="missionDetailsModal" class="fixed inset-0 bg-black/60 hidden overflow-y-auto" role="dialog" aria-modal="true">
337
+ <div class="flex items-center justify-center min-h-screen px-4 py-12">
338
+ <div class="card w-full max-w-4xl">
339
+ <div class="flex items-center justify-between p-6 border-b border-gray-700">
340
+ <h3 class="text-xl font-semibold" id="missionDetailsTitle">Mission Details</h3>
341
+ <button id="closeMissionDetails" class="text-gray-400 hover:text-white">
342
+ <i data-lucide="x" class="w-6 h-6"></i>
343
+ </button>
344
+ </div>
345
+
346
+ <div class="p-6">
347
+ <!-- Mission Info -->
348
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
349
+ <div class="bg-gray-800/50 p-4 rounded-lg">
350
+ <p class="text-gray-400 text-xs uppercase tracking-wider mb-1">Status</p>
351
+ <div id="missionStatus" class="font-medium">Pending</div>
352
+ </div>
353
+ <div class="bg-gray-800/50 p-4 rounded-lg">
354
+ <p class="text-gray-400 text-xs uppercase tracking-wider mb-1">Target URL</p>
355
+ <div id="missionUrlDisplay" class="font-medium text-blue-400 truncate" title="https://example.com">https://example.com</div>
356
+ </div>
357
+ <div class="bg-gray-800/50 p-4 rounded-lg">
358
+ <p class="text-gray-400 text-xs uppercase tracking-wider mb-1">Duration</p>
359
+ <div id="missionDurationDisplay" class="font-medium">0s</div>
360
+ </div>
361
+ </div>
362
+
363
+ <!-- Progress Bar -->
364
+ <div class="mb-6">
365
+ <div class="flex justify-between text-sm mb-2">
366
+ <span class="text-gray-400">Progress</span>
367
+ <span id="missionProgress">0%</span>
368
+ </div>
369
+ <div class="w-full bg-gray-700 rounded-full h-2.5">
370
+ <div id="missionProgressBar" class="progress-bar bg-blue-500 rounded-full" style="width: 0%"></div>
371
+ </div>
372
+ </div>
373
+
374
+ <!-- Logs -->
375
+ <div class="mb-6">
376
+ <h4 class="font-medium mb-3 flex items-center">
377
+ <i data-lucide="terminal" class="w-4 h-4 mr-2 text-gray-400"></i>
378
+ Mission Logs
379
+ </h4>
380
+ <div id="missionLogs" class="bg-gray-900 rounded-lg p-4 font-mono text-sm max-h-40 overflow-y-auto border border-gray-700">
381
+ <p class="text-gray-500">No logs yet...</p>
382
+ </div>
383
+ </div>
384
+
385
+ <!-- Screenshot -->
386
+ <div class="mb-6">
387
+ <h4 class="font-medium mb-3 flex items-center">
388
+ <i data-lucide="image" class="w-4 h-4 mr-2 text-gray-400"></i>
389
+ Screenshots
390
+ </h4>
391
+ <div id="missionScreenshots" class="grid grid-cols-1 md:grid-cols-3 gap-4">
392
+ <div class="aspect-video bg-gray-800 rounded-lg flex items-center justify-center border border-gray-700">
393
+ <p class="text-gray-500">No screenshots yet</p>
394
+ </div>
395
+ </div>
396
+ </div>
397
+
398
+ <!-- Actions -->
399
+ <div class="flex justify-end space-x-3">
400
+ <button id="reRunMission" class="btn-primary px-5 py-3 rounded-lg font-medium flex items-center space-x-2">
401
+ <i data-lucide="rotate-cw"></i>
402
+ <span>Re-run Mission</span>
403
+ </button>
404
+ </div>
405
+ </div>
406
+ </div>
407
+ </div>
408
+ </div>
409
+
410
+ <!-- Notification Toast -->
411
+ <div id="notificationToast" class="fixed bottom-4 right-4 z-50 max-w-md bg-gray-800 border border-gray-700 rounded-lg shadow-2xl p-4 transform translate-y-100 transition-transform duration-300">
412
+ <div class="flex items-start space-x-3">
413
+ <div id="toastIcon" class="mt-1">
414
+ <i data-lucide="info" class="text-blue-400"></i>
415
+ </div>
416
+ <div>
417
+ <h4 id="toastTitle" class="font-medium text-white">Notification</h4>
418
+ <p id="toastMessage" class="text-gray-300 text-sm mt-1">This is a notification message</p>
419
+ </div>
420
+ <button id="closeToast" class="text-gray-400 hover:text-white ml-auto">
421
+ <i data-lucide="x" class="w-4 h-4"></i>
422
+ </button>
423
+ </div>
424
+ </div>
425
+
426
+ <script>
427
+ // Initialize Lucide Icons
428
+ lucide.createIcons();
429
+
430
+ // Mock Data
431
+ let missions = [
432
+ {
433
+ id: 'mission-001',
434
+ url: 'https://example.com/products',
435
+ workflow: [
436
+ { action: 'navigate_to', value: 'https://example.com/products' },
437
+ { action: 'scroll_to_bottom', value: 3 },
438
+ { action: 'click', selector: '#load-more-btn', strategy: 'css' },
439
+ { action: 'extract', type: 'screenshot' }
440
+ ],
441
+ status: 'success',
442
+ duration: 45,
443
+ createdAt: new Date(Date.now() - 3600000),
444
+ logs: [
445
+ { timestamp: new Date(Date.now() - 3600000), action: 'create_session', details: 'Created new browser session' },
446
+ { timestamp: new Date(Date.now() - 3595000), action: 'navigate_to', details: 'Navigated to https://example.com/products' },
447
+ { timestamp: new Date(Date.now() - 3580000), action: 'think', details: 'Identified scroll target' },
448
+ { timestamp: new Date(Date.now() - 3570000), action: 'scroll_page', details: 'Scrolled to bottom (3 times)' },
449
+ { timestamp: new Date(Date.now() - 3550000), action: 'click', details: 'Clicked #load-more-btn successfully' },
450
+ { timestamp: new Date(Date.now() - 3540000), action: 'think', details: 'Detected new content loaded' },
451
+ { timestamp: new Date(Date.now() - 3500000), action: 'extract', details: 'Captured final screenshot' }
452
+ ],
453
+ screenshots: [
454
+ { id: 'ss-001', url: 'http://static.photos/1024x576/123' }
455
+ ]
456
+ },
457
+ {
458
+ id: 'mission-002',
459
+ url: 'https://techstore.com/inventory',
460
+ workflow: [
461
+ { action: 'navigate_to', value: 'https://techstore.com/inventory' },
462
+ { action: 'scroll_to_bottom', value: 5 },
463
+ { action: 'extract', type: 'data', target: '.product-list' }
464
+ ],
465
+ status: 'running',
466
+ duration: 120,
467
+ createdAt: new Date(Date.now() - 1800000),
468
+ logs: [
469
+ { timestamp: new Date(Date.now() - 1800000), action: 'create_session', details: 'Created new browser session' },
470
+ { timestamp: new Date(Date.now() - 1790000), action: 'navigate_to', details: 'Navigated to techstore.com/inventory' },
471
+ { timestamp: new Date(Date.now() - 1780000), action: 'think', details: 'Starting infinite scroll pattern' },
472
+ { timestamp: new Date(Date.now() - 1750000), action: 'scroll_page', details: 'Scrolled to bottom (2/5)' },
473
+ { timestamp: new Date(Date.now() - 1730000), action: 'think', details: 'Waiting for content to load...' }
474
+ ],
475
+ screenshots: []
476
+ },
477
+ {
478
+ id: 'mission-003',
479
+ url: 'https://dataanalytics.io/reports',
480
+ workflow: [
481
+ { action: 'navigate_to', value: 'https://dataanalytics.io/reports' },
482
+ { action: 'click', selector: '#export-btn', strategy: 'css' },
483
+ { action: 'extract', type: 'screenshot' }
484
+ ],
485
+ status: 'failed',
486
+ duration: 28,
487
+ createdAt: new Date(Date.now() - 7200000),
488
+ logs: [
489
+ { timestamp: new Date(Date.now() - 7200000), action: 'create_session', details: 'Created new browser session' },
490
+ { timestamp: new Date(Date.now() - 7195000), action: 'navigate_to', details: 'Navigated to dataanalytics.io/reports' },
491
+ { timestamp: new Date(Date.now() - 7180000), action: 'click', details: 'Failed to find #export-btn' },
492
+ { timestamp: new Date(Date.now() - 7175000), action: 'retry', details: 'Trying alternative selector: .export-action' },
493
+ { timestamp: new Date(Date.now() - 7160000), action: 'click', details: 'Alternative selector also failed' },
494
+ { timestamp: new Date(Date.now() - 7150000), action: 'fail', details: 'Mission failed: Element not found after 2 retries' }
495
+ ],
496
+ screenshots: []
497
+ },
498
+ {
499
+ id: 'mission-004',
500
+ url: 'https://marketingplatform.com/analytics',
501
+ workflow: [
502
+ { action: 'navigate_to', value: 'https://marketingplatform.com/analytics' },
503
+ { action: 'wait', value: 3 },
504
+ { action: 'click', selector: '[data-role="generate-report"]', strategy: 'data-role' },
505
+ { action: 'extract', type: 'screenshot' }
506
+ ],
507
+ status: 'timeout',
508
+ duration: 305,
509
+ createdAt: new Date(Date.now() - 10800000),
510
+ logs: [
511
+ { timestamp: new Date(Date.now() - 10800000), action: 'create_session', details: 'Created new browser session' },
512
+ { timestamp: new Date(Date.now() - 10790000), action: 'navigate_to', details: 'Navigated to marketingplatform.com/analytics' },
513
+ { timestamp: new Date(Date.now() - 10785000), action: 'wait', details: 'Waiting 3 seconds for page load' },
514
+ { timestamp: new Date(Date.now() - 10770000), action: 'think', details: 'Looking for generate-report button' },
515
+ { timestamp: new Date(Date.now() - 10750000), action: 'click', details: 'Attempting to click button' },
516
+ { timestamp: new Date(Date.now() - 10650000), action: 'timeout', details: 'Action timeout exceeded (max 300s)' }
517
+ ],
518
+ screenshots: []
519
+ }
520
+ ];
521
+
522
+ // DOM Elements
523
+ const missionsContainer = document.getElementById('missionsContainer');
524
+ const modal = document.getElementById('missionModal');
525
+ const missionDetailsModal = document.getElementById('missionDetailsModal');
526
+ const createMissionBtn = document.getElementById('createMissionBtn');
527
+ const closeModal = document.getElementById('closeModal');
528
+ const createMission = document.getElementById('createMission');
529
+ const cancelMission = document.getElementById('cancelMission');
530
+ const closeMissionDetails = document.getElementById('closeMissionDetails');
531
+ const reRunMission = document.getElementById('reRunMission');
532
+ const notificationToast = document.getElementById('notificationToast');
533
+ const workflowHelp = document.getElementById('workflowHelp');
534
+
535
+ // Status Colors
536
+ const statusColors = {
537
+ pending: 'status-pending',
538
+ running: 'status-running',
539
+ success: 'status-success',
540
+ failed: 'status-failed',
541
+ timeout: 'status-timeout'
542
+ };
543
+
544
+ // Render Missions
545
+ function renderMissions() {
546
+ missionsContainer.innerHTML = '';
547
+
548
+ if (missions.length === 0) {
549
+ missionsContainer.innerHTML = `
550
+ <div class="text-center py-12 text-gray-400">
551
+ <i data-lucide="folder-x" class="w-16 h-16 mx-auto mb-4 text-gray-600"></i>
552
+ <p>No missions found</p>
553
+ </div>
554
+ `;
555
+ lucide.createIcons();
556
+ return;
557
+ }
558
+
559
+ missions.forEach((mission, index) => {
560
+ const missionCard = document.createElement('div');
561
+ missionCard.className = `card p-6 mission-card ${index % 2 === 0 ? 'mt-6' : ''}`;
562
+ missionCard.innerHTML = `
563
+ <div class="flex items-start justify-between">
564
+ <div class="flex-1">
565
+ <div class="flex items-center space-x-3 mb-3">
566
+ <h3 class="font-medium text-lg">${mission.url}</h3>
567
+ <span class="px-2.5 py-0.5 rounded-full text-xs font-medium ${statusColors[mission.status]}">
568
+ ${mission.status.toUpperCase()}
569
+ </span>
570
+ <span class="px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-700 text-gray-300">
571
+ ${formatDuration(mission.duration)}
572
+ </span>
573
+ </div>
574
+
575
+ <div class="space-y-2">
576
+ <p class="text-sm text-gray-400">
577
+ <span class="font-medium">Created:</span> ${mission.createdAt.toLocaleString()}
578
+ </p>
579
+ <p class="text-sm text-gray-400">
580
+ <span class="font-medium">Actions:</span> ${mission.workflow.length}
581
+ </p>
582
+ <p class="text-sm text-gray-400">
583
+ <span class="font-medium">Logs:</span> ${mission.logs.length} entries
584
+ </p>
585
+ </div>
586
+ </div>
587
+
588
+ <div class="flex flex-col space-y-2">
589
+ <button class="btn-primary px-4 py-2 rounded-lg text-sm font-medium flex items-center space-x-2 view-mission" data-id="${mission.id}">
590
+ <i data-lucide="eye"></i>
591
+ <span>View</span>
592
+ </button>
593
+ ${mission.status !== 'running' ? `
594
+ <button class="btn-success px-4 py-2 rounded-lg text-sm font-medium flex items-center space-x-2 rerun-mission" data-id="${mission.id}">
595
+ <i data-lucide="rotate-cw"></i>
596
+ <span>Re-run</span>
597
+ </button>` : ''}
598
+ </div>
599
+ </div>
600
+ `;
601
+
602
+ missionsContainer.appendChild(missionCard);
603
+ });
604
+
605
+ lucide.createIcons();
606
+ }
607
+
608
+ // Update Dashboard Stats
609
+ function updateStats() {
610
+ const totalMissions = missions.length;
611
+ const successMissions = missions.filter(m => m.status === 'success').length;
612
+ const runningMissions = missions.filter(m => m.status === 'running').length;
613
+ const avgDuration = totalMissions > 0
614
+ ? Math.round(missions.reduce((sum, m) => sum + m.duration, 0) / totalMissions)
615
+ : 0;
616
+
617
+ const successRate = totalMissions > 0
618
+ ? Math.round((successMissions / totalMissions) * 100)
619
+ : 0;
620
+
621
+ document.getElementById('totalMissions').textContent = totalMissions;
622
+ document.getElementById('successRate').textContent = `${successRate}%`;
623
+ document.getElementById('activeAgents').textContent = runningMissions;
624
+ document.getElementById('avgCompletion').textContent = `${avgDuration}s`;
625
+ }
626
+
627
+ // Format Duration
628
+ function formatDuration(seconds) {
629
+ if (seconds < 60) return `${seconds}s`;
630
+ const minutes = Math.floor(seconds / 60);
631
+ const remainingSeconds = seconds % 60;
632
+ return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`;
633
+ }
634
+
635
+ // Show Mission Details
636
+ function showMissionDetails(missionId) {
637
+ const mission = missions.find(m => m.id === missionId);
638
+ if (!mission) return;
639
+
640
+ document.getElementById('missionDetailsTitle').textContent = `Mission: ${mission.id}`;
641
+ document.getElementById('missionUrlDisplay').textContent = mission.url;
642
+ document.getElementById('missionDurationDisplay').textContent = formatDuration(mission.duration);
643
+
644
+ // Update status
645
+ const statusElement = document.getElementById('missionStatus');
646
+ statusElement.textContent = mission.status.toUpperCase();
647
+ statusElement.className = `font-medium ${statusColors[mission.status]}`;
648
+
649
+ // Update progress
650
+ const totalLogs = mission.logs.length;
651
+ const completedLogs = Math.min(totalLogs, Math.ceil(totalLogs * 0.8));
652
+ const progress = Math.round((completedLogs / totalLogs) * 100);
653
+
654
+ document.getElementById('missionProgressBar').style.width = `${progress}%`;
655
+ document.getElementById('missionProgress').textContent = `${progress}%`;
656
+
657
+ // Render logs
658
+ const logsContainer = document.getElementById('missionLogs');
659
+ if (mission.logs.length === 0) {
660
+ logsContainer.innerHTML = '<p class="text-gray-500">No logs yet...</p>';
661
+ } else {
662
+ logsContainer.innerHTML = mission.logs.map(log => `
663
+ <div class="log-entry mb-2">
664
+ <span class="text-gray-500 text-xs">${log.timestamp.toLocaleTimeString()}</span>
665
+ <span class="font-medium text-blue-400 mx-2">${log.action}</span>
666
+ <span class="text-gray-300">${log.details}</span>
667
+ </div>
668
+ `).join('');
669
+ }
670
+
671
+ // Render screenshots
672
+ const screenshotsContainer = document.getElementById('missionScreenshots');
673
+ if (mission.screenshots.length === 0) {
674
+ screenshotsContainer.innerHTML = '<div class="aspect-video bg-gray-800 rounded-lg flex items-center justify-center border border-gray-700"><p class="text-gray-500">No screenshots yet</p></div>';
675
+ } else {
676
+ screenshotsContainer.innerHTML = mission.screenshots.map((ss, index) => `
677
+ <div class="aspect-video bg-gray-800 rounded-lg overflow-hidden border border-gray-700 relative group">
678
+ <img src="${ss.url}" alt="Screenshot ${index + 1}" class="w-full h-full object-cover">
679
+ <div class="absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center">
680
+ <button class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1.5 rounded text-sm">
681
+ <i data-lucide="download"></i> Download
682
+ </button>
683
+ </div>
684
+ </div>
685
+ `).join('');
686
+ }
687
+
688
+ // Show modal
689
+ missionDetailsModal.classList.remove('hidden');
690
+ lucide.createIcons();
691
+ }
692
+
693
+ // Create New Mission
694
+ function createNewMission() {
695
+ const url = document.getElementById('missionUrl').value;
696
+ const duration = parseInt(document.getElementById('missionDuration').value) || 300;
697
+ const priority = document.getElementById('missionPriority').value;
698
+
699
+ // Validate URL
700
+ try {
701
+ new URL(url);
702
+ } catch (e) {
703
+ showToast('Invalid URL', 'Please enter a valid URL starting with http:// or https://', 'error');
704
+ return;
705
+ }
706
+
707
+ // Generate new mission ID
708
+ const missionId = `mission-${String(Math.floor(Math.random() * 10000)).padStart(4, '0')}`;
709
+
710
+ // Create new mission object
711
+ const newMission = {
712
+ id: missionId,
713
+ url: url,
714
+ workflow: [
715
+ { action: 'navigate_to', value: url }
716
+ ],
717
+ status: 'pending',
718
+ duration: 0,
719
+ createdAt: new Date(),
720
+ logs: [
721
+ { timestamp: new Date(), action: 'create_session', details: 'Mission created and queued' }
722
+ ],
723
+ screenshots: []
724
+ };
725
+
726
+ // Add to missions array
727
+ missions.unshift(newMission);
728
+
729
+ // Update stats and render
730
+ updateStats();
731
+ renderMissions();
732
+
733
+ // Show notification
734
+ showToast('Mission Created', `New mission ${missionId} has been created successfully`, 'success');
735
+
736
+ // Close modal
737
+ modal.classList.add('hidden');
738
+ }
739
+
740
+ // Show Toast Notification
741
+ function showToast(title, message, type = 'info') {
742
+ const toast = document.getElementById('notificationToast');
743
+ const titleElement = document.getElementById('toastTitle');
744
+ const messageElement = document.getElementById('toastMessage');
745
+ const iconElement = document.getElementById('toastIcon');
746
+
747
+ titleElement.textContent = title;
748
+ messageElement.textContent = message;
749
+
750
+ // Set icon based on type
751
+ switch (type) {
752
+ case 'success':
753
+ iconElement.innerHTML = '<i data-lucide="circle-check" class="text-green-400"></i>';
754
+ toast.classList.remove('border-red-500', 'border-yellow-500');
755
+ toast.classList.add('border-green-500');
756
+ break;
757
+ case 'error':
758
+ iconElement.innerHTML = '<i data-lucide="circle-alert" class="text-red-400"></i>';
759
+ toast.classList.remove('border-green-500', 'border-yellow-500');
760
+ toast.classList.add('border-red-500');
761
+ break;
762
+ default:
763
+ iconElement.innerHTML = '<i data-lucide="info" class="text-blue-400"></i>';
764
+ toast.classList.remove('border-green-500', 'border-red-500');
765
+ toast.classList.add('border-blue-500');
766
+ }
767
+
768
+ // Show toast
769
+ toast.classList.remove('translate-y-100');
770
+
771
+ // Hide after 5 seconds
772
+ setTimeout(() => {
773
+ toast.classList.add('translate-y-100');
774
+ }, 5000);
775
+ }
776
+
777
+ // Event Listeners
778
+ createMissionBtn.addEventListener('click', () => {
779
+ modal.classList.remove('hidden');
780
+ lucide.createIcons();
781
+ });
782
+
783
+ closeModal.addEventListener('click', () => {
784
+ modal.classList.add('hidden');
785
+ });
786
+
787
+ cancelMission.addEventListener('click', () => {
788
+ modal.classList.add('hidden');
789
+ });
790
+
791
+ createMission.addEventListener('click', createNewMission);
792
+
793
+ closeMissionDetails.addEventListener('click', () => {
794
+ missionDetailsModal.classList.add('hidden');
795
+ });
796
+
797
+ // Close modal when clicking outside
798
+ window.addEventListener('click', (e) => {
799
+ if (e.target === modal) {
800
+ modal.classList.add('hidden');
801
+ }
802
+ if (e.target === missionDetailsModal) {
803
+ missionDetailsModal.classList.add('hidden');
804
+ }
805
+ });
806
+
807
+ // Close toast
808
+ document.getElementById('closeToast').addEventListener('click', () => {
809
+ notificationToast.classList.add('translate-y-100');
810
+ });
811
+
812
+ // View mission details
813
+ missionsContainer.addEventListener('click', (e) => {
814
+ if (e.target.closest('.view-mission')) {
815
+ const missionId = e.target.closest('.view-mission').dataset.id;
816
+ showMissionDetails(missionId);
817
+ }
818
+ });
819
+
820
+ // Re-run mission
821
+ missionsContainer.addEventListener('click', (e) => {
822
+ if (e.target.closest('.rerun-mission')) {
823
+ const missionId = e.target.closest('.rerun-mission').dataset.id;
824
+ const mission = missions.find(m => m.id === missionId);
825
+ if (mission) {
826
+ showToast('Re-running Mission', `Re-running mission ${missionId}`, 'success');
827
+ }
828
+ }
829
+ });
830
+
831
+ // Re-run mission in details modal
832
+ reRunMission.addEventListener('click', () => {
833
+ showToast('Re-running Mission', 'Re-running current mission...', 'success');
834
+ // In a real app, this would trigger a new run
835
+ });
836
+
837
+ // Workflow help
838
+ workflowHelp.addEventListener('click', () => {
839
+ showToast('Workflow Help', 'Supported actions: navigate_to, scroll_page, click, wait, extract, take_screenshot', 'info');
840
+ });
841
+
842
+ // Initialize
843
+ updateStats();
844
+ renderMissions();
845
+ </script>
846
+ <script src="https://deepsite.hf.co/deepsite-badge.js"></script>
847
+ </body>
848
+ </html>
script.js ADDED
@@ -0,0 +1,332 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * AWIA Dashboard - Additional JavaScript Functionality
3
+ * This file contains advanced features and integrations
4
+ */
5
+
6
+ // Theme Management
7
+ class ThemeManager {
8
+ constructor() {
9
+ this.themes = {
10
+ default: {
11
+ bg: 'bg-gray-900',
12
+ card: 'bg-gray-800',
13
+ text: 'text-white'
14
+ },
15
+ dark: {
16
+ bg: 'bg-black',
17
+ card: 'bg-gray-900',
18
+ text: 'text-gray-100'
19
+ },
20
+ minimal: {
21
+ bg: 'bg-white',
22
+ card: 'bg-gray-50',
23
+ text: 'text-gray-800'
24
+ }
25
+ };
26
+
27
+ this.currentTheme = localStorage.getItem('awia-theme') || 'default';
28
+ this.applyTheme(this.currentTheme);
29
+ }
30
+
31
+ applyTheme(themeName) {
32
+ const theme = this.themes[themeName];
33
+ document.documentElement.className = theme.bg + ' ' + theme.text;
34
+ this.currentTheme = themeName;
35
+ localStorage.setItem('awia-theme', themeName);
36
+ }
37
+
38
+ toggleTheme() {
39
+ const themeNames = Object.keys(this.themes);
40
+ const currentIndex = themeNames.indexOf(this.currentTheme);
41
+ const nextIndex = (currentIndex + 1) % themeNames.length;
42
+ this.applyTheme(themeNames[nextIndex]);
43
+ }
44
+ }
45
+
46
+ // Data Visualization
47
+ class DashboardStats {
48
+ constructor() {
49
+ this.chartElements = {};
50
+ this.initCharts();
51
+ }
52
+
53
+ initCharts() {
54
+ // Simple chart implementation using CSS
55
+ this.createChart('successRateChart', 85, 'text-green-400');
56
+ this.createChart('responseTimeChart', 42, 'text-blue-400');
57
+ this.createChart('agentLoadChart', 67, 'text-purple-400');
58
+ }
59
+
60
+ createChart(elementId, value, colorClass) {
61
+ const element = document.getElementById(elementId);
62
+ if (element) {
63
+ element.innerHTML = `
64
+ <div class="relative">
65
+ <div class="absolute inset-0 flex items-center justify-center text-lg font-bold">
66
+ ${value}%
67
+ </div>
68
+ <div class="h-24 w-24 rounded-full border-4 border-gray-700 relative">
69
+ <div class="absolute inset-0 rounded-full overflow-hidden" style="background: conic-gradient(var(--tw-gradient-stops) from-current via-current/0 to-transparent);">
70
+ <div class="h-full w-full ${colorClass} rounded-full" style="clip-path: polygon(0 50%, 100% 50%, 100% ${100 - value}%, 0 ${100 - value}%);"></div>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ `;
75
+ }
76
+ }
77
+ }
78
+
79
+ // Real-time Updates Simulation
80
+ class RealTimeMonitor {
81
+ constructor() {
82
+ this.subscriptions = new Map();
83
+ this.lastUpdate = Date.now();
84
+
85
+ // Start monitoring updates
86
+ this.startMonitoring();
87
+ }
88
+
89
+ subscribe(eventType, callback) {
90
+ if (!this.subscriptions.has(eventType)) {
91
+ this.subscriptions.set(eventType, []);
92
+ }
93
+ this.subscriptions.get(eventType).push(callback);
94
+ }
95
+
96
+ emit(eventType, data) {
97
+ const callbacks = this.subscriptions.get(eventType) || [];
98
+ callbacks.forEach(callback => callback(data));
99
+ }
100
+
101
+ startMonitoring() {
102
+ // Simulate real-time updates
103
+ setInterval(() => {
104
+ const now = Date.now();
105
+
106
+ // Simulate agent activity every 15 seconds
107
+ if (now - this.lastUpdate > 15000) {
108
+ this.simulateAgentActivity();
109
+ this.lastUpdate = now;
110
+ }
111
+
112
+ // Update uptime counter
113
+ this.updateUptime();
114
+ }, 1000);
115
+ }
116
+
117
+ simulateAgentActivity() {
118
+ const activities = [
119
+ { type: 'agent_start', message: 'New agent started for mission-005' },
120
+ { type: 'mission_complete', message: 'Mission-003 completed successfully' },
121
+ { type: 'agent_activity', message: 'Agent #7 working on screenshot capture' }
122
+ ];
123
+
124
+ const randomActivity = activities[Math.floor(Math.random() * activities.length)];
125
+ this.emit('activity', randomActivity);
126
+ }
127
+
128
+ updateUptime() {
129
+ const uptimeElement = document.getElementById('uptimeCounter');
130
+ if (uptimeElement) {
131
+ const now = Date.now();
132
+ const seconds = Math.floor((now - this.lastUpdate) / 1000);
133
+ uptimeElement.textContent = `${seconds}s`;
134
+ }
135
+ }
136
+ }
137
+
138
+ // Mission Workflow Validator
139
+ class WorkflowValidator {
140
+ constructor() {
141
+ this.validActions = [
142
+ 'navigate_to', 'scroll_page', 'click', 'wait',
143
+ 'extract', 'take_screenshot', 'fill_form', 'hover',
144
+ 'drag_and_drop', 'keyboard_input', 'assert_element'
145
+ ];
146
+
147
+ this.requiredFields = {
148
+ 'navigate_to': ['value'],
149
+ 'scroll_page': ['x', 'y'],
150
+ 'click': ['selector'],
151
+ 'wait': ['value']
152
+ };
153
+ }
154
+
155
+ validate(workflow) {
156
+ if (!Array.isArray(workflow)) {
157
+ return { valid: false, errors: ['Workflow must be an array'] };
158
+ }
159
+
160
+ const errors = [];
161
+
162
+ workflow.forEach((step, index) => {
163
+ if (!step.action) {
164
+ errors.push(`Step ${index + 1}: Missing action property`);
165
+ return;
166
+ }
167
+
168
+ if (!this.validActions.includes(step.action)) {
169
+ errors.push(`Step ${index + 1}: Invalid action '${step.action}'`);
170
+ }
171
+
172
+ if (this.requiredFields[step.action]) {
173
+ const missingFields = this.requiredFields[step.action]
174
+ .filter(field => !step[field]);
175
+
176
+ if (missingFields.length > 0) {
177
+ errors.push(`Step ${index + 1}: Missing required fields: ${missingFields.join(', ')}`);
178
+ }
179
+ }
180
+ });
181
+
182
+ return {
183
+ valid: errors.length === 0,
184
+ errors
185
+ };
186
+ }
187
+ }
188
+
189
+ // Local Storage Manager
190
+ class StorageManager {
191
+ constructor() {
192
+ this.missionsKey = 'awia_missions';
193
+ this.settingsKey = 'awia_settings';
194
+
195
+ this.loadMissions();
196
+ }
197
+
198
+ loadMissions() {
199
+ const saved = localStorage.getItem(this.missionsKey);
200
+ if (saved) {
201
+ try {
202
+ // In a real app, you'd merge with existing data
203
+ // For demo, we'll just use saved data if available
204
+ console.log('Loaded missions from localStorage:', JSON.parse(saved));
205
+ } catch (e) {
206
+ console.error('Failed to load missions:', e);
207
+ }
208
+ }
209
+ }
210
+
211
+ saveMissions(missions) {
212
+ localStorage.setItem(this.missionsKey, JSON.stringify(missions));
213
+ }
214
+
215
+ saveSettings(settings) {
216
+ localStorage.setItem(this.settingsKey, JSON.stringify(settings));
217
+ }
218
+
219
+ loadSettings() {
220
+ return JSON.parse(localStorage.getItem(this.settingsKey) || '{}');
221
+ }
222
+ }
223
+
224
+ // Initialize Dashboard Components
225
+ document.addEventListener('DOMContentLoaded', () => {
226
+ // Initialize Theme Manager
227
+ const themeManager = new ThemeManager();
228
+
229
+ // Initialize Dashboard Stats
230
+ const stats = new DashboardStats();
231
+
232
+ // Initialize Real-time Monitor
233
+ const monitor = new RealTimeMonitor();
234
+
235
+ // Initialize Workflow Validator
236
+ const validator = new WorkflowValidator();
237
+
238
+ // Add theme toggle button
239
+ const themeToggle = document.createElement('button');
240
+ themeToggle.className = 'p-2 rounded-lg bg-gray-800 hover:bg-gray-700 text-gray-300 transition-colors';
241
+ themeToggle.innerHTML = '<i data-lucide="moon" class="w-5 h-5"></i>';
242
+ themeToggle.title = 'Toggle Theme';
243
+
244
+ themeToggle.addEventListener('click', () => {
245
+ themeManager.toggleTheme();
246
+ const isDark = document.documentElement.classList.contains('bg-black');
247
+ themeToggle.innerHTML = isDark
248
+ ? '<i data-lucide="sun" class="w-5 h-5"></i>'
249
+ : '<i data-lucide="moon" class="w-5 h-5"></i>';
250
+ lucide.createIcons();
251
+ });
252
+
253
+ // Add theme button to header
254
+ const header = document.querySelector('header .container');
255
+ if (header) {
256
+ header.querySelector('div:last-child').appendChild(themeToggle);
257
+ lucide.createIcons();
258
+ }
259
+
260
+ // Add real-time activity monitor
261
+ const monitorContainer = document.createElement('div');
262
+ monitorContainer.className = 'fixed bottom-4 left-4 z-50';
263
+ monitorContainer.innerHTML = `
264
+ <div class="card p-3">
265
+ <div class="flex items-center space-x-2">
266
+ <div class="relative">
267
+ <div class="w-2 h-2 bg-green-500 rounded-full animate-ping"></div>
268
+ <div class="w-2 h-2 bg-green-500 rounded-full relative z-10"></div>
269
+ </div>
270
+ <div class="text-sm">
271
+ <p class="font-medium">System Active</p>
272
+ <p class="text-xs text-gray-400">Uptime: <span id="uptimeCounter">0</span>s</p>
273
+ </div>
274
+ </div>
275
+ </div>
276
+ `;
277
+
278
+ document.body.appendChild(monitorContainer);
279
+
280
+ // Subscribe to activity updates
281
+ monitor.subscribe('activity', (activity) => {
282
+ // Show notification for activity
283
+ if (activity.type === 'mission_complete') {
284
+ showToast('Mission Complete', activity.message, 'success');
285
+ } else if (activity.type === 'agent_start') {
286
+ showToast('Agent Started', activity.message, 'info');
287
+ }
288
+ });
289
+
290
+ // Initial theme update
291
+ const isDark = document.documentElement.classList.contains('bg-black');
292
+ themeToggle.innerHTML = isDark
293
+ ? '<i data-lucide="sun" class="w-5 h-5"></i>'
294
+ : '<i data-lucide="moon" class="w-5 h-5"></i>';
295
+ });
296
+
297
+ // Show Toast Notification (reusable)
298
+ function showToast(title, message, type = 'info') {
299
+ const toast = document.getElementById('notificationToast');
300
+ const titleElement = document.getElementById('toastTitle');
301
+ const messageElement = document.getElementById('toastMessage');
302
+ const iconElement = document.getElementById('toastIcon');
303
+
304
+ titleElement.textContent = title;
305
+ messageElement.textContent = message;
306
+
307
+ // Set icon based on type
308
+ switch (type) {
309
+ case 'success':
310
+ iconElement.innerHTML = '<i data-lucide="circle-check" class="text-green-400"></i>';
311
+ toast.classList.remove('border-red-500', 'border-yellow-500');
312
+ toast.classList.add('border-green-500');
313
+ break;
314
+ case 'error':
315
+ iconElement.innerHTML = '<i data-lucide="circle-alert" class="text-red-400"></i>';
316
+ toast.classList.remove('border-green-500', 'border-yellow-500');
317
+ toast.classList.add('border-red-500');
318
+ break;
319
+ default:
320
+ iconElement.innerHTML = '<i data-lucide="info" class="text-blue-400"></i>';
321
+ toast.classList.remove('border-green-500', 'border-red-500');
322
+ toast.classList.add('border-blue-500');
323
+ }
324
+
325
+ // Show toast
326
+ toast.classList.remove('translate-y-100');
327
+
328
+ // Hide after 5 seconds
329
+ setTimeout(() => {
330
+ toast.classList.add('translate-y-100');
331
+ }, 5000);
332
+ }