worker-que 1.0.1 → 1.1.2
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/DASHBOARD.md +82 -14
- package/README.md +10 -4
- package/dist/dashboard/index.d.ts +24 -7
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +121 -10
- package/dist/dashboard/index.js.map +1 -1
- package/dist/dashboard/service.d.ts +12 -1
- package/dist/dashboard/service.d.ts.map +1 -1
- package/dist/dashboard/service.js +7 -3
- package/dist/dashboard/service.js.map +1 -1
- package/dist/dashboard/views.d.ts +3 -2
- package/dist/dashboard/views.d.ts.map +1 -1
- package/dist/dashboard/views.js +819 -141
- package/dist/dashboard/views.js.map +1 -1
- package/package.json +8 -2
package/dist/dashboard/views.js
CHANGED
|
@@ -1,7 +1,257 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getLoginHTML = getLoginHTML;
|
|
3
4
|
exports.getDashboardHTML = getDashboardHTML;
|
|
4
|
-
function
|
|
5
|
+
function getLoginHTML(options, error) {
|
|
6
|
+
return `
|
|
7
|
+
<!DOCTYPE html>
|
|
8
|
+
<html lang="en">
|
|
9
|
+
<head>
|
|
10
|
+
<meta charset="UTF-8">
|
|
11
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
12
|
+
<title>Sign in - ${options.title}</title>
|
|
13
|
+
<style>
|
|
14
|
+
* {
|
|
15
|
+
margin: 0;
|
|
16
|
+
padding: 0;
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
body {
|
|
21
|
+
font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif;
|
|
22
|
+
background: linear-gradient(135deg, #0078d4 0%, #005a9e 100%);
|
|
23
|
+
min-height: 100vh;
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
padding: 2rem;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.login-container {
|
|
31
|
+
background: white;
|
|
32
|
+
border-radius: 8px;
|
|
33
|
+
box-shadow: 0 2px 40px rgba(0,0,0,0.2);
|
|
34
|
+
width: 100%;
|
|
35
|
+
max-width: 440px;
|
|
36
|
+
padding: 44px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.logo-container {
|
|
40
|
+
text-align: center;
|
|
41
|
+
margin-bottom: 24px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.logo {
|
|
45
|
+
width: 60px;
|
|
46
|
+
height: 60px;
|
|
47
|
+
background: linear-gradient(135deg, #0078d4, #106ebe);
|
|
48
|
+
border-radius: 12px;
|
|
49
|
+
display: inline-flex;
|
|
50
|
+
align-items: center;
|
|
51
|
+
justify-content: center;
|
|
52
|
+
margin-bottom: 16px;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.logo-icon {
|
|
56
|
+
font-size: 32px;
|
|
57
|
+
color: white;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
h1 {
|
|
61
|
+
font-size: 24px;
|
|
62
|
+
font-weight: 600;
|
|
63
|
+
color: #1f1f1f;
|
|
64
|
+
margin-bottom: 8px;
|
|
65
|
+
text-align: center;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.subtitle {
|
|
69
|
+
font-size: 15px;
|
|
70
|
+
color: #605e5c;
|
|
71
|
+
text-align: center;
|
|
72
|
+
margin-bottom: 32px;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.form-group {
|
|
76
|
+
margin-bottom: 24px;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
label {
|
|
80
|
+
display: block;
|
|
81
|
+
font-size: 14px;
|
|
82
|
+
font-weight: 600;
|
|
83
|
+
color: #323130;
|
|
84
|
+
margin-bottom: 8px;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
input[type="email"],
|
|
88
|
+
input[type="password"] {
|
|
89
|
+
width: 100%;
|
|
90
|
+
padding: 10px 12px;
|
|
91
|
+
font-size: 14px;
|
|
92
|
+
border: 1px solid #8a8886;
|
|
93
|
+
border-radius: 2px;
|
|
94
|
+
transition: all 0.15s ease;
|
|
95
|
+
font-family: 'Segoe UI', sans-serif;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
input:focus {
|
|
99
|
+
outline: none;
|
|
100
|
+
border-color: #0078d4;
|
|
101
|
+
box-shadow: 0 0 0 1px #0078d4;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
input:hover {
|
|
105
|
+
border-color: #323130;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.error-message {
|
|
109
|
+
background: #fde7e9;
|
|
110
|
+
border-left: 3px solid #a4262c;
|
|
111
|
+
color: #a4262c;
|
|
112
|
+
padding: 12px 16px;
|
|
113
|
+
font-size: 13px;
|
|
114
|
+
margin-bottom: 20px;
|
|
115
|
+
border-radius: 2px;
|
|
116
|
+
display: flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
gap: 8px;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.error-icon {
|
|
122
|
+
font-weight: bold;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.submit-btn {
|
|
126
|
+
width: 100%;
|
|
127
|
+
background: #0078d4;
|
|
128
|
+
color: white;
|
|
129
|
+
border: none;
|
|
130
|
+
padding: 11px 24px;
|
|
131
|
+
font-size: 14px;
|
|
132
|
+
font-weight: 600;
|
|
133
|
+
border-radius: 2px;
|
|
134
|
+
cursor: pointer;
|
|
135
|
+
transition: all 0.15s ease;
|
|
136
|
+
font-family: 'Segoe UI', sans-serif;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.submit-btn:hover {
|
|
140
|
+
background: #106ebe;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.submit-btn:active {
|
|
144
|
+
background: #005a9e;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.submit-btn:disabled {
|
|
148
|
+
background: #f3f2f1;
|
|
149
|
+
color: #a19f9d;
|
|
150
|
+
cursor: not-allowed;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.remember-me {
|
|
154
|
+
display: flex;
|
|
155
|
+
align-items: center;
|
|
156
|
+
margin-bottom: 24px;
|
|
157
|
+
font-size: 13px;
|
|
158
|
+
color: #323130;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.remember-me input[type="checkbox"] {
|
|
162
|
+
margin-right: 8px;
|
|
163
|
+
width: 16px;
|
|
164
|
+
height: 16px;
|
|
165
|
+
cursor: pointer;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.footer-text {
|
|
169
|
+
margin-top: 24px;
|
|
170
|
+
text-align: center;
|
|
171
|
+
font-size: 12px;
|
|
172
|
+
color: #605e5c;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.security-badge {
|
|
176
|
+
display: inline-flex;
|
|
177
|
+
align-items: center;
|
|
178
|
+
gap: 6px;
|
|
179
|
+
padding: 8px 12px;
|
|
180
|
+
background: #f3f2f1;
|
|
181
|
+
border-radius: 4px;
|
|
182
|
+
font-size: 12px;
|
|
183
|
+
color: #605e5c;
|
|
184
|
+
margin-top: 16px;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.lock-icon {
|
|
188
|
+
color: #107c10;
|
|
189
|
+
}
|
|
190
|
+
</style>
|
|
191
|
+
</head>
|
|
192
|
+
<body>
|
|
193
|
+
<div class="login-container">
|
|
194
|
+
<div class="logo-container">
|
|
195
|
+
<div class="logo">
|
|
196
|
+
<span class="logo-icon">📊</span>
|
|
197
|
+
</div>
|
|
198
|
+
<h1>${options.title}</h1>
|
|
199
|
+
<p class="subtitle">Sign in to continue to dashboard</p>
|
|
200
|
+
</div>
|
|
201
|
+
|
|
202
|
+
${error ? `
|
|
203
|
+
<div class="error-message">
|
|
204
|
+
<span class="error-icon">⚠</span>
|
|
205
|
+
<span>${error}</span>
|
|
206
|
+
</div>
|
|
207
|
+
` : ''}
|
|
208
|
+
|
|
209
|
+
<form method="POST" action="${options.basePath}/login">
|
|
210
|
+
<div class="form-group">
|
|
211
|
+
<label for="email">Email</label>
|
|
212
|
+
<input
|
|
213
|
+
type="email"
|
|
214
|
+
id="email"
|
|
215
|
+
name="email"
|
|
216
|
+
required
|
|
217
|
+
autocomplete="email"
|
|
218
|
+
placeholder="Enter your email"
|
|
219
|
+
autofocus
|
|
220
|
+
>
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
<div class="form-group">
|
|
224
|
+
<label for="password">Password</label>
|
|
225
|
+
<input
|
|
226
|
+
type="password"
|
|
227
|
+
id="password"
|
|
228
|
+
name="password"
|
|
229
|
+
required
|
|
230
|
+
autocomplete="current-password"
|
|
231
|
+
placeholder="Enter your password"
|
|
232
|
+
>
|
|
233
|
+
</div>
|
|
234
|
+
|
|
235
|
+
<div class="remember-me">
|
|
236
|
+
<input type="checkbox" id="remember" name="remember" value="yes">
|
|
237
|
+
<label for="remember" style="margin-bottom: 0; font-weight: 400;">Keep me signed in</label>
|
|
238
|
+
</div>
|
|
239
|
+
|
|
240
|
+
<button type="submit" class="submit-btn">Sign in</button>
|
|
241
|
+
|
|
242
|
+
<div class="footer-text">
|
|
243
|
+
<div class="security-badge">
|
|
244
|
+
<span class="lock-icon">🔒</span>
|
|
245
|
+
<span>Secure connection</span>
|
|
246
|
+
</div>
|
|
247
|
+
</div>
|
|
248
|
+
</form>
|
|
249
|
+
</div>
|
|
250
|
+
</body>
|
|
251
|
+
</html>
|
|
252
|
+
`.trim();
|
|
253
|
+
}
|
|
254
|
+
function getDashboardHTML(options, userEmail) {
|
|
5
255
|
return `
|
|
6
256
|
<!DOCTYPE html>
|
|
7
257
|
<html lang="en">
|
|
@@ -17,164 +267,296 @@ function getDashboardHTML(options) {
|
|
|
17
267
|
}
|
|
18
268
|
|
|
19
269
|
body {
|
|
20
|
-
font-family: -apple-system, BlinkMacSystemFont,
|
|
21
|
-
background: #
|
|
22
|
-
color: #
|
|
270
|
+
font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif;
|
|
271
|
+
background: #faf9f8;
|
|
272
|
+
color: #201f1e;
|
|
23
273
|
line-height: 1.6;
|
|
24
274
|
}
|
|
25
275
|
|
|
276
|
+
/* Microsoft Fluent Design Header */
|
|
26
277
|
.header {
|
|
27
|
-
background:
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
278
|
+
background: #ffffff;
|
|
279
|
+
border-bottom: 1px solid #edebe9;
|
|
280
|
+
box-shadow: 0 0.3px 0.9px rgba(0,0,0,0.108), 0 1.6px 3.6px rgba(0,0,0,0.132);
|
|
281
|
+
position: sticky;
|
|
282
|
+
top: 0;
|
|
283
|
+
z-index: 100;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.header-content {
|
|
287
|
+
max-width: 1600px;
|
|
288
|
+
margin: 0 auto;
|
|
289
|
+
padding: 0 24px;
|
|
290
|
+
display: flex;
|
|
291
|
+
align-items: center;
|
|
292
|
+
justify-content: space-between;
|
|
293
|
+
height: 48px;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.header-left {
|
|
297
|
+
display: flex;
|
|
298
|
+
align-items: center;
|
|
299
|
+
gap: 16px;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.logo {
|
|
303
|
+
width: 32px;
|
|
304
|
+
height: 32px;
|
|
305
|
+
background: linear-gradient(135deg, #0078d4, #106ebe);
|
|
306
|
+
border-radius: 6px;
|
|
307
|
+
display: flex;
|
|
308
|
+
align-items: center;
|
|
309
|
+
justify-content: center;
|
|
310
|
+
font-size: 18px;
|
|
31
311
|
}
|
|
32
312
|
|
|
33
313
|
.header h1 {
|
|
34
|
-
font-size:
|
|
314
|
+
font-size: 16px;
|
|
35
315
|
font-weight: 600;
|
|
36
|
-
|
|
316
|
+
color: #201f1e;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.header-right {
|
|
320
|
+
display: flex;
|
|
321
|
+
align-items: center;
|
|
322
|
+
gap: 12px;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.user-info {
|
|
326
|
+
display: flex;
|
|
327
|
+
align-items: center;
|
|
328
|
+
gap: 8px;
|
|
329
|
+
padding: 4px 12px 4px 4px;
|
|
330
|
+
background: #f3f2f1;
|
|
331
|
+
border-radius: 4px;
|
|
332
|
+
font-size: 13px;
|
|
333
|
+
color: #323130;
|
|
37
334
|
}
|
|
38
335
|
|
|
39
|
-
.
|
|
40
|
-
|
|
41
|
-
|
|
336
|
+
.user-avatar {
|
|
337
|
+
width: 24px;
|
|
338
|
+
height: 24px;
|
|
339
|
+
background: #0078d4;
|
|
340
|
+
color: white;
|
|
341
|
+
border-radius: 50%;
|
|
342
|
+
display: flex;
|
|
343
|
+
align-items: center;
|
|
344
|
+
justify-content: center;
|
|
345
|
+
font-size: 11px;
|
|
346
|
+
font-weight: 600;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.logout-btn {
|
|
350
|
+
background: transparent;
|
|
351
|
+
border: 1px solid #8a8886;
|
|
352
|
+
color: #323130;
|
|
353
|
+
padding: 6px 12px;
|
|
354
|
+
font-size: 13px;
|
|
355
|
+
border-radius: 2px;
|
|
356
|
+
cursor: pointer;
|
|
357
|
+
transition: all 0.1s ease;
|
|
358
|
+
font-family: 'Segoe UI', sans-serif;
|
|
359
|
+
font-weight: 600;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.logout-btn:hover {
|
|
363
|
+
background: #f3f2f1;
|
|
364
|
+
border-color: #323130;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.logout-btn:active {
|
|
368
|
+
background: #edebe9;
|
|
42
369
|
}
|
|
43
370
|
|
|
44
371
|
.container {
|
|
45
|
-
max-width:
|
|
372
|
+
max-width: 1600px;
|
|
46
373
|
margin: 0 auto;
|
|
47
|
-
padding:
|
|
374
|
+
padding: 24px;
|
|
48
375
|
}
|
|
49
376
|
|
|
377
|
+
/* Fluent Cards */
|
|
50
378
|
.stats-grid {
|
|
51
379
|
display: grid;
|
|
52
|
-
grid-template-columns: repeat(auto-fit, minmax(
|
|
53
|
-
gap:
|
|
54
|
-
margin-bottom:
|
|
380
|
+
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
|
381
|
+
gap: 16px;
|
|
382
|
+
margin-bottom: 24px;
|
|
55
383
|
}
|
|
56
384
|
|
|
57
385
|
.stat-card {
|
|
58
|
-
background:
|
|
59
|
-
border
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
386
|
+
background: #ffffff;
|
|
387
|
+
border: 1px solid #edebe9;
|
|
388
|
+
border-radius: 4px;
|
|
389
|
+
padding: 20px;
|
|
390
|
+
box-shadow: 0 0.3px 0.9px rgba(0,0,0,0.108), 0 1.6px 3.6px rgba(0,0,0,0.132);
|
|
391
|
+
transition: all 0.2s cubic-bezier(0.4, 0.0, 0.23, 1);
|
|
392
|
+
position: relative;
|
|
393
|
+
overflow: hidden;
|
|
63
394
|
}
|
|
64
395
|
|
|
65
396
|
.stat-card:hover {
|
|
66
397
|
transform: translateY(-2px);
|
|
67
|
-
box-shadow: 0
|
|
398
|
+
box-shadow: 0 3.2px 7.2px rgba(0,0,0,0.132), 0 0.6px 1.8px rgba(0,0,0,0.108);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.stat-card::before {
|
|
402
|
+
content: '';
|
|
403
|
+
position: absolute;
|
|
404
|
+
top: 0;
|
|
405
|
+
left: 0;
|
|
406
|
+
right: 0;
|
|
407
|
+
height: 3px;
|
|
408
|
+
background: #8a8886;
|
|
68
409
|
}
|
|
69
410
|
|
|
411
|
+
.stat-card.success::before { background: #107c10; }
|
|
412
|
+
.stat-card.warning::before { background: #faa900; }
|
|
413
|
+
.stat-card.danger::before { background: #d13438; }
|
|
414
|
+
.stat-card.info::before { background: #0078d4; }
|
|
415
|
+
|
|
70
416
|
.stat-label {
|
|
71
|
-
font-size:
|
|
72
|
-
color: #
|
|
417
|
+
font-size: 12px;
|
|
418
|
+
color: #605e5c;
|
|
73
419
|
text-transform: uppercase;
|
|
74
420
|
letter-spacing: 0.5px;
|
|
75
|
-
margin-bottom:
|
|
421
|
+
margin-bottom: 8px;
|
|
422
|
+
font-weight: 600;
|
|
76
423
|
}
|
|
77
424
|
|
|
78
425
|
.stat-value {
|
|
79
|
-
font-size:
|
|
80
|
-
font-weight:
|
|
81
|
-
color: #
|
|
426
|
+
font-size: 32px;
|
|
427
|
+
font-weight: 600;
|
|
428
|
+
color: #323130;
|
|
429
|
+
line-height: 1.2;
|
|
82
430
|
}
|
|
83
431
|
|
|
84
|
-
.stat-card.success .stat-value { color: #
|
|
85
|
-
.stat-card.warning .stat-value { color: #
|
|
86
|
-
.stat-card.danger .stat-value { color: #
|
|
87
|
-
.stat-card.info .stat-value { color: #
|
|
432
|
+
.stat-card.success .stat-value { color: #107c10; }
|
|
433
|
+
.stat-card.warning .stat-value { color: #f7630c; }
|
|
434
|
+
.stat-card.danger .stat-value { color: #d13438; }
|
|
435
|
+
.stat-card.info .stat-value { color: #0078d4; }
|
|
88
436
|
|
|
89
437
|
.section {
|
|
90
|
-
background:
|
|
91
|
-
border
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
438
|
+
background: #ffffff;
|
|
439
|
+
border: 1px solid #edebe9;
|
|
440
|
+
border-radius: 4px;
|
|
441
|
+
padding: 24px;
|
|
442
|
+
margin-bottom: 24px;
|
|
443
|
+
box-shadow: 0 0.3px 0.9px rgba(0,0,0,0.108), 0 1.6px 3.6px rgba(0,0,0,0.132);
|
|
95
444
|
}
|
|
96
445
|
|
|
97
446
|
.section-header {
|
|
98
447
|
display: flex;
|
|
99
448
|
justify-content: space-between;
|
|
100
449
|
align-items: center;
|
|
101
|
-
margin-bottom:
|
|
102
|
-
padding-bottom:
|
|
103
|
-
border-bottom:
|
|
450
|
+
margin-bottom: 20px;
|
|
451
|
+
padding-bottom: 16px;
|
|
452
|
+
border-bottom: 1px solid #edebe9;
|
|
104
453
|
}
|
|
105
454
|
|
|
106
455
|
.section-title {
|
|
107
|
-
font-size:
|
|
456
|
+
font-size: 20px;
|
|
108
457
|
font-weight: 600;
|
|
109
|
-
color: #
|
|
458
|
+
color: #323130;
|
|
110
459
|
}
|
|
111
460
|
|
|
461
|
+
/* Fluent Inputs */
|
|
112
462
|
.filters {
|
|
113
463
|
display: flex;
|
|
114
|
-
gap:
|
|
464
|
+
gap: 12px;
|
|
115
465
|
flex-wrap: wrap;
|
|
116
|
-
margin-bottom:
|
|
466
|
+
margin-bottom: 20px;
|
|
117
467
|
}
|
|
118
468
|
|
|
119
469
|
select, input {
|
|
120
|
-
padding:
|
|
121
|
-
border: 1px solid #
|
|
122
|
-
border-radius:
|
|
123
|
-
font-size:
|
|
470
|
+
padding: 7px 8px;
|
|
471
|
+
border: 1px solid #8a8886;
|
|
472
|
+
border-radius: 2px;
|
|
473
|
+
font-size: 14px;
|
|
124
474
|
background: white;
|
|
475
|
+
color: #323130;
|
|
125
476
|
cursor: pointer;
|
|
126
|
-
transition:
|
|
477
|
+
transition: all 0.15s ease;
|
|
478
|
+
font-family: 'Segoe UI', sans-serif;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
select:hover, input:hover {
|
|
482
|
+
border-color: #323130;
|
|
127
483
|
}
|
|
128
484
|
|
|
129
|
-
select:
|
|
130
|
-
border-color: #667eea;
|
|
485
|
+
select:focus, input:focus {
|
|
131
486
|
outline: none;
|
|
487
|
+
border-color: #0078d4;
|
|
488
|
+
box-shadow: 0 0 0 1px #0078d4;
|
|
132
489
|
}
|
|
133
490
|
|
|
491
|
+
/* Fluent Buttons */
|
|
134
492
|
.btn {
|
|
135
|
-
padding:
|
|
136
|
-
border:
|
|
137
|
-
border-radius:
|
|
138
|
-
font-size:
|
|
493
|
+
padding: 7px 16px;
|
|
494
|
+
border: 1px solid #8a8886;
|
|
495
|
+
border-radius: 2px;
|
|
496
|
+
font-size: 14px;
|
|
497
|
+
font-weight: 600;
|
|
139
498
|
cursor: pointer;
|
|
140
|
-
transition: all 0.
|
|
141
|
-
font-
|
|
499
|
+
transition: all 0.1s ease;
|
|
500
|
+
font-family: 'Segoe UI', sans-serif;
|
|
501
|
+
background: white;
|
|
502
|
+
color: #323130;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.btn:hover {
|
|
506
|
+
background: #f3f2f1;
|
|
507
|
+
border-color: #323130;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.btn:active {
|
|
511
|
+
background: #edebe9;
|
|
142
512
|
}
|
|
143
513
|
|
|
144
514
|
.btn-primary {
|
|
145
|
-
background: #
|
|
515
|
+
background: #0078d4;
|
|
516
|
+
border-color: #0078d4;
|
|
146
517
|
color: white;
|
|
147
518
|
}
|
|
148
519
|
|
|
149
520
|
.btn-primary:hover {
|
|
150
|
-
background: #
|
|
521
|
+
background: #106ebe;
|
|
522
|
+
border-color: #106ebe;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.btn-primary:active {
|
|
526
|
+
background: #005a9e;
|
|
151
527
|
}
|
|
152
528
|
|
|
153
529
|
.btn-danger {
|
|
154
|
-
background: #
|
|
530
|
+
background: #d13438;
|
|
531
|
+
border-color: #d13438;
|
|
155
532
|
color: white;
|
|
156
533
|
}
|
|
157
534
|
|
|
158
535
|
.btn-danger:hover {
|
|
159
|
-
background: #
|
|
536
|
+
background: #a4262c;
|
|
537
|
+
border-color: #a4262c;
|
|
160
538
|
}
|
|
161
539
|
|
|
162
540
|
.btn-success {
|
|
163
|
-
background: #
|
|
541
|
+
background: #107c10;
|
|
542
|
+
border-color: #107c10;
|
|
164
543
|
color: white;
|
|
165
544
|
}
|
|
166
545
|
|
|
167
546
|
.btn-success:hover {
|
|
168
|
-
background: #
|
|
547
|
+
background: #0b6a0b;
|
|
548
|
+
border-color: #0b6a0b;
|
|
169
549
|
}
|
|
170
550
|
|
|
171
551
|
.btn-small {
|
|
172
|
-
padding:
|
|
173
|
-
font-size:
|
|
552
|
+
padding: 5px 12px;
|
|
553
|
+
font-size: 13px;
|
|
174
554
|
}
|
|
175
555
|
|
|
556
|
+
/* Modern Table */
|
|
176
557
|
.table-container {
|
|
177
558
|
overflow-x: auto;
|
|
559
|
+
border-radius: 4px;
|
|
178
560
|
}
|
|
179
561
|
|
|
180
562
|
table {
|
|
@@ -183,108 +565,117 @@ function getDashboardHTML(options) {
|
|
|
183
565
|
}
|
|
184
566
|
|
|
185
567
|
th {
|
|
186
|
-
background: #
|
|
187
|
-
padding:
|
|
568
|
+
background: #f3f2f1;
|
|
569
|
+
padding: 12px 16px;
|
|
188
570
|
text-align: left;
|
|
189
571
|
font-weight: 600;
|
|
190
|
-
color: #
|
|
191
|
-
border-bottom:
|
|
192
|
-
font-size:
|
|
193
|
-
text-transform:
|
|
194
|
-
letter-spacing: 0
|
|
572
|
+
color: #323130;
|
|
573
|
+
border-bottom: 1px solid #edebe9;
|
|
574
|
+
font-size: 13px;
|
|
575
|
+
text-transform: none;
|
|
576
|
+
letter-spacing: 0;
|
|
195
577
|
}
|
|
196
578
|
|
|
197
579
|
td {
|
|
198
|
-
padding:
|
|
199
|
-
border-bottom: 1px solid #
|
|
580
|
+
padding: 12px 16px;
|
|
581
|
+
border-bottom: 1px solid #edebe9;
|
|
582
|
+
font-size: 13px;
|
|
200
583
|
}
|
|
201
584
|
|
|
202
585
|
tr:hover {
|
|
203
|
-
background: #
|
|
586
|
+
background: #faf9f8;
|
|
204
587
|
}
|
|
205
588
|
|
|
589
|
+
tr:last-child td {
|
|
590
|
+
border-bottom: none;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/* Fluent Badges */
|
|
206
594
|
.badge {
|
|
207
595
|
display: inline-block;
|
|
208
|
-
padding:
|
|
209
|
-
border-radius:
|
|
210
|
-
font-size:
|
|
596
|
+
padding: 4px 8px;
|
|
597
|
+
border-radius: 2px;
|
|
598
|
+
font-size: 12px;
|
|
211
599
|
font-weight: 600;
|
|
212
|
-
text-transform:
|
|
213
|
-
letter-spacing: 0.5px;
|
|
600
|
+
text-transform: capitalize;
|
|
214
601
|
}
|
|
215
602
|
|
|
216
|
-
.badge-success { background: #
|
|
217
|
-
.badge-warning { background: #
|
|
218
|
-
.badge-danger { background: #
|
|
219
|
-
.badge-info { background: #
|
|
603
|
+
.badge-success { background: #dff6dd; color: #107c10; }
|
|
604
|
+
.badge-warning { background: #fff4ce; color: #8a5500; }
|
|
605
|
+
.badge-danger { background: #fde7e9; color: #a4262c; }
|
|
606
|
+
.badge-info { background: #deecf9; color: #004e8c; }
|
|
220
607
|
|
|
608
|
+
/* Charts */
|
|
221
609
|
.chart-container {
|
|
222
610
|
display: grid;
|
|
223
|
-
grid-template-columns: repeat(auto-fit, minmax(
|
|
224
|
-
gap:
|
|
225
|
-
margin-top:
|
|
611
|
+
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
|
612
|
+
gap: 24px;
|
|
613
|
+
margin-top: 20px;
|
|
226
614
|
}
|
|
227
615
|
|
|
228
616
|
.chart {
|
|
229
|
-
background: #
|
|
230
|
-
padding:
|
|
231
|
-
border-radius:
|
|
617
|
+
background: #faf9f8;
|
|
618
|
+
padding: 20px;
|
|
619
|
+
border-radius: 4px;
|
|
620
|
+
border: 1px solid #edebe9;
|
|
232
621
|
}
|
|
233
622
|
|
|
234
623
|
.chart-title {
|
|
235
624
|
font-weight: 600;
|
|
236
|
-
margin-bottom:
|
|
237
|
-
color: #
|
|
625
|
+
margin-bottom: 16px;
|
|
626
|
+
color: #323130;
|
|
627
|
+
font-size: 14px;
|
|
238
628
|
}
|
|
239
629
|
|
|
240
630
|
.chart-bar {
|
|
241
631
|
display: flex;
|
|
242
632
|
align-items: center;
|
|
243
|
-
margin-bottom:
|
|
633
|
+
margin-bottom: 12px;
|
|
244
634
|
}
|
|
245
635
|
|
|
246
636
|
.chart-label {
|
|
247
637
|
min-width: 120px;
|
|
248
|
-
font-size:
|
|
249
|
-
color: #
|
|
638
|
+
font-size: 13px;
|
|
639
|
+
color: #605e5c;
|
|
250
640
|
}
|
|
251
641
|
|
|
252
642
|
.chart-bar-bg {
|
|
253
643
|
flex: 1;
|
|
254
|
-
height:
|
|
255
|
-
background: #
|
|
256
|
-
border-radius:
|
|
644
|
+
height: 28px;
|
|
645
|
+
background: #edebe9;
|
|
646
|
+
border-radius: 2px;
|
|
257
647
|
overflow: hidden;
|
|
258
648
|
position: relative;
|
|
259
649
|
}
|
|
260
650
|
|
|
261
651
|
.chart-bar-fill {
|
|
262
652
|
height: 100%;
|
|
263
|
-
background: linear-gradient(90deg, #
|
|
653
|
+
background: linear-gradient(90deg, #0078d4, #106ebe);
|
|
264
654
|
transition: width 0.3s ease;
|
|
265
655
|
}
|
|
266
656
|
|
|
267
657
|
.chart-value {
|
|
268
|
-
margin-left:
|
|
658
|
+
margin-left: 12px;
|
|
269
659
|
font-weight: 600;
|
|
270
|
-
font-size:
|
|
660
|
+
font-size: 13px;
|
|
271
661
|
min-width: 40px;
|
|
662
|
+
color: #323130;
|
|
272
663
|
}
|
|
273
664
|
|
|
274
665
|
.loading {
|
|
275
666
|
text-align: center;
|
|
276
|
-
padding:
|
|
277
|
-
color: #
|
|
667
|
+
padding: 48px;
|
|
668
|
+
color: #605e5c;
|
|
278
669
|
}
|
|
279
670
|
|
|
280
671
|
.spinner {
|
|
281
|
-
border: 3px solid #
|
|
282
|
-
border-top: 3px solid #
|
|
672
|
+
border: 3px solid #edebe9;
|
|
673
|
+
border-top: 3px solid #0078d4;
|
|
283
674
|
border-radius: 50%;
|
|
284
675
|
width: 40px;
|
|
285
676
|
height: 40px;
|
|
286
677
|
animation: spin 1s linear infinite;
|
|
287
|
-
margin: 0 auto
|
|
678
|
+
margin: 0 auto 16px;
|
|
288
679
|
}
|
|
289
680
|
|
|
290
681
|
@keyframes spin {
|
|
@@ -293,49 +684,49 @@ function getDashboardHTML(options) {
|
|
|
293
684
|
}
|
|
294
685
|
|
|
295
686
|
.error {
|
|
296
|
-
background: #
|
|
297
|
-
color: #
|
|
298
|
-
padding:
|
|
299
|
-
border-radius:
|
|
300
|
-
border-left:
|
|
687
|
+
background: #fde7e9;
|
|
688
|
+
color: #a4262c;
|
|
689
|
+
padding: 16px;
|
|
690
|
+
border-radius: 4px;
|
|
691
|
+
border-left: 3px solid #d13438;
|
|
301
692
|
}
|
|
302
693
|
|
|
303
694
|
.empty-state {
|
|
304
695
|
text-align: center;
|
|
305
|
-
padding:
|
|
306
|
-
color: #
|
|
696
|
+
padding: 48px;
|
|
697
|
+
color: #605e5c;
|
|
307
698
|
}
|
|
308
699
|
|
|
309
700
|
.empty-state-icon {
|
|
310
|
-
font-size:
|
|
311
|
-
margin-bottom:
|
|
312
|
-
opacity: 0.
|
|
701
|
+
font-size: 48px;
|
|
702
|
+
margin-bottom: 16px;
|
|
703
|
+
opacity: 0.5;
|
|
313
704
|
}
|
|
314
705
|
|
|
315
706
|
.pagination {
|
|
316
707
|
display: flex;
|
|
317
708
|
justify-content: center;
|
|
318
709
|
align-items: center;
|
|
319
|
-
gap:
|
|
320
|
-
margin-top:
|
|
710
|
+
gap: 12px;
|
|
711
|
+
margin-top: 24px;
|
|
321
712
|
}
|
|
322
713
|
|
|
323
714
|
.pagination button {
|
|
324
|
-
padding:
|
|
715
|
+
padding: 7px 16px;
|
|
325
716
|
}
|
|
326
717
|
|
|
327
718
|
.pagination span {
|
|
328
|
-
color: #
|
|
329
|
-
font-size:
|
|
719
|
+
color: #605e5c;
|
|
720
|
+
font-size: 13px;
|
|
330
721
|
}
|
|
331
722
|
|
|
332
723
|
code {
|
|
333
|
-
background: #
|
|
334
|
-
padding:
|
|
335
|
-
border-radius:
|
|
336
|
-
font-family: '
|
|
337
|
-
font-size:
|
|
338
|
-
color: #
|
|
724
|
+
background: #f3f2f1;
|
|
725
|
+
padding: 2px 6px;
|
|
726
|
+
border-radius: 2px;
|
|
727
|
+
font-family: 'Consolas', 'Monaco', monospace;
|
|
728
|
+
font-size: 12px;
|
|
729
|
+
color: #d13438;
|
|
339
730
|
}
|
|
340
731
|
|
|
341
732
|
.job-args {
|
|
@@ -343,8 +734,143 @@ function getDashboardHTML(options) {
|
|
|
343
734
|
overflow: hidden;
|
|
344
735
|
text-overflow: ellipsis;
|
|
345
736
|
white-space: nowrap;
|
|
346
|
-
font-family: '
|
|
347
|
-
font-size:
|
|
737
|
+
font-family: 'Consolas', 'Monaco', monospace;
|
|
738
|
+
font-size: 12px;
|
|
739
|
+
cursor: pointer;
|
|
740
|
+
padding: 4px 8px;
|
|
741
|
+
border-radius: 2px;
|
|
742
|
+
transition: background 0.1s ease;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
.job-args:hover {
|
|
746
|
+
background: #deecf9;
|
|
747
|
+
color: #004e8c;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
/* Args Modal */
|
|
751
|
+
.modal-overlay {
|
|
752
|
+
display: none;
|
|
753
|
+
position: fixed;
|
|
754
|
+
inset: 0;
|
|
755
|
+
background: rgba(0,0,0,0.4);
|
|
756
|
+
z-index: 200;
|
|
757
|
+
align-items: center;
|
|
758
|
+
justify-content: center;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
.modal-overlay.active {
|
|
762
|
+
display: flex;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
.modal {
|
|
766
|
+
background: #ffffff;
|
|
767
|
+
border-radius: 4px;
|
|
768
|
+
box-shadow: 0 25.6px 57.6px rgba(0,0,0,0.22), 0 4.8px 14.4px rgba(0,0,0,0.18);
|
|
769
|
+
width: 90%;
|
|
770
|
+
max-width: 640px;
|
|
771
|
+
max-height: 80vh;
|
|
772
|
+
display: flex;
|
|
773
|
+
flex-direction: column;
|
|
774
|
+
animation: modalIn 0.15s ease;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
@keyframes modalIn {
|
|
778
|
+
from { opacity: 0; transform: scale(0.95); }
|
|
779
|
+
to { opacity: 1; transform: scale(1); }
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
.modal-header {
|
|
783
|
+
display: flex;
|
|
784
|
+
justify-content: space-between;
|
|
785
|
+
align-items: center;
|
|
786
|
+
padding: 16px 24px;
|
|
787
|
+
border-bottom: 1px solid #edebe9;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
.modal-title {
|
|
791
|
+
font-size: 18px;
|
|
792
|
+
font-weight: 600;
|
|
793
|
+
color: #323130;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
.modal-close {
|
|
797
|
+
background: none;
|
|
798
|
+
border: none;
|
|
799
|
+
font-size: 20px;
|
|
800
|
+
cursor: pointer;
|
|
801
|
+
color: #605e5c;
|
|
802
|
+
padding: 4px 8px;
|
|
803
|
+
border-radius: 2px;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
.modal-close:hover {
|
|
807
|
+
background: #f3f2f1;
|
|
808
|
+
color: #201f1e;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
.modal-body {
|
|
812
|
+
padding: 24px;
|
|
813
|
+
overflow-y: auto;
|
|
814
|
+
flex: 1;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
.modal-footer {
|
|
818
|
+
display: flex;
|
|
819
|
+
justify-content: flex-end;
|
|
820
|
+
gap: 8px;
|
|
821
|
+
padding: 16px 24px;
|
|
822
|
+
border-top: 1px solid #edebe9;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
.args-viewer {
|
|
826
|
+
background: #1e1e1e;
|
|
827
|
+
color: #d4d4d4;
|
|
828
|
+
padding: 16px;
|
|
829
|
+
border-radius: 4px;
|
|
830
|
+
font-family: 'Consolas', 'Monaco', monospace;
|
|
831
|
+
font-size: 13px;
|
|
832
|
+
white-space: pre-wrap;
|
|
833
|
+
word-break: break-word;
|
|
834
|
+
line-height: 1.5;
|
|
835
|
+
max-height: 300px;
|
|
836
|
+
overflow-y: auto;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
.args-editor {
|
|
840
|
+
width: 100%;
|
|
841
|
+
min-height: 200px;
|
|
842
|
+
background: #1e1e1e;
|
|
843
|
+
color: #d4d4d4;
|
|
844
|
+
padding: 16px;
|
|
845
|
+
border-radius: 4px;
|
|
846
|
+
border: 2px solid #0078d4;
|
|
847
|
+
font-family: 'Consolas', 'Monaco', monospace;
|
|
848
|
+
font-size: 13px;
|
|
849
|
+
line-height: 1.5;
|
|
850
|
+
resize: vertical;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
.args-editor:focus {
|
|
854
|
+
outline: none;
|
|
855
|
+
border-color: #106ebe;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
.args-error {
|
|
859
|
+
color: #d13438;
|
|
860
|
+
font-size: 12px;
|
|
861
|
+
margin-top: 8px;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
.copy-feedback {
|
|
865
|
+
color: #107c10;
|
|
866
|
+
font-size: 12px;
|
|
867
|
+
margin-left: 8px;
|
|
868
|
+
opacity: 0;
|
|
869
|
+
transition: opacity 0.2s ease;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
.copy-feedback.show {
|
|
873
|
+
opacity: 1;
|
|
348
874
|
}
|
|
349
875
|
|
|
350
876
|
.error-message {
|
|
@@ -352,8 +878,8 @@ function getDashboardHTML(options) {
|
|
|
352
878
|
overflow: hidden;
|
|
353
879
|
text-overflow: ellipsis;
|
|
354
880
|
white-space: nowrap;
|
|
355
|
-
color: #
|
|
356
|
-
font-size:
|
|
881
|
+
color: #d13438;
|
|
882
|
+
font-size: 12px;
|
|
357
883
|
}
|
|
358
884
|
|
|
359
885
|
.refresh-indicator {
|
|
@@ -361,8 +887,7 @@ function getDashboardHTML(options) {
|
|
|
361
887
|
width: 8px;
|
|
362
888
|
height: 8px;
|
|
363
889
|
border-radius: 50%;
|
|
364
|
-
background: #
|
|
365
|
-
margin-left: 0.5rem;
|
|
890
|
+
background: #107c10;
|
|
366
891
|
animation: pulse 2s infinite;
|
|
367
892
|
}
|
|
368
893
|
|
|
@@ -373,14 +898,29 @@ function getDashboardHTML(options) {
|
|
|
373
898
|
|
|
374
899
|
.actions {
|
|
375
900
|
display: flex;
|
|
376
|
-
gap:
|
|
901
|
+
gap: 8px;
|
|
377
902
|
}
|
|
378
903
|
</style>
|
|
379
904
|
</head>
|
|
380
905
|
<body>
|
|
381
906
|
<div class="header">
|
|
382
|
-
<
|
|
383
|
-
|
|
907
|
+
<div class="header-content">
|
|
908
|
+
<div class="header-left">
|
|
909
|
+
<div class="logo">📊</div>
|
|
910
|
+
<h1>${options.title}</h1>
|
|
911
|
+
</div>
|
|
912
|
+
<div class="header-right">
|
|
913
|
+
${userEmail ? `
|
|
914
|
+
<div class="user-info">
|
|
915
|
+
<div class="user-avatar">${userEmail.charAt(0).toUpperCase()}</div>
|
|
916
|
+
<span>${userEmail}</span>
|
|
917
|
+
</div>
|
|
918
|
+
` : ''}
|
|
919
|
+
<form method="POST" action="${options.basePath}/logout" style="display: inline;">
|
|
920
|
+
<button type="submit" class="logout-btn">Sign out</button>
|
|
921
|
+
</form>
|
|
922
|
+
</div>
|
|
923
|
+
</div>
|
|
384
924
|
</div>
|
|
385
925
|
|
|
386
926
|
<div class="container">
|
|
@@ -408,6 +948,7 @@ function getDashboardHTML(options) {
|
|
|
408
948
|
<div class="section">
|
|
409
949
|
<div class="section-header">
|
|
410
950
|
<h2 class="section-title">Analytics</h2>
|
|
951
|
+
<span class="refresh-indicator"></span>
|
|
411
952
|
</div>
|
|
412
953
|
<div class="chart-container">
|
|
413
954
|
<div class="chart">
|
|
@@ -465,10 +1006,38 @@ function getDashboardHTML(options) {
|
|
|
465
1006
|
</div>
|
|
466
1007
|
</div>
|
|
467
1008
|
|
|
1009
|
+
<!-- Args Modal -->
|
|
1010
|
+
<div class="modal-overlay" id="args-modal">
|
|
1011
|
+
<div class="modal">
|
|
1012
|
+
<div class="modal-header">
|
|
1013
|
+
<span class="modal-title" id="args-modal-title">Job Arguments</span>
|
|
1014
|
+
<button class="modal-close" onclick="closeArgsModal()">×</button>
|
|
1015
|
+
</div>
|
|
1016
|
+
<div class="modal-body">
|
|
1017
|
+
<div id="args-view-mode">
|
|
1018
|
+
<pre class="args-viewer" id="args-content"></pre>
|
|
1019
|
+
</div>
|
|
1020
|
+
<div id="args-edit-mode" style="display:none">
|
|
1021
|
+
<textarea class="args-editor" id="args-editor"></textarea>
|
|
1022
|
+
<div class="args-error" id="args-error"></div>
|
|
1023
|
+
</div>
|
|
1024
|
+
</div>
|
|
1025
|
+
<div class="modal-footer">
|
|
1026
|
+
<span class="copy-feedback" id="copy-feedback">Copied!</span>
|
|
1027
|
+
<button class="btn" id="btn-copy" onclick="copyArgs()">Copy</button>
|
|
1028
|
+
<button class="btn" id="btn-edit" onclick="enterEditMode()">Edit</button>
|
|
1029
|
+
<button class="btn btn-primary" id="btn-save" style="display:none" onclick="saveArgs()">Save</button>
|
|
1030
|
+
<button class="btn" id="btn-cancel-edit" style="display:none" onclick="cancelEdit()">Cancel</button>
|
|
1031
|
+
</div>
|
|
1032
|
+
</div>
|
|
1033
|
+
</div>
|
|
1034
|
+
|
|
468
1035
|
<script>
|
|
469
1036
|
const REFRESH_INTERVAL = ${options.refreshInterval};
|
|
470
1037
|
let currentPage = 0;
|
|
471
1038
|
const pageSize = 50;
|
|
1039
|
+
let currentModalJobId = null;
|
|
1040
|
+
let currentModalArgs = null;
|
|
472
1041
|
|
|
473
1042
|
// Load initial data
|
|
474
1043
|
loadStats();
|
|
@@ -629,7 +1198,7 @@ function getDashboardHTML(options) {
|
|
|
629
1198
|
<td><span class="badge badge-\${statusBadge}">\${status}</span></td>
|
|
630
1199
|
<td>\${formatDate(runAt)}</td>
|
|
631
1200
|
<td>\${job.errorCount > 0 ? '<span class="badge badge-danger">' + job.errorCount + '</span>' : '-'}</td>
|
|
632
|
-
<td class="job-args">\${escapeHtml(JSON.stringify(job.args))}</td>
|
|
1201
|
+
<td class="job-args" data-job-id="\${job.id}" data-args="\${escapeAttr(JSON.stringify(job.args))}" onclick="openArgsFromEl(this)" title="Click to view/edit">\${escapeHtml(JSON.stringify(job.args))}</td>
|
|
633
1202
|
<td>
|
|
634
1203
|
<div class="actions">
|
|
635
1204
|
\${job.errorCount > 0 ?
|
|
@@ -645,9 +1214,9 @@ function getDashboardHTML(options) {
|
|
|
645
1214
|
</table>
|
|
646
1215
|
</div>
|
|
647
1216
|
<div class="pagination">
|
|
648
|
-
<button class="btn
|
|
1217
|
+
<button class="btn" onclick="previousPage()" \${currentPage === 0 ? 'disabled' : ''}>Previous</button>
|
|
649
1218
|
<span>Page \${currentPage + 1} of \${Math.ceil(total / pageSize)}</span>
|
|
650
|
-
<button class="btn
|
|
1219
|
+
<button class="btn" onclick="nextPage()" \${(currentPage + 1) * pageSize >= total ? 'disabled' : ''}>Next</button>
|
|
651
1220
|
</div>
|
|
652
1221
|
\`;
|
|
653
1222
|
|
|
@@ -778,6 +1347,115 @@ function getDashboardHTML(options) {
|
|
|
778
1347
|
div.textContent = text;
|
|
779
1348
|
return div.innerHTML;
|
|
780
1349
|
}
|
|
1350
|
+
|
|
1351
|
+
function escapeAttr(text) {
|
|
1352
|
+
return text.replace(/&/g, '&').replace(/'/g, ''').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
function openArgsFromEl(el) {
|
|
1356
|
+
var jobId = parseInt(el.getAttribute('data-job-id'));
|
|
1357
|
+
var args = JSON.parse(el.getAttribute('data-args'));
|
|
1358
|
+
openArgsModal(jobId, args);
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
function openArgsModal(jobId, args) {
|
|
1362
|
+
currentModalJobId = jobId;
|
|
1363
|
+
currentModalArgs = args;
|
|
1364
|
+
document.getElementById('args-modal-title').textContent = 'Job #' + jobId + ' Arguments';
|
|
1365
|
+
document.getElementById('args-content').textContent = JSON.stringify(args, null, 2);
|
|
1366
|
+
document.getElementById('args-view-mode').style.display = '';
|
|
1367
|
+
document.getElementById('args-edit-mode').style.display = 'none';
|
|
1368
|
+
document.getElementById('btn-copy').style.display = '';
|
|
1369
|
+
document.getElementById('btn-edit').style.display = '';
|
|
1370
|
+
document.getElementById('btn-save').style.display = 'none';
|
|
1371
|
+
document.getElementById('btn-cancel-edit').style.display = 'none';
|
|
1372
|
+
document.getElementById('args-error').textContent = '';
|
|
1373
|
+
document.getElementById('args-modal').classList.add('active');
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
function closeArgsModal() {
|
|
1377
|
+
document.getElementById('args-modal').classList.remove('active');
|
|
1378
|
+
currentModalJobId = null;
|
|
1379
|
+
currentModalArgs = null;
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
function copyArgs() {
|
|
1383
|
+
const text = JSON.stringify(currentModalArgs, null, 2);
|
|
1384
|
+
navigator.clipboard.writeText(text).then(function() {
|
|
1385
|
+
var fb = document.getElementById('copy-feedback');
|
|
1386
|
+
fb.classList.add('show');
|
|
1387
|
+
setTimeout(function() { fb.classList.remove('show'); }, 1500);
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
function enterEditMode() {
|
|
1392
|
+
document.getElementById('args-view-mode').style.display = 'none';
|
|
1393
|
+
document.getElementById('args-edit-mode').style.display = '';
|
|
1394
|
+
document.getElementById('args-editor').value = JSON.stringify(currentModalArgs, null, 2);
|
|
1395
|
+
document.getElementById('btn-copy').style.display = 'none';
|
|
1396
|
+
document.getElementById('btn-edit').style.display = 'none';
|
|
1397
|
+
document.getElementById('btn-save').style.display = '';
|
|
1398
|
+
document.getElementById('btn-cancel-edit').style.display = '';
|
|
1399
|
+
document.getElementById('args-error').textContent = '';
|
|
1400
|
+
document.getElementById('args-editor').focus();
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
function cancelEdit() {
|
|
1404
|
+
document.getElementById('args-view-mode').style.display = '';
|
|
1405
|
+
document.getElementById('args-edit-mode').style.display = 'none';
|
|
1406
|
+
document.getElementById('btn-copy').style.display = '';
|
|
1407
|
+
document.getElementById('btn-edit').style.display = '';
|
|
1408
|
+
document.getElementById('btn-save').style.display = 'none';
|
|
1409
|
+
document.getElementById('btn-cancel-edit').style.display = 'none';
|
|
1410
|
+
document.getElementById('args-error').textContent = '';
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
async function saveArgs() {
|
|
1414
|
+
var raw = document.getElementById('args-editor').value;
|
|
1415
|
+
var parsed;
|
|
1416
|
+
try {
|
|
1417
|
+
parsed = JSON.parse(raw);
|
|
1418
|
+
} catch (e) {
|
|
1419
|
+
document.getElementById('args-error').textContent = 'Invalid JSON: ' + e.message;
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
if (!Array.isArray(parsed)) {
|
|
1424
|
+
document.getElementById('args-error').textContent = 'Arguments must be a JSON array.';
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
try {
|
|
1429
|
+
var response = await fetch(\`${options.basePath}/api/jobs/\${currentModalJobId}/args\`, {
|
|
1430
|
+
method: 'PUT',
|
|
1431
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1432
|
+
body: JSON.stringify({ args: parsed })
|
|
1433
|
+
});
|
|
1434
|
+
|
|
1435
|
+
if (response.ok) {
|
|
1436
|
+
currentModalArgs = parsed;
|
|
1437
|
+
document.getElementById('args-content').textContent = JSON.stringify(parsed, null, 2);
|
|
1438
|
+
cancelEdit();
|
|
1439
|
+
loadJobs();
|
|
1440
|
+
loadStats();
|
|
1441
|
+
} else {
|
|
1442
|
+
var data = await response.json();
|
|
1443
|
+
document.getElementById('args-error').textContent = data.error || 'Failed to update arguments.';
|
|
1444
|
+
}
|
|
1445
|
+
} catch (error) {
|
|
1446
|
+
document.getElementById('args-error').textContent = 'Network error. Please try again.';
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
// Close modal on overlay click
|
|
1451
|
+
document.getElementById('args-modal').addEventListener('click', function(e) {
|
|
1452
|
+
if (e.target === this) closeArgsModal();
|
|
1453
|
+
});
|
|
1454
|
+
|
|
1455
|
+
// Close modal on Escape key
|
|
1456
|
+
document.addEventListener('keydown', function(e) {
|
|
1457
|
+
if (e.key === 'Escape') closeArgsModal();
|
|
1458
|
+
});
|
|
781
1459
|
</script>
|
|
782
1460
|
</body>
|
|
783
1461
|
</html>
|