@nbakka/mcp-appium 2.0.99 → 3.0.1
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/lib/server.js +493 -215
- package/package.json +1 -1
- package/lib/review-ui/index.html +0 -774
- package/lib/review-ui/script.js +0 -176
- package/lib/review-ui/styles.css +0 -244
package/lib/review-ui/index.html
DELETED
|
@@ -1,774 +0,0 @@
|
|
|
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>Test Case Review & Approval</title>
|
|
7
|
-
<style>
|
|
8
|
-
* {
|
|
9
|
-
box-sizing: border-box;
|
|
10
|
-
margin: 0;
|
|
11
|
-
padding: 0;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
body {
|
|
15
|
-
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
16
|
-
background-color: #f8f9fa;
|
|
17
|
-
line-height: 1.6;
|
|
18
|
-
color: #333;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.container {
|
|
22
|
-
max-width: 1400px;
|
|
23
|
-
margin: 0 auto;
|
|
24
|
-
padding: 20px;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.header {
|
|
28
|
-
text-align: center;
|
|
29
|
-
margin-bottom: 30px;
|
|
30
|
-
padding: 20px;
|
|
31
|
-
background: white;
|
|
32
|
-
border-radius: 10px;
|
|
33
|
-
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.header h1 {
|
|
37
|
-
color: #2c3e50;
|
|
38
|
-
margin-bottom: 10px;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.session-info {
|
|
42
|
-
color: #7f8c8d;
|
|
43
|
-
font-size: 14px;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
.section {
|
|
47
|
-
margin-bottom: 30px;
|
|
48
|
-
background: white;
|
|
49
|
-
border-radius: 10px;
|
|
50
|
-
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
51
|
-
overflow: hidden;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.section-header {
|
|
55
|
-
padding: 20px;
|
|
56
|
-
font-weight: bold;
|
|
57
|
-
font-size: 18px;
|
|
58
|
-
border-bottom: 3px solid;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.new-section .section-header {
|
|
62
|
-
background-color: #d4edda;
|
|
63
|
-
color: #155724;
|
|
64
|
-
border-bottom-color: #28a745;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.modify-section .section-header {
|
|
68
|
-
background-color: #fff3cd;
|
|
69
|
-
color: #856404;
|
|
70
|
-
border-bottom-color: #ffc107;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.remove-section .section-header {
|
|
74
|
-
background-color: #f8d7da;
|
|
75
|
-
color: #721c24;
|
|
76
|
-
border-bottom-color: #dc3545;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.section-content {
|
|
80
|
-
padding: 20px;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
.test-case {
|
|
84
|
-
border: 1px solid #e9ecef;
|
|
85
|
-
border-radius: 8px;
|
|
86
|
-
margin-bottom: 15px;
|
|
87
|
-
background: #f8f9fa;
|
|
88
|
-
transition: all 0.3s ease;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
.test-case:hover {
|
|
92
|
-
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
.test-case-header {
|
|
96
|
-
padding: 15px;
|
|
97
|
-
background: white;
|
|
98
|
-
border-bottom: 1px solid #e9ecef;
|
|
99
|
-
display: flex;
|
|
100
|
-
justify-content: space-between;
|
|
101
|
-
align-items: center;
|
|
102
|
-
border-radius: 8px 8px 0 0;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
.test-case-id {
|
|
106
|
-
font-family: 'Courier New', monospace;
|
|
107
|
-
background: #e9ecef;
|
|
108
|
-
padding: 4px 8px;
|
|
109
|
-
border-radius: 4px;
|
|
110
|
-
font-size: 12px;
|
|
111
|
-
color: #495057;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
.test-case-actions {
|
|
115
|
-
display: flex;
|
|
116
|
-
gap: 8px;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
.btn {
|
|
120
|
-
padding: 8px 16px;
|
|
121
|
-
border: none;
|
|
122
|
-
border-radius: 6px;
|
|
123
|
-
cursor: pointer;
|
|
124
|
-
font-size: 13px;
|
|
125
|
-
font-weight: 500;
|
|
126
|
-
transition: all 0.2s ease;
|
|
127
|
-
text-transform: uppercase;
|
|
128
|
-
letter-spacing: 0.5px;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
.btn:hover {
|
|
132
|
-
transform: translateY(-1px);
|
|
133
|
-
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
.btn-edit {
|
|
137
|
-
background: #007bff;
|
|
138
|
-
color: white;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
.btn-edit:hover {
|
|
142
|
-
background: #0056b3;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
.btn-delete {
|
|
146
|
-
background: #dc3545;
|
|
147
|
-
color: white;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
.btn-delete:hover {
|
|
151
|
-
background: #c82333;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
.btn-save {
|
|
155
|
-
background: #28a745;
|
|
156
|
-
color: white;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
.btn-save:hover {
|
|
160
|
-
background: #218838;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
.btn-cancel {
|
|
164
|
-
background: #6c757d;
|
|
165
|
-
color: white;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
.btn-cancel:hover {
|
|
169
|
-
background: #545b62;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
.test-case-content {
|
|
173
|
-
padding: 15px;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
.original-text {
|
|
177
|
-
background: #f8d7da;
|
|
178
|
-
border: 1px solid #f1aeb5;
|
|
179
|
-
border-radius: 4px;
|
|
180
|
-
padding: 10px;
|
|
181
|
-
margin-bottom: 10px;
|
|
182
|
-
text-decoration: line-through;
|
|
183
|
-
color: #721c24;
|
|
184
|
-
font-style: italic;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
.modified-text {
|
|
188
|
-
background: #d1ecf1;
|
|
189
|
-
border: 1px solid #b8daff;
|
|
190
|
-
border-radius: 4px;
|
|
191
|
-
padding: 10px;
|
|
192
|
-
color: #0c5460;
|
|
193
|
-
font-weight: 500;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
.description-text {
|
|
197
|
-
background: #d4edda;
|
|
198
|
-
border: 1px solid #c3e6cb;
|
|
199
|
-
border-radius: 4px;
|
|
200
|
-
padding: 10px;
|
|
201
|
-
color: #155724;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
.remove-text {
|
|
205
|
-
background: #f8d7da;
|
|
206
|
-
border: 1px solid #f1aeb5;
|
|
207
|
-
border-radius: 4px;
|
|
208
|
-
padding: 10px;
|
|
209
|
-
color: #721c24;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
.edit-form {
|
|
213
|
-
background: #e9ecef;
|
|
214
|
-
border-radius: 6px;
|
|
215
|
-
padding: 15px;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
.form-group {
|
|
219
|
-
margin-bottom: 15px;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.form-label {
|
|
223
|
-
display: block;
|
|
224
|
-
margin-bottom: 5px;
|
|
225
|
-
font-weight: 600;
|
|
226
|
-
color: #495057;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
.form-control {
|
|
230
|
-
width: 100%;
|
|
231
|
-
padding: 10px;
|
|
232
|
-
border: 2px solid #ced4da;
|
|
233
|
-
border-radius: 6px;
|
|
234
|
-
font-family: inherit;
|
|
235
|
-
font-size: 14px;
|
|
236
|
-
resize: vertical;
|
|
237
|
-
min-height: 80px;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
.form-control:focus {
|
|
241
|
-
outline: none;
|
|
242
|
-
border-color: #007bff;
|
|
243
|
-
box-shadow: 0 0 0 3px rgba(0,123,255,0.1);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
.form-control[readonly] {
|
|
247
|
-
background-color: #f8f9fa;
|
|
248
|
-
cursor: not-allowed;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
.empty-section {
|
|
252
|
-
text-align: center;
|
|
253
|
-
padding: 40px;
|
|
254
|
-
color: #6c757d;
|
|
255
|
-
font-style: italic;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
.approval-section {
|
|
259
|
-
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
260
|
-
color: white;
|
|
261
|
-
text-align: center;
|
|
262
|
-
padding: 30px;
|
|
263
|
-
border-radius: 10px;
|
|
264
|
-
margin-top: 30px;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
.approval-buttons {
|
|
268
|
-
display: flex;
|
|
269
|
-
justify-content: center;
|
|
270
|
-
gap: 20px;
|
|
271
|
-
margin-top: 20px;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
.btn-primary {
|
|
275
|
-
background: #28a745;
|
|
276
|
-
color: white;
|
|
277
|
-
padding: 15px 30px;
|
|
278
|
-
font-size: 16px;
|
|
279
|
-
font-weight: bold;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
.btn-primary:hover {
|
|
283
|
-
background: #218838;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
.btn-danger {
|
|
287
|
-
background: #dc3545;
|
|
288
|
-
color: white;
|
|
289
|
-
padding: 15px 30px;
|
|
290
|
-
font-size: 16px;
|
|
291
|
-
font-weight: bold;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
.btn-danger:hover {
|
|
295
|
-
background: #c82333;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
.status-message {
|
|
299
|
-
margin-top: 20px;
|
|
300
|
-
padding: 15px;
|
|
301
|
-
border-radius: 6px;
|
|
302
|
-
font-weight: 500;
|
|
303
|
-
text-align: center;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
.status-success {
|
|
307
|
-
background: #d4edda;
|
|
308
|
-
color: #155724;
|
|
309
|
-
border: 1px solid #c3e6cb;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
.status-error {
|
|
313
|
-
background: #f8d7da;
|
|
314
|
-
color: #721c24;
|
|
315
|
-
border: 1px solid #f1aeb5;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
.status-info {
|
|
319
|
-
background: #d1ecf1;
|
|
320
|
-
color: #0c5460;
|
|
321
|
-
border: 1px solid #b8daff;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
.loading {
|
|
325
|
-
text-align: center;
|
|
326
|
-
padding: 60px;
|
|
327
|
-
font-size: 18px;
|
|
328
|
-
color: #6c757d;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
.loading::after {
|
|
332
|
-
content: '...';
|
|
333
|
-
animation: dots 1.5s steps(5, end) infinite;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
@keyframes dots {
|
|
337
|
-
0%, 20% { color: rgba(0,0,0,0); text-shadow: .25em 0 0 rgba(0,0,0,0), .5em 0 0 rgba(0,0,0,0); }
|
|
338
|
-
40% { color: #6c757d; text-shadow: .25em 0 0 rgba(0,0,0,0), .5em 0 0 rgba(0,0,0,0); }
|
|
339
|
-
60% { text-shadow: .25em 0 0 #6c757d, .5em 0 0 rgba(0,0,0,0); }
|
|
340
|
-
80%, 100% { text-shadow: .25em 0 0 #6c757d, .5em 0 0 #6c757d; }
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
.fade-in {
|
|
344
|
-
animation: fadeIn 0.5s ease-in;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
@keyframes fadeIn {
|
|
348
|
-
from { opacity: 0; transform: translateY(20px); }
|
|
349
|
-
to { opacity: 1; transform: translateY(0); }
|
|
350
|
-
}
|
|
351
|
-
</style>
|
|
352
|
-
</head>
|
|
353
|
-
<body>
|
|
354
|
-
<div class="container">
|
|
355
|
-
<div class="header">
|
|
356
|
-
<h1>🧪 Test Case Review & Approval</h1>
|
|
357
|
-
<div class="session-info" id="sessionInfo">
|
|
358
|
-
Loading session information...
|
|
359
|
-
</div>
|
|
360
|
-
</div>
|
|
361
|
-
|
|
362
|
-
<div id="loading" class="loading">
|
|
363
|
-
Loading test cases
|
|
364
|
-
</div>
|
|
365
|
-
|
|
366
|
-
<div id="content" style="display: none;">
|
|
367
|
-
<div id="newSection" class="section new-section">
|
|
368
|
-
<div class="section-header">
|
|
369
|
-
✨ New Test Cases (<span id="newCount">0</span>)
|
|
370
|
-
</div>
|
|
371
|
-
<div class="section-content" id="newCases">
|
|
372
|
-
<div class="empty-section">No new test cases</div>
|
|
373
|
-
</div>
|
|
374
|
-
</div>
|
|
375
|
-
|
|
376
|
-
<div id="modifySection" class="section modify-section">
|
|
377
|
-
<div class="section-header">
|
|
378
|
-
🔄 Modified Test Cases (<span id="modifyCount">0</span>)
|
|
379
|
-
</div>
|
|
380
|
-
<div class="section-content" id="modifyCases">
|
|
381
|
-
<div class="empty-section">No modified test cases</div>
|
|
382
|
-
</div>
|
|
383
|
-
</div>
|
|
384
|
-
|
|
385
|
-
<div id="removeSection" class="section remove-section">
|
|
386
|
-
<div class="section-header">
|
|
387
|
-
🗑️ Test Cases to Remove (<span id="removeCount">0</span>)
|
|
388
|
-
</div>
|
|
389
|
-
<div class="section-content" id="removeCases">
|
|
390
|
-
<div class="empty-section">No test cases to remove</div>
|
|
391
|
-
</div>
|
|
392
|
-
</div>
|
|
393
|
-
|
|
394
|
-
<div class="approval-section">
|
|
395
|
-
<h2>🎯 Review Complete?</h2>
|
|
396
|
-
<p>Review all test cases above and make any necessary changes, then approve or cancel.</p>
|
|
397
|
-
<div class="approval-buttons">
|
|
398
|
-
<button class="btn btn-primary" onclick="approveTestCases()">
|
|
399
|
-
✅ Approve All Test Cases
|
|
400
|
-
</button>
|
|
401
|
-
<button class="btn btn-danger" onclick="cancelReview()">
|
|
402
|
-
❌ Cancel Review
|
|
403
|
-
</button>
|
|
404
|
-
</div>
|
|
405
|
-
<div id="statusMessage" class="status-message" style="display: none;"></div>
|
|
406
|
-
</div>
|
|
407
|
-
</div>
|
|
408
|
-
</div>
|
|
409
|
-
|
|
410
|
-
<script>
|
|
411
|
-
// Global state
|
|
412
|
-
let sessionId = null;
|
|
413
|
-
let testCases = { new: [], modify: [], remove: [] };
|
|
414
|
-
let editingStates = new Set();
|
|
415
|
-
|
|
416
|
-
// Utility functions
|
|
417
|
-
function showStatus(message, type = 'info') {
|
|
418
|
-
const statusEl = document.getElementById('statusMessage');
|
|
419
|
-
statusEl.textContent = message;
|
|
420
|
-
statusEl.className = `status-message status-${type}`;
|
|
421
|
-
statusEl.style.display = 'block';
|
|
422
|
-
|
|
423
|
-
if (type === 'success') {
|
|
424
|
-
setTimeout(() => {
|
|
425
|
-
statusEl.style.display = 'none';
|
|
426
|
-
}, 3000);
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
function updateCounts() {
|
|
431
|
-
document.getElementById('newCount').textContent = testCases.new?.length || 0;
|
|
432
|
-
document.getElementById('modifyCount').textContent = testCases.modify?.length || 0;
|
|
433
|
-
document.getElementById('removeCount').textContent = testCases.remove?.length || 0;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// API functions
|
|
437
|
-
async function apiCall(url, options = {}) {
|
|
438
|
-
try {
|
|
439
|
-
const response = await fetch(url, {
|
|
440
|
-
headers: {
|
|
441
|
-
'Content-Type': 'application/json',
|
|
442
|
-
...options.headers
|
|
443
|
-
},
|
|
444
|
-
...options
|
|
445
|
-
});
|
|
446
|
-
|
|
447
|
-
if (!response.ok) {
|
|
448
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
return await response.json();
|
|
452
|
-
} catch (error) {
|
|
453
|
-
console.error('API call failed:', error);
|
|
454
|
-
throw error;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// Load initial data
|
|
459
|
-
async function loadTestCases() {
|
|
460
|
-
try {
|
|
461
|
-
const data = await apiCall('/api/testcases');
|
|
462
|
-
sessionId = data.sessionId;
|
|
463
|
-
testCases = data.testCases || { new: [], modify: [], remove: [] };
|
|
464
|
-
|
|
465
|
-
document.getElementById('sessionInfo').textContent =
|
|
466
|
-
`Session ID: ${sessionId} | Total Cases: ${
|
|
467
|
-
(testCases.new?.length || 0) +
|
|
468
|
-
(testCases.modify?.length || 0) +
|
|
469
|
-
(testCases.remove?.length || 0)
|
|
470
|
-
}`;
|
|
471
|
-
|
|
472
|
-
document.getElementById('loading').style.display = 'none';
|
|
473
|
-
document.getElementById('content').style.display = 'block';
|
|
474
|
-
document.getElementById('content').classList.add('fade-in');
|
|
475
|
-
|
|
476
|
-
renderAllSections();
|
|
477
|
-
updateCounts();
|
|
478
|
-
} catch (error) {
|
|
479
|
-
document.getElementById('loading').innerHTML =
|
|
480
|
-
`<div class="status-message status-error">❌ Error loading test cases: ${error.message}</div>`;
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
// Render functions
|
|
485
|
-
function renderAllSections() {
|
|
486
|
-
renderNewCases();
|
|
487
|
-
renderModifyCases();
|
|
488
|
-
renderRemoveCases();
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
function renderNewCases() {
|
|
492
|
-
const container = document.getElementById('newCases');
|
|
493
|
-
const cases = testCases.new || [];
|
|
494
|
-
|
|
495
|
-
if (cases.length === 0) {
|
|
496
|
-
container.innerHTML = '<div class="empty-section">No new test cases</div>';
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
container.innerHTML = cases.map((tc) => `
|
|
501
|
-
<div class="test-case" id="new-${tc.id}">
|
|
502
|
-
<div class="test-case-header">
|
|
503
|
-
<span class="test-case-id">${tc.id}</span>
|
|
504
|
-
<div class="test-case-actions">
|
|
505
|
-
<button class="btn btn-edit" onclick="startEdit('new', '${tc.id}')">✏️ Edit</button>
|
|
506
|
-
<button class="btn btn-delete" onclick="deleteTestCase('new', '${tc.id}')">🗑️ Delete</button>
|
|
507
|
-
</div>
|
|
508
|
-
</div>
|
|
509
|
-
<div class="test-case-content">
|
|
510
|
-
<div id="new-${tc.id}-display">
|
|
511
|
-
<div class="description-text">${escapeHtml(tc.description)}</div>
|
|
512
|
-
</div>
|
|
513
|
-
<div id="new-${tc.id}-edit" style="display: none;">
|
|
514
|
-
<div class="edit-form">
|
|
515
|
-
<div class="form-group">
|
|
516
|
-
<label class="form-label">Description:</label>
|
|
517
|
-
<textarea class="form-control" id="new-${tc.id}-desc">${escapeHtml(tc.description)}</textarea>
|
|
518
|
-
</div>
|
|
519
|
-
<div class="test-case-actions">
|
|
520
|
-
<button class="btn btn-save" onclick="saveEdit('new', '${tc.id}')">💾 Save</button>
|
|
521
|
-
<button class="btn btn-cancel" onclick="cancelEdit('new', '${tc.id}')">❌ Cancel</button>
|
|
522
|
-
</div>
|
|
523
|
-
</div>
|
|
524
|
-
</div>
|
|
525
|
-
</div>
|
|
526
|
-
</div>
|
|
527
|
-
`).join('');
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
function renderModifyCases() {
|
|
531
|
-
const container = document.getElementById('modifyCases');
|
|
532
|
-
const cases = testCases.modify || [];
|
|
533
|
-
|
|
534
|
-
if (cases.length === 0) {
|
|
535
|
-
container.innerHTML = '<div class="empty-section">No modified test cases</div>';
|
|
536
|
-
return;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
container.innerHTML = cases.map((tc) => `
|
|
540
|
-
<div class="test-case" id="modify-${tc.id}">
|
|
541
|
-
<div class="test-case-header">
|
|
542
|
-
<span class="test-case-id">${tc.id}</span>
|
|
543
|
-
<div class="test-case-actions">
|
|
544
|
-
<button class="btn btn-edit" onclick="startEdit('modify', '${tc.id}')">✏️ Edit</button>
|
|
545
|
-
<button class="btn btn-delete" onclick="deleteTestCase('modify', '${tc.id}')">🗑️ Delete</button>
|
|
546
|
-
</div>
|
|
547
|
-
</div>
|
|
548
|
-
<div class="test-case-content">
|
|
549
|
-
<div id="modify-${tc.id}-display">
|
|
550
|
-
<div class="original-text">
|
|
551
|
-
<strong>Original:</strong><br>${escapeHtml(tc.original)}
|
|
552
|
-
</div>
|
|
553
|
-
<div class="modified-text">
|
|
554
|
-
<strong>Modified:</strong><br>${escapeHtml(tc.modified)}
|
|
555
|
-
</div>
|
|
556
|
-
</div>
|
|
557
|
-
<div id="modify-${tc.id}-edit" style="display: none;">
|
|
558
|
-
<div class="edit-form">
|
|
559
|
-
<div class="form-group">
|
|
560
|
-
<label class="form-label">Original (Read-only):</label>
|
|
561
|
-
<textarea class="form-control" readonly>${escapeHtml(tc.original)}</textarea>
|
|
562
|
-
</div>
|
|
563
|
-
<div class="form-group">
|
|
564
|
-
<label class="form-label">Modified:</label>
|
|
565
|
-
<textarea class="form-control" id="modify-${tc.id}-mod">${escapeHtml(tc.modified)}</textarea>
|
|
566
|
-
</div>
|
|
567
|
-
<div class="test-case-actions">
|
|
568
|
-
<button class="btn btn-save" onclick="saveEdit('modify', '${tc.id}')">💾 Save</button>
|
|
569
|
-
<button class="btn btn-cancel" onclick="cancelEdit('modify', '${tc.id}')">❌ Cancel</button>
|
|
570
|
-
</div>
|
|
571
|
-
</div>
|
|
572
|
-
</div>
|
|
573
|
-
</div>
|
|
574
|
-
</div>
|
|
575
|
-
`).join('');
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
function renderRemoveCases() {
|
|
579
|
-
const container = document.getElementById('removeCases');
|
|
580
|
-
const cases = testCases.remove || [];
|
|
581
|
-
|
|
582
|
-
if (cases.length === 0) {
|
|
583
|
-
container.innerHTML = '<div class="empty-section">No test cases to remove</div>';
|
|
584
|
-
return;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
container.innerHTML = cases.map((tc) => `
|
|
588
|
-
<div class="test-case" id="remove-${tc.id}">
|
|
589
|
-
<div class="test-case-header">
|
|
590
|
-
<span class="test-case-id">${tc.id}</span>
|
|
591
|
-
<div class="test-case-actions">
|
|
592
|
-
<button class="btn btn-delete" onclick="deleteTestCase('remove', '${tc.id}')">🗑️ Remove</button>
|
|
593
|
-
</div>
|
|
594
|
-
</div>
|
|
595
|
-
<div class="test-case-content">
|
|
596
|
-
<div class="remove-text">
|
|
597
|
-
<strong>⚠️ This test case will be removed:</strong><br>
|
|
598
|
-
${escapeHtml(tc.description)}
|
|
599
|
-
</div>
|
|
600
|
-
</div>
|
|
601
|
-
</div>
|
|
602
|
-
`).join('');
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
// Edit functions
|
|
606
|
-
function startEdit(type, id) {
|
|
607
|
-
const editKey = `${type}-${id}`;
|
|
608
|
-
if (editingStates.has(editKey)) return;
|
|
609
|
-
|
|
610
|
-
editingStates.add(editKey);
|
|
611
|
-
document.getElementById(`${type}-${id}-display`).style.display = 'none';
|
|
612
|
-
document.getElementById(`${type}-${id}-edit`).style.display = 'block';
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
function cancelEdit(type, id) {
|
|
616
|
-
const editKey = `${type}-${id}`;
|
|
617
|
-
editingStates.delete(editKey);
|
|
618
|
-
document.getElementById(`${type}-${id}-display`).style.display = 'block';
|
|
619
|
-
document.getElementById(`${type}-${id}-edit`).style.display = 'none';
|
|
620
|
-
|
|
621
|
-
// Reset form values
|
|
622
|
-
const testCase = findTestCase(type, id);
|
|
623
|
-
if (testCase) {
|
|
624
|
-
if (type === 'new') {
|
|
625
|
-
document.getElementById(`new-${id}-desc`).value = testCase.description;
|
|
626
|
-
} else if (type === 'modify') {
|
|
627
|
-
document.getElementById(`modify-${id}-mod`).value = testCase.modified;
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
function findTestCase(type, id) {
|
|
633
|
-
return testCases[type]?.find(tc => tc.id === id);
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
async function saveEdit(type, id) {
|
|
637
|
-
try {
|
|
638
|
-
const editKey = `${type}-${id}`;
|
|
639
|
-
let updatedData = {};
|
|
640
|
-
|
|
641
|
-
const testCase = findTestCase(type, id);
|
|
642
|
-
if (!testCase) {
|
|
643
|
-
showStatus('Test case not found', 'error');
|
|
644
|
-
return;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
if (type === 'new') {
|
|
648
|
-
const newDesc = document.getElementById(`new-${id}-desc`).value.trim();
|
|
649
|
-
if (!newDesc) {
|
|
650
|
-
showStatus('Description cannot be empty', 'error');
|
|
651
|
-
return;
|
|
652
|
-
}
|
|
653
|
-
updatedData = { description: newDesc };
|
|
654
|
-
testCase.description = newDesc;
|
|
655
|
-
} else if (type === 'modify') {
|
|
656
|
-
const newMod = document.getElementById(`modify-${id}-mod`).value.trim();
|
|
657
|
-
if (!newMod) {
|
|
658
|
-
showStatus('Modified description cannot be empty', 'error');
|
|
659
|
-
return;
|
|
660
|
-
}
|
|
661
|
-
updatedData = { modified: newMod };
|
|
662
|
-
testCase.modified = newMod;
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
// Send update to server
|
|
666
|
-
await apiCall(`/update/${sessionId}`, {
|
|
667
|
-
method: 'POST',
|
|
668
|
-
body: JSON.stringify({
|
|
669
|
-
type,
|
|
670
|
-
id: id,
|
|
671
|
-
data: updatedData
|
|
672
|
-
})
|
|
673
|
-
});
|
|
674
|
-
|
|
675
|
-
editingStates.delete(editKey);
|
|
676
|
-
document.getElementById(`${type}-${id}-display`).style.display = 'block';
|
|
677
|
-
document.getElementById(`${type}-${id}-edit`).style.display = 'none';
|
|
678
|
-
|
|
679
|
-
// Re-render the specific section
|
|
680
|
-
if (type === 'new') renderNewCases();
|
|
681
|
-
else if (type === 'modify') renderModifyCases();
|
|
682
|
-
|
|
683
|
-
showStatus('Changes saved successfully!', 'success');
|
|
684
|
-
} catch (error) {
|
|
685
|
-
showStatus(`Error saving changes: ${error.message}`, 'error');
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
// Delete function
|
|
690
|
-
async function deleteTestCase(type, id) {
|
|
691
|
-
if (!confirm(`Are you sure you want to delete this test case?`)) return;
|
|
692
|
-
|
|
693
|
-
try {
|
|
694
|
-
showStatus('Deleting test case...', 'info');
|
|
695
|
-
|
|
696
|
-
const result = await apiCall(`/delete/${sessionId}`, {
|
|
697
|
-
method: 'POST',
|
|
698
|
-
body: JSON.stringify({ type, id })
|
|
699
|
-
});
|
|
700
|
-
|
|
701
|
-
if (result.testCases) {
|
|
702
|
-
testCases = result.testCases;
|
|
703
|
-
|
|
704
|
-
// Ensure all arrays exist after update
|
|
705
|
-
if (!testCases.new) testCases.new = [];
|
|
706
|
-
if (!testCases.modify) testCases.modify = [];
|
|
707
|
-
if (!testCases.remove) testCases.remove = [];
|
|
708
|
-
|
|
709
|
-
renderAllSections();
|
|
710
|
-
updateCounts();
|
|
711
|
-
showStatus('Test case deleted successfully!', 'success');
|
|
712
|
-
} else {
|
|
713
|
-
showStatus('Unexpected response from server', 'error');
|
|
714
|
-
}
|
|
715
|
-
} catch (error) {
|
|
716
|
-
showStatus(`Error deleting test case: ${error.message}`, 'error');
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
// Approval functions
|
|
721
|
-
async function approveTestCases() {
|
|
722
|
-
if (!confirm('Are you sure you want to approve all test cases? This action cannot be undone.')) return;
|
|
723
|
-
|
|
724
|
-
try {
|
|
725
|
-
showStatus('Processing approval...', 'info');
|
|
726
|
-
|
|
727
|
-
const result = await apiCall(`/approve/${sessionId}`, {
|
|
728
|
-
method: 'POST',
|
|
729
|
-
body: JSON.stringify(testCases)
|
|
730
|
-
});
|
|
731
|
-
|
|
732
|
-
showStatus('✅ Test cases approved successfully! You can close this window.', 'success');
|
|
733
|
-
|
|
734
|
-
// Disable all controls
|
|
735
|
-
document.querySelectorAll('button').forEach(btn => btn.disabled = true);
|
|
736
|
-
|
|
737
|
-
setTimeout(() => {
|
|
738
|
-
window.close();
|
|
739
|
-
}, 2000);
|
|
740
|
-
} catch (error) {
|
|
741
|
-
showStatus(`Error approving test cases: ${error.message}`, 'error');
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
async function cancelReview() {
|
|
746
|
-
if (!confirm('Are you sure you want to cancel this review?')) return;
|
|
747
|
-
|
|
748
|
-
try {
|
|
749
|
-
showStatus('Cancelling review...', 'info');
|
|
750
|
-
|
|
751
|
-
await apiCall(`/cancel/${sessionId}`, { method: 'POST' });
|
|
752
|
-
|
|
753
|
-
showStatus('Review cancelled. You can close this window.', 'info');
|
|
754
|
-
|
|
755
|
-
setTimeout(() => {
|
|
756
|
-
window.close();
|
|
757
|
-
}, 1500);
|
|
758
|
-
} catch (error) {
|
|
759
|
-
showStatus(`Error cancelling review: ${error.message}`, 'error');
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
// Utility function
|
|
764
|
-
function escapeHtml(text) {
|
|
765
|
-
const div = document.createElement('div');
|
|
766
|
-
div.textContent = text;
|
|
767
|
-
return div.innerHTML;
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
// Initialize when page loads
|
|
771
|
-
window.addEventListener('load', loadTestCases);
|
|
772
|
-
</script>
|
|
773
|
-
</body>
|
|
774
|
-
</html>
|