@cryptotaxi247 / CoPilot / commits / 88a85e81

docs: add UI screenshots (Playwright) for docs (#705)

Co-authored-by: Clawdbot <clawdbot@Clawdbots-Mac-mini.local>

taylorcopilot committed Feb 14, 2026 at 17:35 UTC 88a85e811d8972102d3753823fb659fa11b8dba3
35 files changed +190
docs/assets/ui/agents-copilot-actions.png
Binary files /dev/null and b/docs/assets/ui/agents-copilot-actions.png differ
docs/assets/ui/agents-detection-rules.png
Binary files /dev/null and b/docs/assets/ui/agents-detection-rules.png differ
docs/assets/ui/agents-groups.png
Binary files /dev/null and b/docs/assets/ui/agents-groups.png differ
docs/assets/ui/agents-sca-overview.png
Binary files /dev/null and b/docs/assets/ui/agents-sca-overview.png differ
docs/assets/ui/agents-sysmon-config.png
Binary files /dev/null and b/docs/assets/ui/agents-sysmon-config.png differ
docs/assets/ui/agents-vulnerability-overview.png
Binary files /dev/null and b/docs/assets/ui/agents-vulnerability-overview.png differ
docs/assets/ui/agents.png
Binary files /dev/null and b/docs/assets/ui/agents.png differ
docs/assets/ui/alerts-atomic-red-team.png
Binary files /dev/null and b/docs/assets/ui/alerts-atomic-red-team.png differ
docs/assets/ui/alerts-mitre.png
Binary files /dev/null and b/docs/assets/ui/alerts-mitre.png differ
docs/assets/ui/alerts-siem.png
Binary files /dev/null and b/docs/assets/ui/alerts-siem.png differ
docs/assets/ui/artifacts.png
Binary files /dev/null and b/docs/assets/ui/artifacts.png differ
docs/assets/ui/connectors.png
Binary files /dev/null and b/docs/assets/ui/connectors.png differ
docs/assets/ui/customer-portal.png
Binary files /dev/null and b/docs/assets/ui/customer-portal.png differ
docs/assets/ui/customers.png
Binary files /dev/null and b/docs/assets/ui/customers.png differ
docs/assets/ui/external-network-connectors.png
Binary files /dev/null and b/docs/assets/ui/external-network-connectors.png differ
docs/assets/ui/external-singul-app-auth.png
Binary files /dev/null and b/docs/assets/ui/external-singul-app-auth.png differ
docs/assets/ui/external-third-party-integrations.png
Binary files /dev/null and b/docs/assets/ui/external-third-party-integrations.png differ
docs/assets/ui/graylog-management.png
Binary files /dev/null and b/docs/assets/ui/graylog-management.png differ
docs/assets/ui/graylog-metrics.png
Binary files /dev/null and b/docs/assets/ui/graylog-metrics.png differ
docs/assets/ui/graylog-pipelines.png
Binary files /dev/null and b/docs/assets/ui/graylog-pipelines.png differ
docs/assets/ui/healthcheck.png
Binary files /dev/null and b/docs/assets/ui/healthcheck.png differ
docs/assets/ui/incident-alerts.png
Binary files /dev/null and b/docs/assets/ui/incident-alerts.png differ
docs/assets/ui/incident-cases.png
Binary files /dev/null and b/docs/assets/ui/incident-cases.png differ
docs/assets/ui/incident-sources.png
Binary files /dev/null and b/docs/assets/ui/incident-sources.png differ
docs/assets/ui/indices-management.png
Binary files /dev/null and b/docs/assets/ui/indices-management.png differ
docs/assets/ui/indices-snapshots.png
Binary files /dev/null and b/docs/assets/ui/indices-snapshots.png differ
docs/assets/ui/overview.png
Binary files /dev/null and b/docs/assets/ui/overview.png differ
docs/assets/ui/patch-tuesday.png
Binary files /dev/null and b/docs/assets/ui/patch-tuesday.png differ
docs/assets/ui/report-general.png
Binary files /dev/null and b/docs/assets/ui/report-general.png differ
docs/assets/ui/report-sca.png
Binary files /dev/null and b/docs/assets/ui/report-sca.png differ
docs/assets/ui/report-vulnerability.png
Binary files /dev/null and b/docs/assets/ui/report-vulnerability.png differ
docs/assets/ui/scheduler.png
Binary files /dev/null and b/docs/assets/ui/scheduler.png differ
tools/ui-screenshots/package-lock.json new
+57
@@ -0,0 +1,57 @@
1 +{
2 + "name": "copilot-ui-screenshots",
3 + "lockfileVersion": 3,
4 + "requires": true,
5 + "packages": {
6 + "": {
7 + "name": "copilot-ui-screenshots",
8 + "dependencies": {
9 + "playwright": "^1.51.1"
10 + }
11 + },
12 + "node_modules/fsevents": {
13 + "version": "2.3.2",
14 + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
15 + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
16 + "hasInstallScript": true,
17 + "license": "MIT",
18 + "optional": true,
19 + "os": [
20 + "darwin"
21 + ],
22 + "engines": {
23 + "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
24 + }
25 + },
26 + "node_modules/playwright": {
27 + "version": "1.58.2",
28 + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz",
29 + "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==",
30 + "license": "Apache-2.0",
31 + "dependencies": {
32 + "playwright-core": "1.58.2"
33 + },
34 + "bin": {
35 + "playwright": "cli.js"
36 + },
37 + "engines": {
38 + "node": ">=18"
39 + },
40 + "optionalDependencies": {
41 + "fsevents": "2.3.2"
42 + }
43 + },
44 + "node_modules/playwright-core": {
45 + "version": "1.58.2",
46 + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz",
47 + "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==",
48 + "license": "Apache-2.0",
49 + "bin": {
50 + "playwright-core": "cli.js"
51 + },
52 + "engines": {
53 + "node": ">=18"
54 + }
55 + }
56 + }
57 +}
tools/ui-screenshots/package.json new
+11
@@ -0,0 +1,11 @@
1 +{
2 + "name": "copilot-ui-screenshots",
3 + "private": true,
4 + "type": "module",
5 + "scripts": {
6 + "shots": "node ./screenshots.mjs"
7 + },
8 + "dependencies": {
9 + "playwright": "^1.51.1"
10 + }
11 +}
tools/ui-screenshots/screenshots.mjs new
+122
@@ -0,0 +1,122 @@
1 +import fs from 'node:fs/promises';
2 +import path from 'node:path';
3 +import {chromium} from 'playwright';
4 +
5 +const BASE_URL = process.env.COPILOT_BASE_URL || 'https://copilot-lab.socfortressmdr.us';
6 +const USERNAME = process.env.COPILOT_USERNAME;
7 +const PASSWORD = process.env.COPILOT_PASSWORD;
8 +
9 +if (!USERNAME || !PASSWORD) {
10 + console.error('Missing COPILOT_USERNAME or COPILOT_PASSWORD in environment.');
11 + process.exit(1);
12 +}
13 +
14 +const OUT_DIR = path.resolve(process.cwd(), '..', '..', 'docs', 'assets', 'ui');
15 +
16 +const routes = [
17 + {key: 'overview', path: '/overview'},
18 + {key: 'incident-sources', path: '/incident-management/sources'},
19 + {key: 'incident-alerts', path: '/incident-management/alerts'},
20 + {key: 'incident-cases', path: '/incident-management/cases'},
21 + {key: 'alerts-siem', path: '/alerts/siem'},
22 + {key: 'alerts-mitre', path: '/alerts/mitre'},
23 + {key: 'alerts-atomic-red-team', path: '/alerts/atomic-red-team'},
24 + {key: 'artifacts', path: '/artifacts'},
25 + {key: 'customers', path: '/customers'},
26 + {key: 'agents', path: '/agents'},
27 + {key: 'agents-groups', path: '/agents/groups'},
28 + {key: 'agents-sysmon-config', path: '/agents/sysmon-config'},
29 + {key: 'agents-detection-rules', path: '/agents/detection-rules'},
30 + {key: 'agents-copilot-actions', path: '/agents/copilot-actions'},
31 + {key: 'agents-vulnerability-overview', path: '/agents/vulnerability-overview'},
32 + {key: 'agents-sca-overview', path: '/agents/sca-overview'},
33 + {key: 'patch-tuesday', path: '/patch-tuesday'},
34 + {key: 'report-general', path: '/report-creation/general'},
35 + {key: 'report-vulnerability', path: '/report-creation/vulnerability-reports'},
36 + {key: 'report-sca', path: '/report-creation/sca-reports'},
37 + {key: 'healthcheck', path: '/healthcheck'},
38 + {key: 'indices-management', path: '/indices/management'},
39 + {key: 'indices-snapshots', path: '/indices/snapshots'},
40 + {key: 'graylog-management', path: '/graylog/management'},
41 + {key: 'graylog-metrics', path: '/graylog/metrics'},
42 + {key: 'graylog-pipelines', path: '/graylog/pipelines'},
43 + {key: 'connectors', path: '/connectors'},
44 + {key: 'external-third-party-integrations', path: '/external-services/third-party-integrations'},
45 + {key: 'external-network-connectors', path: '/external-services/network-connectors'},
46 + {key: 'external-singul-app-auth', path: '/external-services/singul-app-auth'},
47 + {key: 'scheduler', path: '/scheduler'},
48 + {key: 'customer-portal', path: '/customer-portal'}
49 +];
50 +
51 +const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
52 +
53 +async function ensureDir(p) {
54 + await fs.mkdir(p, {recursive: true});
55 +}
56 +
57 +async function main() {
58 + await ensureDir(OUT_DIR);
59 +
60 + const browser = await chromium.launch({headless: true});
61 + const context = await browser.newContext({
62 + viewport: {width: 1440, height: 900},
63 + deviceScaleFactor: 2,
64 + });
65 + const page = await context.newPage();
66 +
67 + // Login
68 + await page.goto(`${BASE_URL}/login`, {waitUntil: 'domcontentloaded'});
69 + await page.waitForTimeout(500);
70 +
71 + // Try a few common selectors for the login form
72 + const userInput = page.getByRole('textbox', {name: /username/i}).first()
73 + .or(page.getByPlaceholder(/username/i).first())
74 + .or(page.locator('input[type="text"], input[type="email"]').first());
75 +
76 + const passInput = page.getByRole('textbox', {name: /password/i}).first()
77 + .or(page.getByPlaceholder(/password/i).first())
78 + .or(page.locator('input[type="password"]').first());
79 +
80 + await userInput.fill(USERNAME);
81 + await passInput.fill(PASSWORD);
82 +
83 + const signIn = page.getByRole('button', {name: /sign in/i}).first()
84 + .or(page.locator('button[type="submit"]').first());
85 +
86 + await Promise.all([
87 + page.waitForLoadState('networkidle').catch(() => undefined),
88 + signIn.click()
89 + ]);
90 +
91 + // Give SPA time to hydrate
92 + await sleep(1500);
93 +
94 + // If still on /login, fail early
95 + if (page.url().includes('/login')) {
96 + const shot = path.join(OUT_DIR, '_login-failed.png');
97 + await page.screenshot({path: shot, fullPage: true});
98 + throw new Error(`Login appears to have failed; screenshot saved to ${shot}`);
99 + }
100 +
101 + // Screenshot sweep
102 + for (const r of routes) {
103 + const url = `${BASE_URL}${r.path}`;
104 + console.log(`SHOT ${r.key} -> ${url}`);
105 + await page.goto(url, {waitUntil: 'domcontentloaded'});
106 + await page.waitForTimeout(1200);
107 +
108 + // Attempt to close any toast/overlay by pressing Escape (best-effort)
109 + await page.keyboard.press('Escape').catch(() => undefined);
110 +
111 + const outPath = path.join(OUT_DIR, `${r.key}.png`);
112 + await page.screenshot({path: outPath, fullPage: true});
113 + }
114 +
115 + await browser.close();
116 + console.log(`Done. Wrote ${routes.length} screenshots to ${OUT_DIR}`);
117 +}
118 +
119 +main().catch((err) => {
120 + console.error(err?.stack || String(err));
121 + process.exit(1);
122 +});