shell-mirror 1.5.56 → 1.5.57
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/package.json +1 -1
- package/public/app/dashboard.css +19 -0
- package/public/app/dashboard.js +107 -8
package/package.json
CHANGED
package/public/app/dashboard.css
CHANGED
|
@@ -833,4 +833,23 @@ body {
|
|
|
833
833
|
opacity: 0;
|
|
834
834
|
transform: translateX(100%);
|
|
835
835
|
}
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
/* API Error Display */
|
|
839
|
+
.api-error {
|
|
840
|
+
text-align: center;
|
|
841
|
+
padding: 20px;
|
|
842
|
+
background: #fff5f5;
|
|
843
|
+
border: 1px solid #fed7d7;
|
|
844
|
+
border-radius: 8px;
|
|
845
|
+
color: #c53030;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
.api-error p {
|
|
849
|
+
margin-bottom: 15px;
|
|
850
|
+
font-weight: 500;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
.api-error button {
|
|
854
|
+
margin-top: 10px;
|
|
836
855
|
}
|
package/public/app/dashboard.js
CHANGED
|
@@ -102,8 +102,24 @@ class ShellMirrorDashboard {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
setupWebSocket() {
|
|
105
|
+
// Detect production environment
|
|
106
|
+
const isProduction = window.location.hostname === 'shellmirror.app' ||
|
|
107
|
+
window.location.hostname === 'www.shellmirror.app' ||
|
|
108
|
+
window.location.hostname === 'www.igori.eu' ||
|
|
109
|
+
window.location.hostname === 'igori.eu';
|
|
110
|
+
|
|
105
111
|
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
106
|
-
|
|
112
|
+
let wsUrl;
|
|
113
|
+
|
|
114
|
+
if (isProduction) {
|
|
115
|
+
// For production, try the Heroku WebSocket app URL
|
|
116
|
+
// This may need to be adjusted based on actual deployment architecture
|
|
117
|
+
wsUrl = `wss://shell-mirror-30aa5479ceaf.herokuapp.com/?role=dashboard`;
|
|
118
|
+
console.log('[DASHBOARD] 🌐 Production environment detected, using Heroku WebSocket URL');
|
|
119
|
+
} else {
|
|
120
|
+
// For development, use same host
|
|
121
|
+
wsUrl = `${protocol}//${window.location.host}/?role=dashboard`;
|
|
122
|
+
}
|
|
107
123
|
|
|
108
124
|
console.log('[DASHBOARD] 🔌 Connecting to WebSocket:', wsUrl);
|
|
109
125
|
|
|
@@ -111,9 +127,20 @@ class ShellMirrorDashboard {
|
|
|
111
127
|
this.websocket = new WebSocket(wsUrl);
|
|
112
128
|
|
|
113
129
|
this.websocket.onopen = () => {
|
|
114
|
-
console.log('[DASHBOARD] ✅ WebSocket connected');
|
|
130
|
+
console.log('[DASHBOARD] ✅ WebSocket connected to:', wsUrl);
|
|
115
131
|
this.reconnectAttempts = 0;
|
|
116
132
|
this.updateConnectionStatus('connected');
|
|
133
|
+
|
|
134
|
+
// Send authentication info if available
|
|
135
|
+
const user = this.user;
|
|
136
|
+
if (user) {
|
|
137
|
+
console.log('[DASHBOARD] 🔐 Sending authentication to WebSocket');
|
|
138
|
+
this.websocket.send(JSON.stringify({
|
|
139
|
+
type: 'authenticate',
|
|
140
|
+
userId: user.id || user.email,
|
|
141
|
+
email: user.email
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
117
144
|
};
|
|
118
145
|
|
|
119
146
|
this.websocket.onmessage = (event) => {
|
|
@@ -121,13 +148,38 @@ class ShellMirrorDashboard {
|
|
|
121
148
|
};
|
|
122
149
|
|
|
123
150
|
this.websocket.onclose = (event) => {
|
|
124
|
-
|
|
151
|
+
const closeReasons = {
|
|
152
|
+
1000: 'Normal Closure',
|
|
153
|
+
1001: 'Going Away',
|
|
154
|
+
1002: 'Protocol Error',
|
|
155
|
+
1003: 'Unsupported Data',
|
|
156
|
+
1004: 'Reserved',
|
|
157
|
+
1005: 'No Status Rcvd',
|
|
158
|
+
1006: 'Abnormal Closure',
|
|
159
|
+
1007: 'Invalid frame payload data',
|
|
160
|
+
1008: 'Policy Violation',
|
|
161
|
+
1009: 'Message too big',
|
|
162
|
+
1010: 'Mandatory Extension',
|
|
163
|
+
1011: 'Internal Server Error',
|
|
164
|
+
1015: 'TLS Handshake'
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const reason = closeReasons[event.code] || 'Unknown';
|
|
168
|
+
console.log(`[DASHBOARD] 🔌 WebSocket closed: ${event.code} (${reason})`, event.reason);
|
|
169
|
+
|
|
170
|
+
if (event.code === 1008) {
|
|
171
|
+
console.error('[DASHBOARD] ❌ Authentication required - WebSocket rejected connection');
|
|
172
|
+
} else if (event.code === 1006) {
|
|
173
|
+
console.error('[DASHBOARD] ❌ Abnormal closure - WebSocket endpoint may not exist');
|
|
174
|
+
}
|
|
175
|
+
|
|
125
176
|
this.updateConnectionStatus('disconnected');
|
|
126
177
|
this.attemptReconnect();
|
|
127
178
|
};
|
|
128
179
|
|
|
129
180
|
this.websocket.onerror = (error) => {
|
|
130
181
|
console.error('[DASHBOARD] ❌ WebSocket error:', error);
|
|
182
|
+
console.log('[DASHBOARD] 🔍 WebSocket URL attempted:', wsUrl);
|
|
131
183
|
this.updateConnectionStatus('error');
|
|
132
184
|
};
|
|
133
185
|
|
|
@@ -222,9 +274,26 @@ class ShellMirrorDashboard {
|
|
|
222
274
|
this.setupWebSocket();
|
|
223
275
|
}, delay);
|
|
224
276
|
} else {
|
|
225
|
-
console.log('[DASHBOARD] ❌ Max reconnection attempts reached
|
|
226
|
-
this.updateConnectionStatus('
|
|
277
|
+
console.log('[DASHBOARD] ❌ Max reconnection attempts reached, switching to HTTP-only mode');
|
|
278
|
+
this.updateConnectionStatus('offline');
|
|
279
|
+
this.enableHttpOnlyMode();
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
enableHttpOnlyMode() {
|
|
284
|
+
console.log('[DASHBOARD] 📡 Enabling HTTP-only mode (no real-time updates)');
|
|
285
|
+
this.websocket = null;
|
|
286
|
+
|
|
287
|
+
// Update UI to show HTTP-only mode
|
|
288
|
+
const connectionStatus = document.getElementById('connection-status');
|
|
289
|
+
if (connectionStatus) {
|
|
290
|
+
connectionStatus.textContent = '📡 HTTP Only';
|
|
291
|
+
connectionStatus.className = 'connection-status offline';
|
|
292
|
+
connectionStatus.title = 'Real-time updates unavailable - using polling';
|
|
227
293
|
}
|
|
294
|
+
|
|
295
|
+
// Continue with HTTP polling only
|
|
296
|
+
console.log('[DASHBOARD] ✅ Dashboard running in HTTP-only mode');
|
|
228
297
|
}
|
|
229
298
|
|
|
230
299
|
updateConnectionStatus(status) {
|
|
@@ -301,15 +370,27 @@ class ShellMirrorDashboard {
|
|
|
301
370
|
|
|
302
371
|
async loadDashboardData() {
|
|
303
372
|
try {
|
|
304
|
-
// Load active agents
|
|
305
|
-
|
|
373
|
+
// Load active agents with detailed debugging
|
|
374
|
+
console.log('[DASHBOARD] 📡 Fetching agents from API...');
|
|
375
|
+
const agentsResponse = await fetch('/php-backend/api/agents-list.php', {
|
|
376
|
+
credentials: 'include' // Include authentication cookies
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
console.log('[DASHBOARD] 🔍 API Response Status:', agentsResponse.status);
|
|
380
|
+
console.log('[DASHBOARD] 🔍 API Response Headers:', Object.fromEntries(agentsResponse.headers.entries()));
|
|
381
|
+
|
|
306
382
|
const agentsData = await agentsResponse.json();
|
|
383
|
+
console.log('[DASHBOARD] 🔍 API Response Data:', agentsData);
|
|
307
384
|
|
|
308
385
|
if (agentsData.success && agentsData.data && agentsData.data.agents) {
|
|
309
386
|
this.agents = agentsData.data.agents;
|
|
387
|
+
console.log('[DASHBOARD] ✅ Loaded agents:', this.agents.length);
|
|
310
388
|
|
|
311
389
|
// Load session data from localStorage (persisted from terminal connections)
|
|
312
390
|
this.loadSessionsFromStorage();
|
|
391
|
+
} else {
|
|
392
|
+
console.warn('[DASHBOARD] ⚠️ No agents found in API response:', agentsData);
|
|
393
|
+
this.agents = [];
|
|
313
394
|
}
|
|
314
395
|
|
|
315
396
|
// TODO: Load session history when API is available
|
|
@@ -331,7 +412,25 @@ class ShellMirrorDashboard {
|
|
|
331
412
|
];
|
|
332
413
|
|
|
333
414
|
} catch (error) {
|
|
334
|
-
console.error('Failed to load dashboard data:', error);
|
|
415
|
+
console.error('[DASHBOARD] ❌ Failed to load dashboard data:', error);
|
|
416
|
+
this.agents = [];
|
|
417
|
+
|
|
418
|
+
// Show error in UI
|
|
419
|
+
const agentsCard = document.querySelector('.dashboard-card');
|
|
420
|
+
if (agentsCard) {
|
|
421
|
+
agentsCard.innerHTML = `
|
|
422
|
+
<div class="card-header">
|
|
423
|
+
<h2>🖥️ Active Agents</h2>
|
|
424
|
+
<span class="agent-count">Error</span>
|
|
425
|
+
</div>
|
|
426
|
+
<div class="card-content">
|
|
427
|
+
<div class="api-error">
|
|
428
|
+
<p>⚠️ Failed to load agents: ${error.message}</p>
|
|
429
|
+
<button onclick="dashboard.manualRefresh()" class="btn-primary">Retry</button>
|
|
430
|
+
</div>
|
|
431
|
+
</div>
|
|
432
|
+
`;
|
|
433
|
+
}
|
|
335
434
|
}
|
|
336
435
|
}
|
|
337
436
|
|