parse-dashboard-analytics 1.0.7 → 1.0.8
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/Parse-Dashboard/app.js +84 -10
- package/Parse-Dashboard/parse-dashboard-config.json +7 -5
- package/Parse-Dashboard/public/analytics.html +9 -8
- package/Parse-Dashboard/public/bundles/dashboard.bundle.js +1 -1
- package/Parse-Dashboard/public/custom-remote-analytics.html +710 -0
- package/Parse-Dashboard/public/simple-analytics.html +294 -0
- package/package.json +1 -1
|
@@ -0,0 +1,294 @@
|
|
|
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>Analytics Dashboard - Working Demo</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
16
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
17
|
+
color: white;
|
|
18
|
+
min-height: 100vh;
|
|
19
|
+
padding: 20px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.container {
|
|
23
|
+
max-width: 1200px;
|
|
24
|
+
margin: 0 auto;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.header {
|
|
28
|
+
background: rgba(255, 255, 255, 0.1);
|
|
29
|
+
backdrop-filter: blur(15px);
|
|
30
|
+
border-radius: 16px;
|
|
31
|
+
padding: 32px;
|
|
32
|
+
margin-bottom: 32px;
|
|
33
|
+
text-align: center;
|
|
34
|
+
position: relative;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.status {
|
|
38
|
+
position: absolute;
|
|
39
|
+
top: 20px;
|
|
40
|
+
right: 20px;
|
|
41
|
+
padding: 8px 16px;
|
|
42
|
+
border-radius: 20px;
|
|
43
|
+
font-size: 12px;
|
|
44
|
+
font-weight: 600;
|
|
45
|
+
background: rgba(40, 167, 69, 0.3);
|
|
46
|
+
color: #28a745;
|
|
47
|
+
border: 1px solid rgba(40, 167, 69, 0.5);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.metrics-grid {
|
|
51
|
+
display: grid;
|
|
52
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
53
|
+
gap: 24px;
|
|
54
|
+
margin-bottom: 40px;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.metric-card {
|
|
58
|
+
background: rgba(255, 255, 255, 0.1);
|
|
59
|
+
backdrop-filter: blur(15px);
|
|
60
|
+
border-radius: 16px;
|
|
61
|
+
padding: 32px;
|
|
62
|
+
text-align: center;
|
|
63
|
+
position: relative;
|
|
64
|
+
overflow: hidden;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.metric-card::before {
|
|
68
|
+
content: '';
|
|
69
|
+
position: absolute;
|
|
70
|
+
top: 0;
|
|
71
|
+
left: 0;
|
|
72
|
+
right: 0;
|
|
73
|
+
height: 3px;
|
|
74
|
+
background: linear-gradient(90deg, #ff6b6b, #4ecdc4, #45b7d1, #96ceb4);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.metric-value {
|
|
78
|
+
font-size: 48px;
|
|
79
|
+
font-weight: 800;
|
|
80
|
+
margin-bottom: 8px;
|
|
81
|
+
background: linear-gradient(45deg, #fff, #e0e7ff);
|
|
82
|
+
-webkit-background-clip: text;
|
|
83
|
+
-webkit-text-fill-color: transparent;
|
|
84
|
+
background-clip: text;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.metric-label {
|
|
88
|
+
font-size: 18px;
|
|
89
|
+
opacity: 0.9;
|
|
90
|
+
margin-bottom: 8px;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.metric-change {
|
|
94
|
+
font-size: 14px;
|
|
95
|
+
padding: 4px 12px;
|
|
96
|
+
border-radius: 20px;
|
|
97
|
+
background: rgba(40, 167, 69, 0.3);
|
|
98
|
+
color: #28a745;
|
|
99
|
+
display: inline-block;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.server-info {
|
|
103
|
+
background: rgba(255, 255, 255, 0.1);
|
|
104
|
+
backdrop-filter: blur(10px);
|
|
105
|
+
border-radius: 12px;
|
|
106
|
+
padding: 24px;
|
|
107
|
+
margin-top: 32px;
|
|
108
|
+
text-align: center;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.back-button {
|
|
112
|
+
display: inline-block;
|
|
113
|
+
padding: 12px 24px;
|
|
114
|
+
background: rgba(255, 255, 255, 0.2);
|
|
115
|
+
color: white;
|
|
116
|
+
text-decoration: none;
|
|
117
|
+
border-radius: 25px;
|
|
118
|
+
margin-bottom: 32px;
|
|
119
|
+
transition: all 0.3s ease;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.back-button:hover {
|
|
123
|
+
background: rgba(255, 255, 255, 0.3);
|
|
124
|
+
transform: translateX(-5px);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.refresh-btn {
|
|
128
|
+
background: rgba(255, 255, 255, 0.2);
|
|
129
|
+
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
130
|
+
color: white;
|
|
131
|
+
padding: 10px 20px;
|
|
132
|
+
border-radius: 20px;
|
|
133
|
+
cursor: pointer;
|
|
134
|
+
margin-left: 16px;
|
|
135
|
+
}
|
|
136
|
+
</style>
|
|
137
|
+
</head>
|
|
138
|
+
<body>
|
|
139
|
+
<div class="container">
|
|
140
|
+
<a href="#" onclick="history.back()" class="back-button">← Back to Dashboard</a>
|
|
141
|
+
|
|
142
|
+
<div class="header">
|
|
143
|
+
<div class="status" id="status">Connected</div>
|
|
144
|
+
<h1>✅ CUSTOM Analytics Dashboard - WORKING CORRECTLY</h1>
|
|
145
|
+
<p>🎉 SUCCESS! This is the custom simple-analytics.html file!</p>
|
|
146
|
+
<p style="color: green; font-weight: bold;">The analyticsPage configuration is working properly.</p>
|
|
147
|
+
<button class="refresh-btn" onclick="loadData()">Refresh Data</button>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<div class="metrics-grid">
|
|
151
|
+
<div class="metric-card">
|
|
152
|
+
<div class="metric-value" id="totalUsers">Loading...</div>
|
|
153
|
+
<div class="metric-label">Total Users</div>
|
|
154
|
+
<div class="metric-change" id="usersChange">+15.2% this month</div>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
<div class="metric-card">
|
|
158
|
+
<div class="metric-value" id="totalObjects">Loading...</div>
|
|
159
|
+
<div class="metric-label">Total Objects</div>
|
|
160
|
+
<div class="metric-change" id="objectsChange">+8.7% this week</div>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<div class="metric-card">
|
|
164
|
+
<div class="metric-value" id="apiCalls">Loading...</div>
|
|
165
|
+
<div class="metric-label">API Calls (24h)</div>
|
|
166
|
+
<div class="metric-change" id="apiChange">+12.3% today</div>
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
<div class="metric-card">
|
|
170
|
+
<div class="metric-value" id="activeSessions">Loading...</div>
|
|
171
|
+
<div class="metric-label">Active Sessions</div>
|
|
172
|
+
<div class="metric-change" id="sessionsChange">+22.1% this hour</div>
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
|
|
176
|
+
<div class="server-info">
|
|
177
|
+
<h3>🔧 Server Connection</h3>
|
|
178
|
+
<p>Status: <span id="serverStatus">Checking connection...</span></p>
|
|
179
|
+
<p id="serverUrl">Endpoint: Detecting...</p>
|
|
180
|
+
<p><small>Last updated: <span id="lastUpdated">Never</span></small></p>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
|
|
184
|
+
<script>
|
|
185
|
+
let serverUrl = '';
|
|
186
|
+
|
|
187
|
+
// Test different server endpoints
|
|
188
|
+
async function findWorkingServer() {
|
|
189
|
+
const servers = [
|
|
190
|
+
'http://localhost:3001',
|
|
191
|
+
'http://192.168.0.138:3001',
|
|
192
|
+
'http://192.168.0.138:3000'
|
|
193
|
+
];
|
|
194
|
+
|
|
195
|
+
for (const server of servers) {
|
|
196
|
+
try {
|
|
197
|
+
console.log(`Testing: ${server}`);
|
|
198
|
+
const response = await fetch(`${server}/api/analytics/overview`, {
|
|
199
|
+
method: 'GET',
|
|
200
|
+
headers: { 'Content-Type': 'application/json' },
|
|
201
|
+
mode: 'cors'
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
if (response.ok) {
|
|
205
|
+
console.log(`✅ Working server found: ${server}`);
|
|
206
|
+
serverUrl = server;
|
|
207
|
+
document.getElementById('serverStatus').textContent = '✅ Connected';
|
|
208
|
+
document.getElementById('serverUrl').textContent = `Endpoint: ${server}`;
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
} catch (error) {
|
|
212
|
+
console.log(`❌ Failed: ${server} - ${error.message}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
console.log('❌ No working server found, using mock data');
|
|
217
|
+
document.getElementById('serverStatus').textContent = '❌ Using Mock Data';
|
|
218
|
+
document.getElementById('serverUrl').textContent = 'Endpoint: Mock Data Generator';
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Load analytics data
|
|
223
|
+
async function loadData() {
|
|
224
|
+
const hasServer = await findWorkingServer();
|
|
225
|
+
|
|
226
|
+
let data;
|
|
227
|
+
if (hasServer && serverUrl) {
|
|
228
|
+
try {
|
|
229
|
+
const response = await fetch(`${serverUrl}/api/analytics/overview`);
|
|
230
|
+
data = await response.json();
|
|
231
|
+
console.log('📊 Live data loaded:', data);
|
|
232
|
+
} catch (error) {
|
|
233
|
+
console.error('❌ Failed to load live data:', error);
|
|
234
|
+
data = generateMockData();
|
|
235
|
+
}
|
|
236
|
+
} else {
|
|
237
|
+
data = generateMockData();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Update UI
|
|
241
|
+
document.getElementById('totalUsers').textContent = data.metrics.totalUsers.toLocaleString();
|
|
242
|
+
document.getElementById('totalObjects').textContent = data.metrics.totalObjects.toLocaleString();
|
|
243
|
+
document.getElementById('apiCalls').textContent = data.metrics.apiCalls.toLocaleString();
|
|
244
|
+
document.getElementById('activeSessions').textContent = data.metrics.activeSessions.toLocaleString();
|
|
245
|
+
|
|
246
|
+
document.getElementById('usersChange').textContent = data.changes.users;
|
|
247
|
+
document.getElementById('objectsChange').textContent = data.changes.objects;
|
|
248
|
+
document.getElementById('apiChange').textContent = data.changes.api;
|
|
249
|
+
document.getElementById('sessionsChange').textContent = data.changes.sessions;
|
|
250
|
+
|
|
251
|
+
document.getElementById('lastUpdated').textContent = new Date().toLocaleTimeString();
|
|
252
|
+
|
|
253
|
+
const statusEl = document.getElementById('status');
|
|
254
|
+
if (hasServer) {
|
|
255
|
+
statusEl.textContent = 'Live Data';
|
|
256
|
+
statusEl.style.background = 'rgba(40, 167, 69, 0.3)';
|
|
257
|
+
statusEl.style.color = '#28a745';
|
|
258
|
+
} else {
|
|
259
|
+
statusEl.textContent = 'Mock Data';
|
|
260
|
+
statusEl.style.background = 'rgba(255, 193, 7, 0.3)';
|
|
261
|
+
statusEl.style.color = '#ffc107';
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Generate mock data
|
|
266
|
+
function generateMockData() {
|
|
267
|
+
return {
|
|
268
|
+
timestamp: new Date().toISOString(),
|
|
269
|
+
metrics: {
|
|
270
|
+
totalUsers: Math.floor(Math.random() * 5000) + 1000,
|
|
271
|
+
totalObjects: Math.floor(Math.random() * 20000) + 5000,
|
|
272
|
+
apiCalls: Math.floor(Math.random() * 1000) + 200,
|
|
273
|
+
activeSessions: Math.floor(Math.random() * 100) + 20
|
|
274
|
+
},
|
|
275
|
+
changes: {
|
|
276
|
+
users: '+' + (Math.random() * 20 + 5).toFixed(1) + '% this month',
|
|
277
|
+
objects: '+' + (Math.random() * 15 + 3).toFixed(1) + '% this week',
|
|
278
|
+
api: '+' + (Math.random() * 10 + 1).toFixed(1) + '% today',
|
|
279
|
+
sessions: '+' + (Math.random() * 25 + 5).toFixed(1) + '% this hour'
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Initialize on page load
|
|
285
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
286
|
+
console.log('🚀 Starting Analytics Dashboard...');
|
|
287
|
+
loadData();
|
|
288
|
+
|
|
289
|
+
// Auto-refresh every 30 seconds
|
|
290
|
+
setInterval(loadData, 30000);
|
|
291
|
+
});
|
|
292
|
+
</script>
|
|
293
|
+
</body>
|
|
294
|
+
</html>
|