skopix 2.0.92 → 2.0.94
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/cli/commands/dashboard.js +22 -0
- package/package.json +1 -1
- package/web/app/index.html +42 -16
|
@@ -1482,11 +1482,17 @@ export async function dashboardCommand(options) {
|
|
|
1482
1482
|
replayAgent.currentJob = { type: 'replay', runId, testName: test.name };
|
|
1483
1483
|
broadcastAgentList();
|
|
1484
1484
|
sendToAgent(replayAgent, { type: 'replay', runId, test, setupTest, env: userEnv || {} });
|
|
1485
|
+
if (teamMode && currentUser) {
|
|
1486
|
+
teamMode.db.logAudit({ userId: currentUser.id, action: 'test.run', targetType: 'test', targetId: test.id, metadata: { name: test.name, scope: test.scope, agent: replayAgent.name } });
|
|
1487
|
+
}
|
|
1485
1488
|
sendJSON(res, 200, { runId, agent: { id: replayAgent.id, name: replayAgent.name } });
|
|
1486
1489
|
return;
|
|
1487
1490
|
}
|
|
1488
1491
|
|
|
1489
1492
|
const runId = startReplay(test, setupTest, activeRuns, reportsDir, currentUser, { ...process.env, ...(userEnv || {}) });
|
|
1493
|
+
if (teamMode && currentUser) {
|
|
1494
|
+
teamMode.db.logAudit({ userId: currentUser.id, action: 'test.run', targetType: 'test', targetId: test.id, metadata: { name: test.name, scope: test.scope } });
|
|
1495
|
+
}
|
|
1490
1496
|
sendJSON(res, 200, { runId });
|
|
1491
1497
|
return;
|
|
1492
1498
|
}
|
|
@@ -1496,6 +1502,15 @@ export async function dashboardCommand(options) {
|
|
|
1496
1502
|
const config = JSON.parse(body);
|
|
1497
1503
|
const userEnv = await resolveUserSecretsEnv(currentUser?.id, teamMode);
|
|
1498
1504
|
const runId = startRun(config, activeRuns, reportsDir, currentUser, userEnv);
|
|
1505
|
+
if (teamMode && currentUser) {
|
|
1506
|
+
teamMode.db.logAudit({
|
|
1507
|
+
userId: currentUser.id,
|
|
1508
|
+
action: 'test.run',
|
|
1509
|
+
targetType: 'test',
|
|
1510
|
+
targetId: config.testId || config.suiteId || 'unknown',
|
|
1511
|
+
metadata: { testName: config.testName || config.suiteName, scope: config.scope }
|
|
1512
|
+
});
|
|
1513
|
+
}
|
|
1499
1514
|
sendJSON(res, 200, { runId });
|
|
1500
1515
|
return;
|
|
1501
1516
|
}
|
|
@@ -1583,6 +1598,9 @@ export async function dashboardCommand(options) {
|
|
|
1583
1598
|
const result = await updateTest(suitesDir, scope, testId, data);
|
|
1584
1599
|
// Extract any new unmatched steps to pending review queue
|
|
1585
1600
|
extractStepsToLibrary(suitesDir, data.steps || [], data.name || testId).catch(() => {});
|
|
1601
|
+
if (teamMode && currentUser) {
|
|
1602
|
+
teamMode.db.logAudit({ userId: currentUser.id, action: 'test.updated', targetType: 'test', targetId: testId, metadata: { name: data.name, scope } });
|
|
1603
|
+
}
|
|
1586
1604
|
sendJSON(res, 200, result);
|
|
1587
1605
|
} catch (err) {
|
|
1588
1606
|
sendJSON(res, 400, { error: err.message });
|
|
@@ -1593,7 +1611,11 @@ export async function dashboardCommand(options) {
|
|
|
1593
1611
|
const parts = pathname.split('/');
|
|
1594
1612
|
const scope = decodeURIComponent(parts[3]);
|
|
1595
1613
|
const testId = decodeURIComponent(parts[4]);
|
|
1614
|
+
const testToDelete = await getTest(suitesDir, scope, testId).catch(() => null);
|
|
1596
1615
|
await deleteTest(suitesDir, scope, testId);
|
|
1616
|
+
if (teamMode && currentUser) {
|
|
1617
|
+
teamMode.db.logAudit({ userId: currentUser.id, action: 'test.deleted', targetType: 'test', targetId: testId, metadata: { name: testToDelete?.name, scope } });
|
|
1618
|
+
}
|
|
1597
1619
|
sendJSON(res, 200, { deleted: true });
|
|
1598
1620
|
return;
|
|
1599
1621
|
}
|
package/package.json
CHANGED
package/web/app/index.html
CHANGED
|
@@ -2070,21 +2070,32 @@ body.viewer-mode .saved-test-row { cursor: default !important; }
|
|
|
2070
2070
|
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center">
|
|
2071
2071
|
<select class="form-select" id="audit-action-filter" style="padding:8px 12px;font-size:12px;width:auto" onchange="renderAuditLog()">
|
|
2072
2072
|
<option value="">All actions</option>
|
|
2073
|
-
<
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
<
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2073
|
+
<optgroup label="Tests">
|
|
2074
|
+
<option value="test.created">Test created</option>
|
|
2075
|
+
<option value="test.updated">Test updated</option>
|
|
2076
|
+
<option value="test.deleted">Test deleted</option>
|
|
2077
|
+
<option value="test.duplicated">Test duplicated</option>
|
|
2078
|
+
<option value="test.run">Test run</option>
|
|
2079
|
+
</optgroup>
|
|
2080
|
+
<optgroup label="Users">
|
|
2081
|
+
<option value="user.login">Logins</option>
|
|
2082
|
+
<option value="user.logout">Logouts</option>
|
|
2083
|
+
<option value="user.created">User created</option>
|
|
2084
|
+
<option value="user.deleted">User deleted</option>
|
|
2085
|
+
<option value="user.role_changed">Role changed</option>
|
|
2086
|
+
<option value="user.disabled">User disabled</option>
|
|
2087
|
+
<option value="user.enabled">User enabled</option>
|
|
2088
|
+
<option value="user.sessions_revoked">Force logout</option>
|
|
2089
|
+
<option value="user.reset_generated">Password reset generated</option>
|
|
2090
|
+
<option value="user.password_reset">Password reset used</option>
|
|
2091
|
+
<option value="user.password_changed">Password changed</option>
|
|
2092
|
+
<option value="user.secret_set">Secret set</option>
|
|
2093
|
+
<option value="user.secret_deleted">Secret deleted</option>
|
|
2094
|
+
</optgroup>
|
|
2095
|
+
<optgroup label="Invites">
|
|
2096
|
+
<option value="invite.created">Invite created</option>
|
|
2097
|
+
<option value="invite.revoked">Invite revoked</option>
|
|
2098
|
+
</optgroup>
|
|
2088
2099
|
</select>
|
|
2089
2100
|
<span id="audit-count" style="font-family:var(--mono);font-size:11px;color:var(--muted)"></span>
|
|
2090
2101
|
</div>
|
|
@@ -5144,13 +5155,28 @@ function renderAuditLog() {
|
|
|
5144
5155
|
'user.secret_deleted': { label: 'Secret removed', badge: 'background:rgba(255,255,255,0.04);color:var(--muted)' },
|
|
5145
5156
|
'invite.created': { label: 'Invite created', badge: 'background:rgba(0,212,255,0.15);color:var(--cyan)' },
|
|
5146
5157
|
'invite.revoked': { label: 'Invite revoked', badge: 'background:rgba(255,255,255,0.04);color:var(--muted)' },
|
|
5158
|
+
'test.created': { label: 'Test created', badge: 'background:rgba(16,185,129,0.15);color:var(--green)' },
|
|
5159
|
+
'test.updated': { label: 'Test updated', badge: 'background:rgba(0,212,255,0.15);color:var(--cyan)' },
|
|
5160
|
+
'test.deleted': { label: 'Test deleted', badge: 'background:rgba(239,68,68,0.15);color:var(--red)' },
|
|
5161
|
+
'test.duplicated': { label: 'Test duplicated', badge: 'background:rgba(0,212,255,0.15);color:var(--cyan)' },
|
|
5162
|
+
'test.run': { label: 'Test run', badge: 'background:rgba(124,58,237,0.15);color:var(--purple)' },
|
|
5147
5163
|
};
|
|
5148
5164
|
|
|
5149
5165
|
list.innerHTML = _auditEntries.map(e => {
|
|
5150
5166
|
const meta = actionMeta[e.action] || { label: e.action, badge: 'background:rgba(255,255,255,0.04);color:var(--muted)' };
|
|
5151
5167
|
const when = formatDateTime(e.createdAt);
|
|
5152
5168
|
const actor = e.userName ? `${escapeHtml(e.userName)} <span style="color:var(--muted2)">·</span> <span style="color:var(--muted)">${escapeHtml(e.userEmail || '')}</span>` : '<span style="color:var(--muted2)">system</span>';
|
|
5153
|
-
|
|
5169
|
+
// Show metadata nicely — test name, scope etc
|
|
5170
|
+
let metaDisplay = '';
|
|
5171
|
+
if (e.metadata) {
|
|
5172
|
+
const m = e.metadata;
|
|
5173
|
+
const parts = [];
|
|
5174
|
+
if (m.name) parts.push(escapeHtml(m.name));
|
|
5175
|
+
else if (m.testName) parts.push(escapeHtml(m.testName));
|
|
5176
|
+
if (m.scope && m.scope !== 'saved') parts.push(escapeHtml(m.scope));
|
|
5177
|
+
if (m.type) parts.push(escapeHtml(m.type));
|
|
5178
|
+
metaDisplay = parts.length ? `<span style="color:var(--muted);font-size:11px;margin-left:8px">— ${parts.join(' · ')}</span>` : '';
|
|
5179
|
+
}
|
|
5154
5180
|
return `
|
|
5155
5181
|
<div class="saved-test-row" style="cursor:default;align-items:center;padding:14px 22px">
|
|
5156
5182
|
<div style="display:flex;align-items:center;gap:14px;flex:1;min-width:0">
|