@sun-asterisk/sungen 3.2.33 → 3.2.34
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/dist/cli/commands/audit.d.ts +4 -0
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +16 -3
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/changed.d.ts.map +1 -1
- package/dist/cli/commands/changed.js +2 -3
- package/dist/cli/commands/changed.js.map +1 -1
- package/dist/cli/commands/dashboard.d.ts.map +1 -1
- package/dist/cli/commands/dashboard.js +2 -28
- package/dist/cli/commands/dashboard.js.map +1 -1
- package/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +40 -35
- package/dist/cli/commands/delivery.js.map +1 -1
- package/dist/cli/commands/results-merge.d.ts +9 -0
- package/dist/cli/commands/results-merge.d.ts.map +1 -1
- package/dist/cli/commands/results-merge.js +7 -0
- package/dist/cli/commands/results-merge.js.map +1 -1
- package/dist/cli/commands/select.d.ts +12 -0
- package/dist/cli/commands/select.d.ts.map +1 -0
- package/dist/cli/commands/select.js +122 -0
- package/dist/cli/commands/select.js.map +1 -0
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +3 -0
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/index.js +7 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/dashboard/templates/index.html +1 -1
- package/dist/dashboard/types.d.ts +1 -0
- package/dist/dashboard/types.d.ts.map +1 -1
- package/dist/exporters/csv-exporter.d.ts.map +1 -1
- package/dist/exporters/csv-exporter.js +11 -10
- package/dist/exporters/csv-exporter.js.map +1 -1
- package/dist/exporters/json-exporter.d.ts.map +1 -1
- package/dist/exporters/json-exporter.js +7 -0
- package/dist/exporters/json-exporter.js.map +1 -1
- package/dist/exporters/manual-hybrid-oracle.d.ts +54 -0
- package/dist/exporters/manual-hybrid-oracle.d.ts.map +1 -0
- package/dist/exporters/manual-hybrid-oracle.js +114 -0
- package/dist/exporters/manual-hybrid-oracle.js.map +1 -0
- package/dist/exporters/matrix/build.d.ts.map +1 -1
- package/dist/exporters/matrix/build.js +6 -2
- package/dist/exporters/matrix/build.js.map +1 -1
- package/dist/exporters/matrix/export.d.ts +3 -0
- package/dist/exporters/matrix/export.d.ts.map +1 -1
- package/dist/exporters/matrix/export.js +1 -0
- package/dist/exporters/matrix/export.js.map +1 -1
- package/dist/exporters/matrix/gates.js +6 -0
- package/dist/exporters/matrix/gates.js.map +1 -1
- package/dist/exporters/matrix/render-testcase-sheet.d.ts.map +1 -1
- package/dist/exporters/matrix/render-testcase-sheet.js +10 -4
- package/dist/exporters/matrix/render-testcase-sheet.js.map +1 -1
- package/dist/exporters/matrix/types.d.ts +8 -1
- package/dist/exporters/matrix/types.d.ts.map +1 -1
- package/dist/exporters/matrix/types.js.map +1 -1
- package/dist/exporters/matrix/wording.d.ts +1 -1
- package/dist/exporters/matrix/wording.d.ts.map +1 -1
- package/dist/exporters/matrix/wording.js +10 -1
- package/dist/exporters/matrix/wording.js.map +1 -1
- package/dist/exporters/run-environment.d.ts +32 -0
- package/dist/exporters/run-environment.d.ts.map +1 -0
- package/dist/exporters/run-environment.js +125 -0
- package/dist/exporters/run-environment.js.map +1 -0
- package/dist/exporters/scenario-merger.d.ts +18 -0
- package/dist/exporters/scenario-merger.d.ts.map +1 -1
- package/dist/exporters/scenario-merger.js +47 -3
- package/dist/exporters/scenario-merger.js.map +1 -1
- package/dist/exporters/test-data-resolver.d.ts +0 -4
- package/dist/exporters/test-data-resolver.d.ts.map +1 -1
- package/dist/exporters/test-data-resolver.js +0 -7
- package/dist/exporters/test-data-resolver.js.map +1 -1
- package/dist/generators/gherkin-parser/index.d.ts +11 -4
- package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
- package/dist/generators/gherkin-parser/index.js +49 -19
- package/dist/generators/gherkin-parser/index.js.map +1 -1
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts +4 -0
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/click-select-action.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/select-action.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/pick-option.hbs +13 -0
- package/dist/generators/test-generator/adapters/playwright/templates/test-file.hbs +16 -0
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +23 -2
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/generators/test-generator/diagnostics.d.ts +3 -1
- package/dist/generators/test-generator/diagnostics.d.ts.map +1 -1
- package/dist/generators/test-generator/diagnostics.js +3 -1
- package/dist/generators/test-generator/diagnostics.js.map +1 -1
- package/dist/harness/audit.d.ts +3 -0
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +17 -8
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/data-driven-lint.d.ts.map +1 -1
- package/dist/harness/data-driven-lint.js +69 -27
- package/dist/harness/data-driven-lint.js.map +1 -1
- package/dist/harness/next-step.d.ts.map +1 -1
- package/dist/harness/next-step.js +1 -0
- package/dist/harness/next-step.js.map +1 -1
- package/dist/harness/parse.d.ts +24 -0
- package/dist/harness/parse.d.ts.map +1 -1
- package/dist/harness/parse.js +117 -13
- package/dist/harness/parse.js.map +1 -1
- package/dist/harness/quality-gates.d.ts.map +1 -1
- package/dist/harness/quality-gates.js +6 -4
- package/dist/harness/quality-gates.js.map +1 -1
- package/dist/harness/read-text.d.ts +15 -0
- package/dist/harness/read-text.d.ts.map +1 -1
- package/dist/harness/read-text.js +25 -0
- package/dist/harness/read-text.js.map +1 -1
- package/dist/harness/select-by-ids.d.ts +31 -0
- package/dist/harness/select-by-ids.d.ts.map +1 -0
- package/dist/harness/select-by-ids.js +106 -0
- package/dist/harness/select-by-ids.js.map +1 -0
- package/dist/harness/sensors.d.ts +8 -1
- package/dist/harness/sensors.d.ts.map +1 -1
- package/dist/harness/sensors.js +61 -9
- package/dist/harness/sensors.js.map +1 -1
- package/dist/harness/spec-branches.js +1 -1
- package/dist/harness/spec-branches.js.map +1 -1
- package/dist/harness/ui-inventory.d.ts +40 -0
- package/dist/harness/ui-inventory.d.ts.map +1 -0
- package/dist/harness/ui-inventory.js +191 -0
- package/dist/harness/ui-inventory.js.map +1 -0
- package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
- package/dist/harness/viewpoint-ledger.js +64 -9
- package/dist/harness/viewpoint-ledger.js.map +1 -1
- package/dist/orchestrator/screen-manager.d.ts.map +1 -1
- package/dist/orchestrator/screen-manager.js +3 -11
- package/dist/orchestrator/screen-manager.js.map +1 -1
- package/dist/orchestrator/templates/ai-src/agents/discovery.md +11 -3
- package/dist/orchestrator/templates/ai-src/agents/reviewer.md +8 -0
- package/dist/orchestrator/templates/ai-src/commands/create-test.md +2 -2
- package/dist/orchestrator/templates/ai-src/commands/review.md +2 -2
- package/dist/orchestrator/templates/ai-src/commands/run-test.md +70 -13
- package/dist/orchestrator/templates/ai-src/skills/sungen-capture/mode-local.md +2 -2
- package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +20 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +17 -8
- package/dist/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +58 -14
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +41 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +7 -0
- package/dist/orchestrator/templates/playwright.config.ts +4 -2
- package/dist/orchestrator/templates/specs-url-assert.d.ts.map +1 -1
- package/dist/orchestrator/templates/specs-url-assert.js +24 -2
- package/dist/orchestrator/templates/specs-url-assert.js.map +1 -1
- package/dist/orchestrator/templates/specs-url-assert.ts +23 -2
- package/dist/orchestrator/trace-mode-install.d.ts +14 -0
- package/dist/orchestrator/trace-mode-install.d.ts.map +1 -0
- package/dist/orchestrator/trace-mode-install.js +132 -0
- package/dist/orchestrator/trace-mode-install.js.map +1 -0
- package/dist/orchestrator/viewpoint-pattern-catalog.d.ts +20 -0
- package/dist/orchestrator/viewpoint-pattern-catalog.d.ts.map +1 -0
- package/dist/orchestrator/viewpoint-pattern-catalog.js +45 -0
- package/dist/orchestrator/viewpoint-pattern-catalog.js.map +1 -0
- package/package.json +3 -3
- package/src/cli/commands/audit.ts +14 -3
- package/src/cli/commands/changed.ts +2 -4
- package/src/cli/commands/dashboard.ts +1 -26
- package/src/cli/commands/delivery.ts +37 -32
- package/src/cli/commands/results-merge.ts +7 -1
- package/src/cli/commands/select.ts +88 -0
- package/src/cli/commands/update.ts +3 -0
- package/src/cli/index.ts +7 -2
- package/src/dashboard/templates/index.html +1 -1
- package/src/dashboard/types.ts +1 -0
- package/src/exporters/csv-exporter.ts +7 -10
- package/src/exporters/json-exporter.ts +6 -1
- package/src/exporters/manual-hybrid-oracle.ts +112 -0
- package/src/exporters/matrix/build.ts +6 -2
- package/src/exporters/matrix/export.ts +4 -0
- package/src/exporters/matrix/gates.ts +6 -0
- package/src/exporters/matrix/render-testcase-sheet.ts +10 -4
- package/src/exporters/matrix/types.ts +8 -1
- package/src/exporters/matrix/wording.ts +10 -1
- package/src/exporters/run-environment.ts +89 -0
- package/src/exporters/scenario-merger.ts +49 -4
- package/src/exporters/test-data-resolver.ts +0 -6
- package/src/generators/gherkin-parser/index.ts +50 -18
- package/src/generators/test-generator/adapters/adapter-interface.ts +4 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/click-select-action.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/select-action.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/pick-option.hbs +13 -0
- package/src/generators/test-generator/adapters/playwright/templates/test-file.hbs +16 -0
- package/src/generators/test-generator/code-generator.ts +23 -2
- package/src/generators/test-generator/diagnostics.ts +3 -1
- package/src/harness/audit.ts +20 -9
- package/src/harness/data-driven-lint.ts +82 -24
- package/src/harness/next-step.ts +1 -0
- package/src/harness/parse.ts +123 -16
- package/src/harness/quality-gates.ts +6 -4
- package/src/harness/read-text.ts +25 -0
- package/src/harness/select-by-ids.ts +83 -0
- package/src/harness/sensors.ts +59 -9
- package/src/harness/spec-branches.ts +1 -1
- package/src/harness/ui-inventory.ts +164 -0
- package/src/harness/viewpoint-ledger.ts +57 -11
- package/src/orchestrator/screen-manager.ts +3 -11
- package/src/orchestrator/templates/ai-src/agents/discovery.md +11 -3
- package/src/orchestrator/templates/ai-src/agents/reviewer.md +8 -0
- package/src/orchestrator/templates/ai-src/commands/create-test.md +2 -2
- package/src/orchestrator/templates/ai-src/commands/review.md +2 -2
- package/src/orchestrator/templates/ai-src/commands/run-test.md +70 -13
- package/src/orchestrator/templates/ai-src/skills/sungen-capture/mode-local.md +2 -2
- package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +20 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +17 -8
- package/src/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +58 -14
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +41 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +7 -0
- package/src/orchestrator/templates/playwright.config.ts +4 -2
- package/src/orchestrator/templates/specs-url-assert.ts +23 -2
- package/src/orchestrator/trace-mode-install.ts +94 -0
- package/src/orchestrator/viewpoint-pattern-catalog.ts +58 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VIEWPOINT_PATTERNS = void 0;
|
|
4
|
+
exports.uiPatternRows = uiPatternRows;
|
|
5
|
+
exports.VIEWPOINT_PATTERNS = [
|
|
6
|
+
{ n: 1, name: 'Form & Inputs' },
|
|
7
|
+
{ n: 2, name: 'File Upload' },
|
|
8
|
+
{ n: 3, name: 'Import / Export' },
|
|
9
|
+
{ n: 4, name: 'Create / Add' },
|
|
10
|
+
{ n: 5, name: 'Update / Edit' },
|
|
11
|
+
{ n: 6, name: 'Delete' },
|
|
12
|
+
{ n: 7, name: 'Data Table' },
|
|
13
|
+
{ n: 8, name: 'Search' },
|
|
14
|
+
{ n: 9, name: 'Filter' },
|
|
15
|
+
{ n: 10, name: 'List / Card View' },
|
|
16
|
+
{ n: 11, name: 'Chart / Analytics' },
|
|
17
|
+
{ n: 12, name: 'Modal / Dialog' },
|
|
18
|
+
{ n: 13, name: 'Navigation' },
|
|
19
|
+
{ n: 14, name: 'Notification / Toast / Alert' },
|
|
20
|
+
{ n: 15, name: 'Login / Logout' },
|
|
21
|
+
{ n: 16, name: 'Register' },
|
|
22
|
+
{ n: 17, name: 'Password Management' },
|
|
23
|
+
{ n: 18, name: 'Bottom Sheet', mobile: true },
|
|
24
|
+
{ n: 19, name: 'Tab Bar / Bottom Navigation', mobile: true },
|
|
25
|
+
{ n: 20, name: 'Swipe-to-Delete Row', mobile: true },
|
|
26
|
+
{ n: 21, name: 'Native Picker', mobile: true },
|
|
27
|
+
{ n: 22, name: 'Permission Dialog', mobile: true },
|
|
28
|
+
{ n: 23, name: 'Biometric Prompt', mobile: true },
|
|
29
|
+
{ n: 24, name: 'Camera / Gallery Picker', mobile: true },
|
|
30
|
+
{ n: 25, name: 'Push Notification', mobile: true },
|
|
31
|
+
{ n: 26, name: 'Deep-link Entry', mobile: true },
|
|
32
|
+
{ n: 27, name: 'Offline Banner', mobile: true },
|
|
33
|
+
{ n: 28, name: 'Onboarding Carousel', mobile: true },
|
|
34
|
+
{ n: 29, name: 'Pull-to-Refresh List', mobile: true },
|
|
35
|
+
{ n: 30, name: 'Soft-Keyboard Overlap', mobile: true },
|
|
36
|
+
{ n: 31, name: 'Settings Toggle List', mobile: true },
|
|
37
|
+
{ n: 32, name: 'App Lifecycle & Orientation', mobile: true },
|
|
38
|
+
];
|
|
39
|
+
/** The scaffold's pattern-table rows: 1–17 for every screen, plus Group F on a mobile project. */
|
|
40
|
+
function uiPatternRows(isMobile) {
|
|
41
|
+
return exports.VIEWPOINT_PATTERNS
|
|
42
|
+
.filter((p) => isMobile || !p.mobile)
|
|
43
|
+
.map((p) => `| ${p.n} | ${p.name} | ☐ | |`);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=viewpoint-pattern-catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewpoint-pattern-catalog.js","sourceRoot":"","sources":["../../src/orchestrator/viewpoint-pattern-catalog.ts"],"names":[],"mappings":";;;AAqDA,sCAIC;AAxCY,QAAA,kBAAkB,GAAgC;IAC7D,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE;IAC/B,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE;IAC7B,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE;IACjC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE;IAC9B,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE;IAC/B,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE;IACxB,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE;IAC5B,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE;IACxB,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE;IACxB,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE;IACnC,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE;IACpC,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE;IACjC,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;IAC7B,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,8BAA8B,EAAE;IAC/C,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE;IACjC,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;IAC3B,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE;IACtC,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE;IAC7C,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,6BAA6B,EAAE,MAAM,EAAE,IAAI,EAAE;IAC5D,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,MAAM,EAAE,IAAI,EAAE;IACpD,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE;IAC9C,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,EAAE,IAAI,EAAE;IAClD,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,IAAI,EAAE;IACjD,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,yBAAyB,EAAE,MAAM,EAAE,IAAI,EAAE;IACxD,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,EAAE,IAAI,EAAE;IAClD,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,EAAE;IAChD,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,IAAI,EAAE;IAC/C,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,MAAM,EAAE,IAAI,EAAE;IACpD,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,MAAM,EAAE,IAAI,EAAE;IACrD,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,uBAAuB,EAAE,MAAM,EAAE,IAAI,EAAE;IACtD,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,MAAM,EAAE,IAAI,EAAE;IACrD,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,6BAA6B,EAAE,MAAM,EAAE,IAAI,EAAE;CAC7D,CAAC;AAEF,kGAAkG;AAClG,SAAgB,aAAa,CAAC,QAAiB;IAC7C,OAAO,0BAAkB;SACtB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;SACpC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC;AAChD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sun-asterisk/sungen",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.34",
|
|
4
4
|
"description": "Deterministic E2E Test Compiler - Gherkin + Selectors → Playwright tests",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"@babel/types": "^7.28.5",
|
|
41
41
|
"@cucumber/gherkin": "^37.0.0",
|
|
42
42
|
"@cucumber/messages": "^31.0.0",
|
|
43
|
-
"@sungen/driver-data-factory": "3.2.
|
|
44
|
-
"@sungen/driver-ui": "3.2.
|
|
43
|
+
"@sungen/driver-data-factory": "3.2.34",
|
|
44
|
+
"@sungen/driver-ui": "3.2.34",
|
|
45
45
|
"chalk": "^5.6.2",
|
|
46
46
|
"commander": "^14.0.2",
|
|
47
47
|
"dotenv": "^17.2.3",
|
|
@@ -15,6 +15,14 @@ export function bar(ratio: number, width = 20): string {
|
|
|
15
15
|
return '█'.repeat(n) + '░'.repeat(width - n);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
/** The ⑥ headline. No viewpoint ID read → nothing was matched, so `0%` would read as a measured
|
|
19
|
+
* failure; say `n/a` and why instead (#832). Same with no scenario yet (#852). */
|
|
20
|
+
export function traceabilityHeadline(trace: AuditReport['trace']): string {
|
|
21
|
+
if (trace.overviewIds === 0) return ' ⑥ Traceability — n/a (no viewpoint ID found in test-viewpoint.md)';
|
|
22
|
+
if (trace.total === 0) return ' ⑥ Traceability — n/a (no scenarios yet)';
|
|
23
|
+
return ` ⑥ Traceability — ${(trace.mappedRatio * 100).toFixed(0)}% scenarios linked to viewpoint-overview`;
|
|
24
|
+
}
|
|
25
|
+
|
|
18
26
|
function render(r: AuditReport): void {
|
|
19
27
|
const L = console.log;
|
|
20
28
|
L('');
|
|
@@ -82,7 +90,7 @@ function render(r: AuditReport): void {
|
|
|
82
90
|
if (r.depth.shallowBusinessCritical.length > 8) L(` … +${r.depth.shallowBusinessCritical.length - 8} more`);
|
|
83
91
|
L('');
|
|
84
92
|
L(` ③ Claim-Proof — ${r.claim.proven}/${r.claim.withClaims} titled claims proven by steps [${r.claim.verdict.toUpperCase()}]`);
|
|
85
|
-
if (r.claim.unproven.length === 0) L(' ✓ every claim (all/only/single/correct/changes/hidden) is backed by an assertion');
|
|
93
|
+
if (r.claim.unproven.length === 0) L(' ✓ every claim (all/only/single/correct/changes/hidden/order/limit) is backed by an assertion');
|
|
86
94
|
for (const u of r.claim.unproven.slice(0, 8)) L(` ${u.severity === 'fail' ? '✗' : '⚠'} [${u.claim}] ${u.name} → needs ${u.need}`);
|
|
87
95
|
if (r.claim.unproven.length > 8) L(` … +${r.claim.unproven.length - 8} more`);
|
|
88
96
|
L('');
|
|
@@ -110,7 +118,7 @@ function render(r: AuditReport): void {
|
|
|
110
118
|
}
|
|
111
119
|
}
|
|
112
120
|
L('');
|
|
113
|
-
L(
|
|
121
|
+
L(traceabilityHeadline(r.trace));
|
|
114
122
|
L(` ${r.trace.note}`);
|
|
115
123
|
L('');
|
|
116
124
|
if (r.spec.hasSpec && (r.spec.frTotal > 0 || r.spec.triggerGaps.length > 0 || r.spec.verdict !== 'pass')) {
|
|
@@ -198,7 +206,10 @@ export function registerAuditCommand(program: Command): void {
|
|
|
198
206
|
console.log(' Re-run the audit to score atomicLedger + traceability against it.\n');
|
|
199
207
|
}
|
|
200
208
|
} else if (options.acceptViewpoint && !options.json) {
|
|
201
|
-
|
|
209
|
+
// `absent` covers a file with no readable viewpoint id too — say which (#832).
|
|
210
|
+
console.log(vb.status === 'absent'
|
|
211
|
+
? `\n ○ nothing to accept for ${name} — no viewpoint ID found in requirements/test-viewpoint.md (missing file, or no section declares one).\n`
|
|
212
|
+
: `\n ○ nothing to accept for ${name} — the viewpoint baseline is ${vb.status}.\n`);
|
|
202
213
|
}
|
|
203
214
|
|
|
204
215
|
// Persist report under .sungen/reports/ (flat slug: api flow `flows/x` → `flows-x-audit.json`).
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { Command } from 'commander';
|
|
13
13
|
import { buildRunManifest, readRunManifest, writeRunManifest, selectChanged } from '../../harness/run-manifest';
|
|
14
14
|
import { findUnitDir } from '../resolve-unit';
|
|
15
|
+
import { titlesToGrep } from '../../harness/select-by-ids';
|
|
15
16
|
import { execFileSync } from 'child_process';
|
|
16
17
|
import * as path from 'path';
|
|
17
18
|
|
|
@@ -40,9 +41,6 @@ function gitChangedFiles(unitDir: string): string[] {
|
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
/** Escape a scenario title for a `-g` / `--mochaOpts.grep` regex. */
|
|
44
|
-
const toGrep = (titles: string[]): string =>
|
|
45
|
-
titles.map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
|
|
46
44
|
|
|
47
45
|
export function registerChangedCommand(program: Command): void {
|
|
48
46
|
program
|
|
@@ -75,7 +73,7 @@ export function registerChangedCommand(program: Command): void {
|
|
|
75
73
|
if (options.grep) {
|
|
76
74
|
// Empty output is meaningful: nothing to run. A caller must treat "" as "skip the run",
|
|
77
75
|
// never as "match everything" — an empty grep would run the whole suite.
|
|
78
|
-
console.log(
|
|
76
|
+
console.log(titlesToGrep(selection.scenarios));
|
|
79
77
|
return;
|
|
80
78
|
}
|
|
81
79
|
if (options.json) { console.log(JSON.stringify(selection, null, 2)); return; }
|
|
@@ -11,8 +11,7 @@ import { Command } from 'commander';
|
|
|
11
11
|
import * as path from 'path';
|
|
12
12
|
import * as fs from 'fs';
|
|
13
13
|
import { execSync } from 'child_process';
|
|
14
|
-
import {
|
|
15
|
-
import { resolveWebBaseUrl } from '../../exporters/env-qa';
|
|
14
|
+
import { getEnvironment } from '../../exporters/run-environment';
|
|
16
15
|
import {
|
|
17
16
|
buildDashboardSnapshot,
|
|
18
17
|
DashboardTarget,
|
|
@@ -37,30 +36,6 @@ const COLOR = {
|
|
|
37
36
|
|
|
38
37
|
function log(msg: string): void { console.log(msg); }
|
|
39
38
|
|
|
40
|
-
function getEnvironment(cwd: string): EnvironmentInfo {
|
|
41
|
-
let baseURL = '';
|
|
42
|
-
let projectName = 'chromium';
|
|
43
|
-
const configPath = path.join(cwd, 'playwright.config.ts');
|
|
44
|
-
if (fs.existsSync(configPath)) {
|
|
45
|
-
const c = fs.readFileSync(configPath, 'utf-8');
|
|
46
|
-
// Both config shapes: legacy literal and env-aware resolveBaseUrl('x') wrapper.
|
|
47
|
-
const baseMatch = c.match(/baseURL:\s*(?:resolveBaseUrl\(\s*)?['"]([^'"]+)['"]/);
|
|
48
|
-
if (baseMatch) baseURL = baseMatch[1];
|
|
49
|
-
const projMatch = c.match(/name:\s*['"]([^'"]+)['"]/);
|
|
50
|
-
if (projMatch) projectName = projMatch[1];
|
|
51
|
-
}
|
|
52
|
-
// Same SUNGEN_BASE_URL override as delivery — the two surfaces must agree.
|
|
53
|
-
baseURL = resolveWebBaseUrl(cwd, baseURL);
|
|
54
|
-
|
|
55
|
-
let executor = process.env.CI_USER || process.env.USER || '';
|
|
56
|
-
try {
|
|
57
|
-
const gitUser = execSync('git config user.name', { cwd, encoding: 'utf-8' }).trim();
|
|
58
|
-
if (gitUser) executor = gitUser;
|
|
59
|
-
} catch { /* ignore */ }
|
|
60
|
-
|
|
61
|
-
return { baseURL, projectName, executor };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
39
|
interface DashboardOptions {
|
|
65
40
|
noHistory?: boolean;
|
|
66
41
|
open?: boolean;
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
import { Command } from 'commander';
|
|
7
7
|
import * as path from 'path';
|
|
8
8
|
import * as fs from 'fs';
|
|
9
|
-
import { execSync } from 'child_process';
|
|
10
9
|
import { parse as parseYaml } from 'yaml';
|
|
11
10
|
import { parseFeatureMetadata } from '../../exporters/feature-parser';
|
|
12
11
|
import { parseSpecFile } from '../../exporters/spec-parser';
|
|
@@ -24,7 +23,7 @@ import {
|
|
|
24
23
|
import { renderXlsxMultiSheet, writeXlsx, buildApiDetailRows, addApiDetailSheet } from '../../exporters/xlsx-exporter';
|
|
25
24
|
import { loadApiCatalog } from '../../exporters/api-catalog-loader';
|
|
26
25
|
import { resolveApiEnvironment } from '../../exporters/api-environment';
|
|
27
|
-
import {
|
|
26
|
+
import { getEnvironment, platformOfResultFile, RunEnvironment } from '../../exporters/run-environment';
|
|
28
27
|
import { resolvePlatformAppId } from '../../exporters/mobile-app-id';
|
|
29
28
|
import { scanTestDataSecrets, formatSecretScan, type SecretScanResult } from '../../harness/secret-scan';
|
|
30
29
|
import { EnvironmentInfo, PreflightCheck, ScreenSummary, TestCaseRow, ApiCatalogEntry } from '../../exporters/types';
|
|
@@ -342,34 +341,27 @@ export function hasBlockingMissing(p: PreflightCheck): boolean {
|
|
|
342
341
|
// Environment
|
|
343
342
|
// ----------------------------------------------------------------------------
|
|
344
343
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
if (fs.existsSync(configPath)) {
|
|
350
|
-
const c = fs.readFileSync(configPath, 'utf-8');
|
|
351
|
-
// Both config shapes: the legacy literal `baseURL: 'x'` and the env-aware
|
|
352
|
-
// `baseURL: resolveBaseUrl('x')` (the quoted value is the static fallback).
|
|
353
|
-
const baseMatch = c.match(/baseURL:\s*(?:resolveBaseUrl\(\s*)?['"]([^'"]+)['"]/);
|
|
354
|
-
if (baseMatch) baseURL = baseMatch[1];
|
|
355
|
-
const projMatch = c.match(/name:\s*['"]([^'"]+)['"]/);
|
|
356
|
-
if (projMatch) projectName = projMatch[1];
|
|
357
|
-
}
|
|
358
|
-
// SUNGEN_BASE_URL (shell > .env.qa.<SUNGEN_ENV> > .env.qa) overrides the static
|
|
359
|
-
// value — the Test Environment column must show the host the run actually hit.
|
|
360
|
-
baseURL = resolveWebBaseUrl(cwd, baseURL);
|
|
361
|
-
|
|
362
|
-
let executor = process.env.CI_USER || process.env.USER || '';
|
|
363
|
-
try {
|
|
364
|
-
const gitUser = execSync('git config user.name', { cwd, encoding: 'utf-8' }).trim();
|
|
365
|
-
if (gitUser) executor = gitUser;
|
|
366
|
-
} catch {
|
|
367
|
-
// ignore
|
|
368
|
-
}
|
|
344
|
+
/** The unit's path for the Environment column — a flow records it in its page selector. */
|
|
345
|
+
function targetFeaturePath(target: DeliveryTarget, declared: string | undefined, selectorsFile: string): string | undefined {
|
|
346
|
+
return declared || (target.isFlow ? readFlowPagePath(selectorsFile) : undefined);
|
|
347
|
+
}
|
|
369
348
|
|
|
370
|
-
|
|
349
|
+
/**
|
|
350
|
+
* Executor + environment for the matrix's run-result rows (#850) — resolved exactly as the
|
|
351
|
+
* legacy workbook resolves them: the API datasource host for an api unit, and on mobile the
|
|
352
|
+
* app id of the OS the result file came from (`<f>-test-result.<os>[.<env>].json`).
|
|
353
|
+
*/
|
|
354
|
+
function matrixRunEnv(cwd: string, target: DeliveryTarget, env: EnvironmentInfo, paths: MatrixTargetPaths): RunEnvironment {
|
|
355
|
+
const base = qaDir(cwd, target);
|
|
356
|
+
let declared: string | undefined;
|
|
357
|
+
try { declared = parseFeatureMetadata(paths.featureFile).featurePath; } catch { /* loadMatrixModel reports it */ }
|
|
358
|
+
const featurePath = targetFeaturePath(target, declared, path.join(base, 'selectors', `${target.featureBaseName}.yaml`));
|
|
359
|
+
const apiEnv = target.kind === 'api' ? resolveApiEnvironment(cwd, loadApiCatalog(cwd, target.kind, target.screen)) : null;
|
|
360
|
+
const os = platformOfResultFile(paths.resultsPath) ?? process.env.MOBILE_PLATFORM ?? process.env.SUNGEN_ENV;
|
|
361
|
+
return { ...env, ...(apiEnv ?? {}), featurePath: resolvePlatformAppId(featurePath, os) };
|
|
371
362
|
}
|
|
372
363
|
|
|
364
|
+
|
|
373
365
|
/**
|
|
374
366
|
* True when this is a mobile project (`platform: mobile` in qa/capabilities.yaml).
|
|
375
367
|
* Mobile results are written PER-OS (`<feature>-test-result.android|ios.json`) —
|
|
@@ -405,6 +397,18 @@ function removeBaseDeliverables(cwd: string, featureBaseName: string): void {
|
|
|
405
397
|
// Per-screen export
|
|
406
398
|
// ----------------------------------------------------------------------------
|
|
407
399
|
|
|
400
|
+
/**
|
|
401
|
+
* #810 — a manual oracle that lives only in unlabelled `Tester verifies:` prose is exported
|
|
402
|
+
* verbatim into Expected (never dropped), and the author is told to structure it.
|
|
403
|
+
*/
|
|
404
|
+
function warnUnlabeledManualOracles(label: string, merged: ReturnType<typeof mergeFeatureAndSpec>): void {
|
|
405
|
+
const hits = merged.filter((m) => m.unlabeledManualOracle);
|
|
406
|
+
if (!hits.length) return;
|
|
407
|
+
log(`${COLOR.yellow}⚠ ${label}: manual oracle found only in an unlabeled comment (${hits.length})${COLOR.reset} — exported verbatim into Expected; write it as numbered "N. Observable: …" lines:`);
|
|
408
|
+
for (const m of hits.slice(0, 10)) log(` ${m.feature.name.slice(0, 90)}`);
|
|
409
|
+
if (hits.length > 10) log(` … and ${hits.length - 10} more`);
|
|
410
|
+
}
|
|
411
|
+
|
|
408
412
|
async function exportTarget(
|
|
409
413
|
cwd: string,
|
|
410
414
|
target: DeliveryTarget,
|
|
@@ -423,14 +427,12 @@ async function exportTarget(
|
|
|
423
427
|
const spec = parseSpecFile(specFile);
|
|
424
428
|
|
|
425
429
|
const merged = mergeFeatureAndSpec(feature, spec);
|
|
430
|
+
warnUnlabeledManualOracles(label, merged);
|
|
426
431
|
// Screens get their URL path from the .feature file directly. Flows record
|
|
427
432
|
// it in selectors/<feature>.yaml under the page-selector block — fall back
|
|
428
433
|
// to that so the Environment column shows a full URL for flows too.
|
|
429
|
-
let featurePath = feature.featurePath;
|
|
430
434
|
const selectorsFile = path.join(base, 'selectors', `${target.featureBaseName}.yaml`);
|
|
431
|
-
|
|
432
|
-
featurePath = readFlowPagePath(selectorsFile);
|
|
433
|
-
}
|
|
435
|
+
const featurePath = targetFeaturePath(target, feature.featurePath, selectorsFile);
|
|
434
436
|
const selectorKeyMap = loadSelectorKeyMap(selectorsFile);
|
|
435
437
|
|
|
436
438
|
const specLink = fs.existsSync(specMdFile) ? path.relative(cwd, specMdFile) : '';
|
|
@@ -673,8 +675,10 @@ async function exportMatrixTarget(
|
|
|
673
675
|
cwd: string,
|
|
674
676
|
target: DeliveryTarget,
|
|
675
677
|
opts: { check?: boolean; preview?: boolean; format?: MatrixFormat },
|
|
678
|
+
env: EnvironmentInfo,
|
|
676
679
|
): Promise<MatrixRunSummary | 'skipped' | null> {
|
|
677
680
|
const paths = matrixPathsFor(cwd, target);
|
|
681
|
+
paths.runEnv = matrixRunEnv(cwd, target, env, paths);
|
|
678
682
|
|
|
679
683
|
// A feature whose scenarios are ALL @exploration probes has nothing to deliver —
|
|
680
684
|
// skip it quietly (no map required) instead of demanding a reviewed grouping for
|
|
@@ -1004,10 +1008,11 @@ export function registerDeliveryCommand(program: Command): void {
|
|
|
1004
1008
|
|
|
1005
1009
|
const matrixSummaries: MatrixRunSummary[] = [];
|
|
1006
1010
|
const notExported: string[] = [];
|
|
1011
|
+
const env = getEnvironment(cwd);
|
|
1007
1012
|
for (const target of toExport) {
|
|
1008
1013
|
const s = await exportMatrixTarget(cwd, target, {
|
|
1009
1014
|
check: options.check, preview: options.preview, format: format as MatrixFormat,
|
|
1010
|
-
});
|
|
1015
|
+
}, env);
|
|
1011
1016
|
if (s === 'skipped') continue; // all-@exploration feature — neither exported nor a failure
|
|
1012
1017
|
if (s) matrixSummaries.push(s);
|
|
1013
1018
|
else notExported.push(target.isFlow ? `flow/${target.featureBaseName}` : target.featureBaseName);
|
|
@@ -39,7 +39,7 @@ function readReport(file: string, label: string): any {
|
|
|
39
39
|
* (flows → screens → api → api flows); the same basename found in more than one
|
|
40
40
|
* place is an ambiguity error, never a silent pick.
|
|
41
41
|
*/
|
|
42
|
-
function resolveFeatureDir(cwd: string, name: string): string {
|
|
42
|
+
export function resolveFeatureDir(cwd: string, name: string): string {
|
|
43
43
|
const roots = [
|
|
44
44
|
path.join(cwd, 'specs', 'generated', 'flows'),
|
|
45
45
|
path.join(cwd, 'specs', 'generated'),
|
|
@@ -89,6 +89,12 @@ export function runResultsMerge(baseArg: string | undefined, newArg: string | un
|
|
|
89
89
|
if (!baseFile || path.dirname(baseFile) !== dir) {
|
|
90
90
|
throw new Error(`results merge: no per-target result file for "${opts.screen}" in ${path.relative(cwd, dir)} — nothing to merge into (a first full run writes it directly).`);
|
|
91
91
|
}
|
|
92
|
+
// Under SUNGEN_ENV the candidate order falls back to the base-locale file when the env file
|
|
93
|
+
// does not exist yet; merging a `vi` subset there would overwrite `ja`/base results in silence.
|
|
94
|
+
const env = process.env.SUNGEN_ENV;
|
|
95
|
+
if (env && !path.basename(baseFile).endsWith(`.${env}.json`)) {
|
|
96
|
+
throw new Error(`results merge: SUNGEN_ENV=${env} but "${opts.screen}" has no ${env} result file yet (found ${path.basename(baseFile)}) — run the full ${env} suite first; it writes the file directly.`);
|
|
97
|
+
}
|
|
92
98
|
// Ghost/foreign-title checks need the CURRENT spec titles.
|
|
93
99
|
const specFile = path.join(dir, `${opts.screen}.spec.ts`);
|
|
94
100
|
try { specTitles = parseSpecFile(specFile).tests.map((t) => t.testTitle); } catch { specTitles = null; }
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sungen select` — which tests does a list of test-case IDs name? (#835)
|
|
3
|
+
*
|
|
4
|
+
* Backs `run-test --ids`. Like `sungen changed` for `--change-only`, the selection is computed here
|
|
5
|
+
* so it is deterministic and testable; the workflow only runs it and merges the subset result into
|
|
6
|
+
* the existing per-feature result file.
|
|
7
|
+
*
|
|
8
|
+
* Fails loud: an ID that selects nothing runnable exits non-zero, because a 0-test run reports green.
|
|
9
|
+
*/
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
import * as path from 'path';
|
|
12
|
+
import { findUnitDir } from '../resolve-unit';
|
|
13
|
+
import { loadUnitScenarios } from '../../harness/parse';
|
|
14
|
+
import { parseIdList, selectByIds } from '../../harness/select-by-ids';
|
|
15
|
+
import { resolveFeatureDir } from './results-merge';
|
|
16
|
+
import { readCapabilities } from '../../harness/capability';
|
|
17
|
+
import { projectRootFromScreenDir } from '../../harness/intent';
|
|
18
|
+
|
|
19
|
+
export function registerSelectCommand(program: Command): void {
|
|
20
|
+
program
|
|
21
|
+
.command('select')
|
|
22
|
+
.description('List the tests a set of test-case IDs selects, grouped per feature (backs run-test --ids)')
|
|
23
|
+
.option('-s, --screen <name>', 'Screen or flow name')
|
|
24
|
+
.option('--api <name>', 'API-first area or api flow (qa/api/<name>)')
|
|
25
|
+
.option('--area <name>', 'Alias of --api')
|
|
26
|
+
.requiredOption('--ids <list>', 'Test-case IDs, comma- or space-separated (e.g. VP-UI-001,VP-UI-002)')
|
|
27
|
+
.option('--json', 'Output the selection as JSON (per feature: spec, ids, titles, grep)')
|
|
28
|
+
.option('--grep', 'Output ONLY the regex for -g / --mochaOpts.grep (selection must lie in one feature)')
|
|
29
|
+
.action((options) => {
|
|
30
|
+
try {
|
|
31
|
+
const name = options.screen || options.api || options.area;
|
|
32
|
+
if (!name) throw new Error('Provide --screen <name> (or --api <area>)');
|
|
33
|
+
const dir = findUnitDir(name);
|
|
34
|
+
if (!dir) throw new Error(`Not found: qa/screens|flows|api/${name}`);
|
|
35
|
+
const ids = parseIdList(options.ids);
|
|
36
|
+
if (ids.length === 0) throw new Error('--ids is empty — pass at least one test-case ID');
|
|
37
|
+
|
|
38
|
+
const cwd = process.cwd();
|
|
39
|
+
// Same capability set `generate` compiles against: a @requires:<cap> scenario is a skip without it.
|
|
40
|
+
const enabledCaps = new Set(readCapabilities(projectRootFromScreenDir(path.resolve(dir))).enabled.map((c) => c.toLowerCase()));
|
|
41
|
+
const selection = selectByIds(loadUnitScenarios(dir, name), ids, name, enabledCaps);
|
|
42
|
+
// Resolve each feature's compiled spec: a test cannot run before `sungen generate`.
|
|
43
|
+
const features = selection.features.map((g) => {
|
|
44
|
+
let spec: string | null = null;
|
|
45
|
+
try { spec = path.relative(cwd, path.join(resolveFeatureDir(cwd, g.feature), `${g.feature}.spec.ts`)); } catch { /* reported below */ }
|
|
46
|
+
return { ...g, spec };
|
|
47
|
+
});
|
|
48
|
+
const notCompiled = features.filter((f) => !f.spec).map((f) => f.feature);
|
|
49
|
+
const failed = selection.unknown.length > 0 || selection.notRunnable.length > 0 || notCompiled.length > 0 || features.length === 0;
|
|
50
|
+
|
|
51
|
+
if (options.json) {
|
|
52
|
+
console.log(JSON.stringify({ unit: name, features, unknown: selection.unknown, notRunnable: selection.notRunnable, notCompiled }, null, 2));
|
|
53
|
+
if (failed) process.exitCode = 1;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (options.grep) {
|
|
57
|
+
// Only a clean single-feature selection prints a regex; anything else must not be run
|
|
58
|
+
// as if it were complete, so it prints nothing and exits non-zero.
|
|
59
|
+
if (failed || features.length !== 1) {
|
|
60
|
+
console.error(features.length > 1
|
|
61
|
+
? `select: the IDs span ${features.length} features (${features.map((f) => f.feature).join(', ')}) — use --json and run each feature on its own.`
|
|
62
|
+
: 'select: nothing runnable for these IDs — run without --grep to see why.');
|
|
63
|
+
process.exitCode = 1;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
console.log(features[0].grep);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const selected = features.reduce((n, f) => n + f.titles.length, 0);
|
|
71
|
+
// A @cases scenario expands to one test per dataset row, so this counts scenarios.
|
|
72
|
+
console.log(`\n ${selected} scenario(s) selected for ${ids.length} ID(s) in ${name}:\n`);
|
|
73
|
+
for (const f of features) {
|
|
74
|
+
console.log(` ${f.feature} → ${f.spec ?? '(not compiled — run sungen generate first)'}`);
|
|
75
|
+
for (const t of f.titles) console.log(` ▶ ${t}`);
|
|
76
|
+
}
|
|
77
|
+
for (const u of selection.unknown) {
|
|
78
|
+
console.log(` ✗ ${u.id} — no scenario has this ID${u.didYouMean.length ? ` (did you mean ${u.didYouMean.join(', ')}?)` : ''}`);
|
|
79
|
+
}
|
|
80
|
+
for (const n of selection.notRunnable) console.log(` ○ ${n.id} — ${n.reason}`);
|
|
81
|
+
console.log('');
|
|
82
|
+
if (failed) process.exitCode = 1;
|
|
83
|
+
} catch (err) {
|
|
84
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
85
|
+
process.exitCode = 1;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
@@ -103,6 +103,9 @@ export function registerUpdateCommand(program: Command): void {
|
|
|
103
103
|
// playwright.config.ts is written once at init and never re-synced — patch the reporter in.
|
|
104
104
|
const { installReportSanitizeReporter } = require('../../orchestrator/report-sanitize-reporter-install');
|
|
105
105
|
installReportSanitizeReporter(process.cwd(), options.dryRun ?? false);
|
|
106
|
+
// …and move the old `trace: 'on-first-retry'` default, which never records a trace off CI.
|
|
107
|
+
const { installTraceMode } = require('../../orchestrator/trace-mode-install');
|
|
108
|
+
installTraceMode(process.cwd(), options.dryRun ?? false);
|
|
106
109
|
} catch (error) {
|
|
107
110
|
console.error('❌ Update failed:', error);
|
|
108
111
|
process.exit(1);
|
package/src/cli/index.ts
CHANGED
|
@@ -24,6 +24,7 @@ import { registerIngestCommand } from './commands/ingest';
|
|
|
24
24
|
import { registerEvalCommand } from './commands/eval';
|
|
25
25
|
import { registerManifestCommand } from './commands/manifest';
|
|
26
26
|
import { registerChangedCommand } from './commands/changed';
|
|
27
|
+
import { registerSelectCommand } from './commands/select';
|
|
27
28
|
import { registerLedgerCommand } from './commands/ledger';
|
|
28
29
|
import { registerFeedbackCommand } from './commands/feedback';
|
|
29
30
|
import { registerQaFeedbackCommand } from './commands/qa-feedback';
|
|
@@ -75,6 +76,7 @@ registerSetupMobileEnvCommand(program);
|
|
|
75
76
|
registerGateCommand(program);
|
|
76
77
|
registerManifestCommand(program);
|
|
77
78
|
registerChangedCommand(program);
|
|
79
|
+
registerSelectCommand(program);
|
|
78
80
|
registerLedgerCommand(program);
|
|
79
81
|
registerFeedbackCommand(program);
|
|
80
82
|
registerQaFeedbackCommand(program);
|
|
@@ -123,12 +125,15 @@ registerSetupMobileEnvCommand(program);
|
|
|
123
125
|
const opts = actionCommand.opts() as Record<string, unknown>;
|
|
124
126
|
const unit = [opts.screen, opts.flow, opts.area].find((v) => typeof v === 'string' && v)
|
|
125
127
|
?? (typeof actionCommand.args?.[0] === 'string' ? actionCommand.args[0] : undefined);
|
|
126
|
-
|
|
128
|
+
// `--grep` is machine output too: callers capture it with `$(…)`, and a footer on stdout
|
|
129
|
+
// became part of the regex — the last alternative of `changed --grep` silently matched
|
|
130
|
+
// nothing, so `--change-only` skipped its last scenario (#836).
|
|
131
|
+
handBack = { unit: unit as string | undefined, json: opts.json === true || opts.grep === true };
|
|
127
132
|
});
|
|
128
133
|
process.on('exit', (code) => {
|
|
129
134
|
if (!handBack || code === 1) return;
|
|
130
135
|
const line = `\nNext: sungen next${handBack.unit ? ` ${handBack.unit}` : ''}`;
|
|
131
|
-
// stderr under --json so the hand-back never lands in the
|
|
136
|
+
// stderr under --json / --grep so the hand-back never lands in the captured payload.
|
|
132
137
|
if (handBack.json) process.stderr.write(`${line}\n`);
|
|
133
138
|
else process.stdout.write(`${line}\n`);
|
|
134
139
|
});
|
|
@@ -121,7 +121,7 @@ use chrome, FireFox or Internet Explorer 11`)}var a=e(`safe-buffer`),o=e(`random
|
|
|
121
121
|
(Test evidence, DefectID, Actual result)`]));let f=[`Accessing`,`GUI`,`Function`],p=new Map;for(let e of o){let t=p.get(e.category2)||[];t.push(e),p.set(e.category2,t)}let m=new Set,h=(e,t)=>{d.push(UN([``,e,``,``,``,``,``,``,``,``,``,``,``,``,``,``]));for(let e of t)d.push(UN(LN(e)))};for(let e of f){let t=p.get(e);!t||t.length===0||(m.add(e),h(e,t))}for(let[e,t]of p.entries())m.has(e)||h(e,t);return``+d.join(`
|
|
122
122
|
`)+`
|
|
123
123
|
`}async function MN(e,t){let n=IN(e,t.screens),r=VN();for(let t of n)for(let n of ON(t)){let t=DN(FN(n),{sungenVersion:e.environment.sungenVersion});n.apiDetail&&n.apiDetail.length>0&&EN(t,n.apiDetail);let i=await KN(await t.xlsx.writeBuffer()),a=new Blob([i.buffer],{type:`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`}),o=URL.createObjectURL(a);GN(`${n.basename}-testcases_${r}.xlsx`,o),setTimeout(()=>URL.revokeObjectURL(o),1e3)}}function NN(e){let t={total:e.length,passed:0,failed:0,pending:0,na:0,notCompiled:0,passRate:0};for(let n of e)n.status===`Passed`?t.passed++:n.status===`Failed`?t.failed++:n.status===`Pending`?t.pending++:n.status===`N/A`&&t.na++,n.type===`Not compiled`&&t.notCompiled++;let n=t.passed+t.failed;return t.passRate=n>0?t.passed/n:0,t}function PN(e){return{tcId:e.tcId,category1:e.category1,category2:e.category2,precondition:e.precondition,testData:e.testData,steps:RN(e.steps),expectedResults:RN(e.expectedResults),priority:e.priority,testcaseType:e.type,testResult:e.status,executedDate:e.executedDate??``,testExecutor:e.testExecutor??``,testEnvironment:e.testEnvironment??``,note:zN(e)}}function FN(e){let t=e.specLink??``,n=(n,r)=>{let i=NN(r);return{sheetName:n,summary:{screen:e.basename,total:i.total,passed:i.passed,failed:i.failed,pending:i.pending,na:i.na},rows:r.map(PN),specLink:t}},r=[];if(e.locales&&e.locales.length>=2){let t=[];for(let i of e.locales){let e=i.scenarios.filter(e=>e.type!==`Manual`);r.push(n(`${i.displayCode} Auto`,e)),i.locale===``&&(t=i.scenarios.filter(e=>e.type===`Manual`))}t.length===0&&e.locales[0]&&(t=e.locales[0].scenarios.filter(e=>e.type===`Manual`)),r.push(n(`Manual`,t))}else{let t=e.scenarios.filter(e=>e.type!==`Manual`),i=e.scenarios.filter(e=>e.type===`Manual`);r.push(n(`Auto`,t)),r.push(n(`Manual`,i))}return r}function IN(e,t){if(!t||t.length===0)return e.screens;let n=new Set(t);return e.screens.filter(e=>n.has(e.name))}function LN(e){return[e.tcId,``,``,``,e.category1,e.precondition,e.testData,RN(e.steps),RN(e.expectedResults),e.priority,e.type,e.status,e.executedDate??``,e.testExecutor??``,e.testEnvironment??``,zN(e)]}function RN(e){return!e||e.length===0?``:e.length===1?e[0]:e.map((e,t)=>`${t+1}. ${e}`).join(`
|
|
124
|
-
`)}function zN(e){if(e.type===`Not compiled`)return`Scenario not compiled — re-run \`sungen generate --screen ${e.category4}\``;if(e.status!==`Failed`)return``;let t=[];if(e.errorMessage){let n=e.errorMessage.replace(/^Error:\s*/i,``),r=n.length>200?n.substring(0,197)+`…`:n;t.push(`• Error: ${r}`)}return e.tracePath&&t.push(`• Trace: ${e.tracePath}`),t.join(`
|
|
124
|
+
`)}function zN(e){if(e.type===`Not compiled`)return`Scenario not compiled — re-run \`sungen generate --screen ${e.category4}\``;if(e.type===`Manual`&&e.manualReason&&!e.executedDate)return`Manual: ${e.manualReason}`;if(e.status!==`Failed`)return``;let t=[];if(e.errorMessage){let n=e.errorMessage.replace(/^Error:\s*/i,``),r=n.length>200?n.substring(0,197)+`…`:n;t.push(`• Error: ${r}`)}return e.tracePath&&t.push(`• Trace: ${e.tracePath}`),t.join(`
|
|
125
125
|
`)}function BN(){let e=new Date(Date.now()+kN);return`${String(e.getUTCDate()).padStart(2,`0`)}/${String(e.getUTCMonth()+1).padStart(2,`0`)}/${e.getUTCFullYear()}`}function VN(){let e=new Date(Date.now()+kN);return`${e.getUTCFullYear()}-${String(e.getUTCMonth()+1).padStart(2,`0`)}-${String(e.getUTCDate()).padStart(2,`0`)}_${String(e.getUTCHours()).padStart(2,`0`)}-${String(e.getUTCMinutes()).padStart(2,`0`)}-${String(e.getUTCSeconds()).padStart(2,`0`)}`}function HN(e){if(e==null)return``;let t=String(e);return/[",\n\r]/.test(t)?`"`+t.replace(/"/g,`""`)+`"`:t}function UN(e){return e.map(HN).join(`,`)}function WN(e,t,n){let r=new Blob([t],{type:n}),i=URL.createObjectURL(r);GN(e,i),setTimeout(()=>URL.revokeObjectURL(i),1e3)}function GN(e,t){let n=document.createElement(`a`);n.href=t,n.download=e,document.body.appendChild(n),n.click(),n.remove()}async function KN(e){let t=await aN.default.loadAsync(e),n=Object.keys(t.files).filter(e=>/^xl\/drawings\/drawing\d+\.xml$/.test(e));for(let e of n){let n=t.file(e);if(!n)continue;let r=(await n.async(`string`)).replace(/<a:picLocks([^/]*)\/>/g,(e,t)=>{let n=e=>RegExp(`\\b${e}=`).test(t);return`<a:picLocks${t}${[`noMove`,`noResize`,`noSelect`].filter(e=>!n(e)).map(e=>` ${e}="1"`).join(``)}/>`});t.file(e,r)}return t.generateAsync({type:`uint8array`,compression:`DEFLATE`})}function qN({snapshot:e}){let{t}=O(),[n,r]=(0,y.useState)(`all`),[i,a]=(0,y.useState)(()=>new Set),o=e.screens,s=n===`all`?o:o.filter(e=>i.has(e.name)),c=s.reduce((e,t)=>e+t.summary.total,0),l=e=>e.reduce((e,t)=>e+Math.max(1,t.features?.length??1),0),u=l(s),d=l(o),f=e=>{let t=new Set(i);t.has(e)?t.delete(e):t.add(e),a(t)},p=()=>a(new Set(o.map(e=>e.name))),m=()=>a(new Set),h=i.size===o.length&&o.length>0;return(0,M.jsxs)(`div`,{className:`space-y-6 max-w-3xl`,children:[(0,M.jsxs)(`div`,{className:`bg-white dark:bg-night-800 rounded-xl border border-ink-100 dark:border-night-700 p-6 shadow-sm space-y-5`,children:[(0,M.jsxs)(`div`,{children:[(0,M.jsx)(`h2`,{className:`text-lg font-semibold mb-1`,children:t(`export.title`)}),(0,M.jsx)(`p`,{className:`text-xs text-ink-500 dark:text-night-500`,children:t(`export.subtitle`)})]}),(0,M.jsxs)(`div`,{className:`space-y-3`,children:[(0,M.jsx)(YN,{children:t(`export.scope`)}),(0,M.jsxs)(`div`,{className:`flex flex-wrap gap-3`,children:[(0,M.jsx)(JN,{checked:n===`all`,onChange:()=>r(`all`),label:t(`export.allScreens`),hint:t(`export.allScreens.hint`,{screens:o.length,files:d,tcs:e.summary.total})}),(0,M.jsx)(JN,{checked:n===`selected`,onChange:()=>r(`selected`),label:t(`export.selectedScreens`),hint:t(`export.selectedScreens.hint`)})]})]}),n===`selected`&&(0,M.jsxs)(`div`,{className:`space-y-2`,children:[(0,M.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,M.jsx)(YN,{children:t(`export.screens`)}),(0,M.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,M.jsx)(`span`,{className:`text-xs text-ink-500 dark:text-night-500 tabular-nums`,children:t(`export.selectedCount`,{selected:i.size,total:o.length})}),(0,M.jsx)(`button`,{type:`button`,onClick:p,disabled:h,className:`text-xs px-2 py-1 rounded-md border border-ink-100 dark:border-night-700 hover:bg-ink-100 dark:hover:bg-night-700 disabled:opacity-40 disabled:cursor-not-allowed`,children:t(`export.selectAll`)}),(0,M.jsx)(`button`,{type:`button`,onClick:m,disabled:i.size===0,className:`text-xs px-2 py-1 rounded-md border border-ink-100 dark:border-night-700 hover:bg-ink-100 dark:hover:bg-night-700 disabled:opacity-40 disabled:cursor-not-allowed`,children:t(`export.deselectAll`)})]})]}),(0,M.jsx)(`div`,{className:`grid grid-cols-2 sm:grid-cols-3 gap-2`,children:o.map(e=>{let n=i.has(e.name),r=e.features?.length??0;return(0,M.jsxs)(`label`,{className:`flex items-center gap-2 px-3 py-2 rounded-lg border cursor-pointer ${n?`bg-brand-50 dark:bg-brand-700/20 border-brand-500`:`bg-white dark:bg-night-900 border-ink-100 dark:border-night-700`}`,children:[(0,M.jsx)(`input`,{type:`checkbox`,checked:n,onChange:()=>f(e.name),className:`accent-brand-600`}),(0,M.jsx)(`span`,{className:`text-sm font-medium`,children:e.name}),r>1&&(0,M.jsx)(`span`,{className:`text-[10px] uppercase tracking-wider px-1.5 py-0.5 rounded-md bg-brand-100 dark:bg-brand-700/30 text-brand-700 dark:text-brand-100`,children:t(`export.featuresBadge`,{n:r})}),(0,M.jsx)(`span`,{className:`text-xs text-ink-500 dark:text-night-500 ml-auto`,children:e.summary.total})]},e.name)})})]}),(0,M.jsxs)(`div`,{className:`border-t border-ink-100 dark:border-night-700 pt-5 flex flex-wrap items-center gap-3`,children:[(0,M.jsxs)(`button`,{type:`button`,onClick:()=>{AN(e,{screens:n===`all`?void 0:Array.from(i)})},disabled:s.length===0,className:`px-4 py-2 rounded-lg bg-white dark:bg-night-900 border border-ink-100 dark:border-night-700 text-sm font-medium hover:bg-ink-100 dark:hover:bg-night-700 disabled:opacity-40 disabled:cursor-not-allowed inline-flex items-center gap-2`,children:[(0,M.jsx)(XN,{}),t(`export.downloadCsv`)]}),(0,M.jsxs)(`button`,{type:`button`,onClick:()=>{MN(e,{screens:n===`all`?void 0:Array.from(i)})},disabled:s.length===0,className:`px-4 py-2 rounded-lg bg-brand-600 text-white text-sm font-medium hover:bg-brand-700 disabled:opacity-40 disabled:cursor-not-allowed inline-flex items-center gap-2`,children:[(0,M.jsx)(XN,{}),t(`export.downloadXlsx`)]}),(0,M.jsx)(`span`,{className:`text-sm text-ink-500 dark:text-night-500 ml-auto`,children:t(`export.summary`,{screens:s.length,files:u,tcs:c})})]})]}),(0,M.jsx)(ZN,{})]})}function JN({checked:e,onChange:t,label:n,hint:r}){return(0,M.jsxs)(`button`,{type:`button`,onClick:t,className:`flex-1 min-w-[180px] text-left px-4 py-3 rounded-lg border transition-colors ${e?`bg-brand-50 dark:bg-brand-700/20 border-brand-500 ring-1 ring-brand-500`:`bg-white dark:bg-night-900 border-ink-100 dark:border-night-700 hover:border-ink-300 dark:hover:border-night-600`}`,children:[(0,M.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,M.jsx)(`span`,{className:`w-3 h-3 rounded-full border-2 ${e?`border-brand-600 bg-brand-600`:`border-ink-300 dark:border-night-500`}`}),(0,M.jsx)(`span`,{className:`text-sm font-medium`,children:n})]}),(0,M.jsx)(`div`,{className:`text-xs text-ink-500 dark:text-night-500 mt-1 ml-5`,children:r})]})}function YN({children:e}){return(0,M.jsx)(`div`,{className:`text-xs font-semibold uppercase tracking-wider text-ink-500 dark:text-night-500`,children:e})}function XN(){return(0,M.jsxs)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,M.jsx)(`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`}),(0,M.jsx)(`polyline`,{points:`7 10 12 15 17 10`}),(0,M.jsx)(`line`,{x1:`12`,y1:`15`,x2:`12`,y2:`3`})]})}function ZN(){let{t:e}=O();return(0,M.jsxs)(`div`,{className:`bg-brand-50 dark:bg-brand-700/15 border border-brand-100 dark:border-brand-700/40 rounded-xl p-4 text-sm text-ink-700 dark:text-night-300`,children:[(0,M.jsx)(`div`,{className:`font-semibold mb-1`,children:e(`export.tip.title`)}),(0,M.jsx)(`code`,{className:`font-mono text-xs`,children:`sungen delivery [name…]`}),(0,M.jsxs)(`span`,{className:`text-ink-500 dark:text-night-500`,children:[e(`export.tip.body`),(0,M.jsx)(`span`,{className:`font-mono`,children:`qa/deliverables/`})]})]})}function QN(){let e=(0,y.useMemo)(sM,[]),[t,n]=(0,y.useState)(`overview`),[r,i]=(0,y.useState)(`all`),[a,o]=(0,y.useState)(null),s=(0,y.useRef)(0),{theme:c,toggle:l}=tM(),{t:u}=O();if(!e)return(0,M.jsx)(`div`,{className:`min-h-screen flex items-center justify-center p-6`,children:(0,M.jsx)(F,{title:u(`empty.title`),body:u(`empty.body`),hint:u(`empty.hint`)})});let{current:d,history:f}=e,p=f.length>0,m=d.screens.filter(e=>!rM(e)).length,h=d.screens.filter(e=>rM(e)).length,g=m>0&&h>0,_=g?r:`all`,v=(0,y.useMemo)(()=>oM(d,_),[d,_]),b=(0,y.useMemo)(()=>({...e,current:v}),[e,v]);return(0,M.jsxs)(`div`,{className:`min-h-screen flex`,children:[(0,M.jsx)(P,{active:t,onChange:n,hasHistory:p}),(0,M.jsxs)(`div`,{className:`flex-1 flex flex-col min-w-0`,children:[(0,M.jsx)(eP,{current:d,theme:c,onToggleTheme:l}),g&&(0,M.jsx)($N,{value:r,onChange:i,allCount:m+h,webCount:m,mobileCount:h}),(0,M.jsxs)(`main`,{className:`flex-1 p-6 overflow-x-hidden`,children:[t===`overview`&&(0,M.jsx)(dM,{payload:b,theme:c,onSelectScreen:e=>{s.current+=1,o({name:e,nonce:s.current}),n(`suites`)}}),t===`suites`&&(0,M.jsx)(MM,{snapshot:v,focusScreen:a}),t===`trends`&&(0,M.jsx)(WM,{payload:e,theme:c}),t===`compare`&&(0,M.jsx)(XM,{payload:e}),t===`export`&&(0,M.jsx)(qN,{snapshot:v})]})]})]})}function $N({value:e,onChange:t,allCount:n,webCount:r,mobileCount:i}){return(0,M.jsx)(`div`,{className:`bg-white dark:bg-night-800 border-b border-ink-100 dark:border-night-700 px-6 pt-3 flex gap-1`,children:[{key:`all`,label:`All`,count:n},{key:`web`,label:`🌐 Web`,count:r},{key:`mobile`,label:`📱 Mobile`,count:i}].map(n=>(0,M.jsxs)(`button`,{onClick:()=>t(n.key),className:`px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors ${e===n.key?`border-brand-500 text-brand-600 dark:text-brand-500`:`border-transparent text-ink-500 dark:text-night-500 hover:text-ink-700 dark:hover:text-night-300`}`,children:[n.label,(0,M.jsx)(`span`,{className:`ml-1.5 text-xs text-ink-400 dark:text-night-500`,children:n.count})]},n.key))})}function eP({current:e,theme:t,onToggleTheme:n}){let{t:r}=O();return(0,M.jsxs)(`header`,{className:`bg-white dark:bg-night-800 border-b border-ink-100 dark:border-night-700 px-6 py-4 flex flex-wrap items-center gap-4`,children:[(0,M.jsxs)(`div`,{children:[(0,M.jsx)(`div`,{className:`text-xs uppercase tracking-wider text-ink-500 dark:text-night-500`,children:r(`header.run`)}),(0,M.jsx)(`div`,{className:`text-sm font-mono font-medium`,children:qj(e.runId)})]}),(0,M.jsx)(nP,{}),(0,M.jsx)(tP,{label:r(`header.environment`),value:e.environment.baseURL||`—`}),(0,M.jsx)(tP,{label:r(`header.project`),value:e.environment.projectName||`—`}),e.environment.gitBranch&&(0,M.jsx)(tP,{label:r(`header.branch`),value:e.environment.gitBranch,mono:!0}),(0,M.jsxs)(`div`,{className:`ml-auto flex items-center gap-2`,children:[(0,M.jsxs)(`div`,{className:`text-xs text-ink-500 dark:text-night-500 mr-1`,children:[`sungen v`,e.environment.sungenVersion]}),(0,M.jsx)(z,{}),(0,M.jsx)(I,{theme:t,onToggle:n})]})]})}function tP({label:e,value:t,mono:n}){return(0,M.jsxs)(`div`,{className:`min-w-0`,children:[(0,M.jsx)(`div`,{className:`text-xs uppercase tracking-wider text-ink-500 dark:text-night-500`,children:e}),(0,M.jsx)(`div`,{className:`text-sm truncate max-w-[260px] ${n?`font-mono`:``}`,title:t,children:t})]})}function nP(){return(0,M.jsx)(`div`,{className:`hidden sm:block w-px h-8 bg-ink-100 dark:bg-night-700`})}function rP(){let{locale:e,setLocale:t}=k();return(0,M.jsx)(A,{value:(0,y.useMemo)(()=>({locale:e,setLocale:t,t:(t,n)=>E(e,t,n)}),[e]),children:(0,M.jsx)(QN,{})})}(0,v.createRoot)(document.getElementById(`root`)).render((0,M.jsx)(y.StrictMode,{children:(0,M.jsx)(rP,{})}));</script>
|
|
126
126
|
<style rel="stylesheet" crossorigin>*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:""}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Helvetica Neue,sans-serif;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button{-webkit-appearance:button;background-color:#0000;background-image:none}input:where([type=button]){-webkit-appearance:button;background-color:#0000;background-image:none}input:where([type=reset]){-webkit-appearance:button;background-color:#0000;background-image:none}input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}html,body,#root{height:100%}body{font-feature-settings:"cv11", "ss01"}body,.stat-card,.nav-link{transition:background-color .15s,border-color .15s,color .15s}.stat-card{--tw-border-opacity:1;border-width:1px;border-color:rgb(241 245 249/var(--tw-border-opacity,1));--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1));--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow);border-radius:.75rem;flex-direction:column;gap:.25rem;padding:1.25rem;display:flex}.stat-card:is(.dark *){--tw-border-opacity:1;border-color:rgb(31 42 68/var(--tw-border-opacity,1));--tw-bg-opacity:1;background-color:rgb(17 26 44/var(--tw-bg-opacity,1))}.stat-label{text-transform:uppercase;letter-spacing:.05em;--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity,1));font-size:.75rem;font-weight:500;line-height:1rem}.stat-label:is(.dark *){--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity,1))}.stat-value{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction);font-size:1.875rem;font-weight:600;line-height:2.25rem}.pill{border-radius:.375rem;align-items:center;padding:.125rem .5rem;font-size:.75rem;font-weight:500;line-height:1rem;display:inline-flex}.nav-link{cursor:pointer;--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity,1));border-radius:.5rem;padding:.5rem .75rem;font-size:.875rem;font-weight:500;line-height:1.25rem}.nav-link:hover{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.nav-link:is(.dark *){--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity,1))}.nav-link:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgb(31 42 68/var(--tw-bg-opacity,1))}.nav-link-active{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1));--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}.nav-link-active:hover{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.nav-link-active:is(.dark *){--tw-text-opacity:1;color:rgb(219 234 254/var(--tw-text-opacity,1));background-color:#1d4ed833}.nav-link-active:hover:is(.dark *){background-color:#1d4ed84d}.dark .scrollbar-thin::-webkit-scrollbar-thumb{background:#1f2a44}.dark .scrollbar-thin::-webkit-scrollbar-thumb:hover{background:#2a3654}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{top:0;bottom:0;left:0;right:0}.bottom-0{bottom:0}.left-0{left:0}.left-3{left:.75rem}.right-0{right:0}.top-0{top:0}.top-1\/2{top:50%}.top-full{top:100%}.z-40{z-index:40}.z-50{z-index:50}.col-span-3{grid-column:span 3/span 3}.col-span-6{grid-column:span 6/span 6}.-mx-2{margin-left:-.5rem;margin-right:-.5rem}.mx-auto{margin-left:auto;margin-right:auto}.-mb-px{margin-bottom:-1px}.-mt-1{margin-top:-.25rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-1\.5{margin-left:.375rem}.ml-5{margin-left:1.25rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-1\.5{height:.375rem}.h-12{height:3rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-5{height:1.25rem}.h-56{height:14rem}.h-6{height:1.5rem}.h-72{height:18rem}.h-8{height:2rem}.h-9{height:2.25rem}.min-h-\[400px\]{min-height:400px}.min-h-screen{min-height:100vh}.w-1{width:.25rem}.w-1\.5{width:.375rem}.w-12{width:3rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-3{width:.75rem}.w-5{width:1.25rem}.w-56{width:14rem}.w-8{width:2rem}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0}.min-w-\[160px\]{min-width:160px}.min-w-\[180px\]{min-width:180px}.min-w-\[200px\]{min-width:200px}.max-w-3xl{max-width:48rem}.max-w-\[260px\]{max-width:260px}.max-w-md{max-width:28rem}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-y-1\/2{--tw-translate-y:-50%;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate:180deg;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-90{--tw-rotate:90deg;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.scroll-mt-4{scroll-margin-top:1rem}.list-decimal{list-style-type:decimal}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-ink-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(241 245 249/var(--tw-divide-opacity,1))}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.whitespace-pre-wrap{white-space:pre-wrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-sm{border-radius:.125rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-bad-500\/40{border-color:#dc262666}.border-brand-100{--tw-border-opacity:1;border-color:rgb(219 234 254/var(--tw-border-opacity,1))}.border-brand-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.border-brand-500\/40{border-color:#3b82f666}.border-brand-600{--tw-border-opacity:1;border-color:rgb(37 99 235/var(--tw-border-opacity,1))}.border-emerald-300\/60{border-color:#6ee7b799}.border-ink-100{--tw-border-opacity:1;border-color:rgb(241 245 249/var(--tw-border-opacity,1))}.border-ink-300{--tw-border-opacity:1;border-color:rgb(203 213 225/var(--tw-border-opacity,1))}.border-ok-500\/40{border-color:#16a34a66}.border-purple-500\/40{border-color:#a855f766}.border-transparent{border-color:#0000}.border-warn-500\/40{border-color:#d9770666}.bg-amber-100{--tw-bg-opacity:1;background-color:rgb(254 243 199/var(--tw-bg-opacity,1))}.bg-bad-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity,1))}.bg-bad-100\/30{background-color:#fee2e24d}.bg-bad-500{--tw-bg-opacity:1;background-color:rgb(220 38 38/var(--tw-bg-opacity,1))}.bg-brand-100{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity,1))}.bg-brand-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-brand-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.bg-brand-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.bg-emerald-100{--tw-bg-opacity:1;background-color:rgb(209 250 229/var(--tw-bg-opacity,1))}.bg-emerald-500{--tw-bg-opacity:1;background-color:rgb(16 185 129/var(--tw-bg-opacity,1))}.bg-ink-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.bg-ink-100\/50{background-color:#f1f5f980}.bg-ink-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity,1))}.bg-ink-500{--tw-bg-opacity:1;background-color:rgb(100 116 139/var(--tw-bg-opacity,1))}.bg-ink-900\/50{background-color:#0f172a80}.bg-ok-100{--tw-bg-opacity:1;background-color:rgb(220 252 231/var(--tw-bg-opacity,1))}.bg-ok-100\/30{background-color:#dcfce74d}.bg-ok-500{--tw-bg-opacity:1;background-color:rgb(22 163 74/var(--tw-bg-opacity,1))}.bg-purple-100{--tw-bg-opacity:1;background-color:rgb(243 232 255/var(--tw-bg-opacity,1))}.bg-purple-500{--tw-bg-opacity:1;background-color:rgb(168 85 247/var(--tw-bg-opacity,1))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity,1))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity,1))}.bg-sky-100{--tw-bg-opacity:1;background-color:rgb(224 242 254/var(--tw-bg-opacity,1))}.bg-sky-500{--tw-bg-opacity:1;background-color:rgb(14 165 233/var(--tw-bg-opacity,1))}.bg-warn-100{--tw-bg-opacity:1;background-color:rgb(254 243 199/var(--tw-bg-opacity,1))}.bg-warn-500{--tw-bg-opacity:1;background-color:rgb(217 119 6/var(--tw-bg-opacity,1))}.bg-warn-500\/10{background-color:#d977061a}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-white\/60{background-color:#fff9}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pl-12{padding-left:3rem}.pl-20{padding-left:5rem}.pl-5{padding-left:1.25rem}.pl-9{padding-left:2.25rem}.pr-3{padding-right:.75rem}.pr-4{padding-right:1rem}.pr-5{padding-right:1.25rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.pt-5{padding-top:1.25rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}.font-sans{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Helvetica Neue,sans-serif}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-none{line-height:1}.leading-tight{line-height:1.25}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-amber-700{--tw-text-opacity:1;color:rgb(180 83 9/var(--tw-text-opacity,1))}.text-bad-500{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.text-brand-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-brand-700{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}.text-emerald-700{--tw-text-opacity:1;color:rgb(4 120 87/var(--tw-text-opacity,1))}.text-ink-300{--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity,1))}.text-ink-500{--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity,1))}.text-ink-700{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity,1))}.text-ink-900{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity,1))}.text-ok-500{--tw-text-opacity:1;color:rgb(22 163 74/var(--tw-text-opacity,1))}.text-purple-700{--tw-text-opacity:1;color:rgb(126 34 206/var(--tw-text-opacity,1))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity,1))}.text-sky-700{--tw-text-opacity:1;color:rgb(3 105 161/var(--tw-text-opacity,1))}.text-warn-500{--tw-text-opacity:1;color:rgb(217 119 6/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-white\/80{color:#fffc}.line-through{text-decoration-line:line-through}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.accent-brand-600{accent-color:#2563eb}.opacity-35{opacity:.35}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.opacity-70{opacity:.7}.shadow-2xl{--tw-shadow:0 25px 50px -12px #00000040;--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000), var(--tw-ring-shadow,0 0 #0000), var(--tw-shadow)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow,0 0 #0000)}.ring-brand-500{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity,1))}.invert{--tw-invert:invert(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.\!filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)!important}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-transform{transition-property:transform;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-700{transition-duration:.7s}.placeholder\:text-ink-500::placeholder{--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity,1))}.hover\:border-ink-300:hover{--tw-border-opacity:1;border-color:rgb(203 213 225/var(--tw-border-opacity,1))}.hover\:bg-brand-700:hover{--tw-bg-opacity:1;background-color:rgb(29 78 216/var(--tw-bg-opacity,1))}.hover\:bg-ink-100:hover{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.hover\:bg-ink-100\/40:hover{background-color:#f1f5f966}.hover\:bg-ink-100\/50:hover{background-color:#f1f5f980}.hover\:bg-ink-100\/60:hover{background-color:#f1f5f999}.hover\:bg-ink-300\/60:hover{background-color:#cbd5e199}.hover\:text-ink-700:hover{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity,1))}.focus\:border-transparent:focus{border-color:#0000}.focus\:outline-none:focus{outline-offset:2px;outline:2px solid #0000}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow,0 0 #0000)}.focus\:ring-brand-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity,1))}.focus-visible\:outline:focus-visible{outline-style:solid}.focus-visible\:outline-2:focus-visible{outline-width:2px}.focus-visible\:outline-brand-500:focus-visible{outline-color:#3b82f6}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-40:disabled{opacity:.4}.dark\:divide-night-700:is(.dark *)>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(31 42 68/var(--tw-divide-opacity,1))}.dark\:border-amber-500\/40:is(.dark *){border-color:#f59e0b66}.dark\:border-brand-500\/40:is(.dark *){border-color:#3b82f666}.dark\:border-brand-700\/40:is(.dark *){border-color:#1d4ed866}.dark\:border-emerald-500\/40:is(.dark *){border-color:#10b98166}.dark\:border-emerald-700:is(.dark *){--tw-border-opacity:1;border-color:rgb(4 120 87/var(--tw-border-opacity,1))}.dark\:border-night-500:is(.dark *){--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity,1))}.dark\:border-night-600:is(.dark *){--tw-border-opacity:1;border-color:rgb(42 54 84/var(--tw-border-opacity,1))}.dark\:border-night-700:is(.dark *){--tw-border-opacity:1;border-color:rgb(31 42 68/var(--tw-border-opacity,1))}.dark\:border-purple-500\/40:is(.dark *){border-color:#a855f766}.dark\:border-red-500\/40:is(.dark *){border-color:#ef444466}.dark\:bg-amber-500\/15:is(.dark *){background-color:#f59e0b26}.dark\:bg-black\/70:is(.dark *){background-color:#000000b3}.dark\:bg-brand-500:is(.dark *){--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.dark\:bg-brand-700\/15:is(.dark *){background-color:#1d4ed826}.dark\:bg-brand-700\/20:is(.dark *){background-color:#1d4ed833}.dark\:bg-brand-700\/25:is(.dark *){background-color:#1d4ed840}.dark\:bg-brand-700\/30:is(.dark *){background-color:#1d4ed84d}.dark\:bg-emerald-400:is(.dark *){--tw-bg-opacity:1;background-color:rgb(52 211 153/var(--tw-bg-opacity,1))}.dark\:bg-emerald-500\/15:is(.dark *){background-color:#10b98126}.dark\:bg-emerald-500\/5:is(.dark *){background-color:#10b9810d}.dark\:bg-emerald-900\/40:is(.dark *){background-color:#064e3b66}.dark\:bg-night-500:is(.dark *){--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity,1))}.dark\:bg-night-700:is(.dark *){--tw-bg-opacity:1;background-color:rgb(31 42 68/var(--tw-bg-opacity,1))}.dark\:bg-night-700\/50:is(.dark *){background-color:#1f2a4480}.dark\:bg-night-800:is(.dark *){--tw-bg-opacity:1;background-color:rgb(17 26 44/var(--tw-bg-opacity,1))}.dark\:bg-night-900:is(.dark *){--tw-bg-opacity:1;background-color:rgb(11 18 32/var(--tw-bg-opacity,1))}.dark\:bg-night-900\/20:is(.dark *){background-color:#0b122033}.dark\:bg-night-900\/30:is(.dark *){background-color:#0b12204d}.dark\:bg-night-900\/40:is(.dark *){background-color:#0b122066}.dark\:bg-purple-500\/15:is(.dark *){background-color:#a855f726}.dark\:bg-red-400:is(.dark *){--tw-bg-opacity:1;background-color:rgb(248 113 113/var(--tw-bg-opacity,1))}.dark\:bg-red-500\/15:is(.dark *){background-color:#ef444426}.dark\:bg-red-500\/5:is(.dark *){background-color:#ef44440d}.dark\:bg-sky-500\/15:is(.dark *){background-color:#0ea5e926}.dark\:bg-sky-900\/40:is(.dark *){background-color:#0c4a6e66}.dark\:text-amber-300:is(.dark *){--tw-text-opacity:1;color:rgb(252 211 77/var(--tw-text-opacity,1))}.dark\:text-brand-100:is(.dark *){--tw-text-opacity:1;color:rgb(219 234 254/var(--tw-text-opacity,1))}.dark\:text-brand-500:is(.dark *){--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.dark\:text-emerald-300:is(.dark *){--tw-text-opacity:1;color:rgb(110 231 183/var(--tw-text-opacity,1))}.dark\:text-night-100:is(.dark *){--tw-text-opacity:1;color:rgb(226 232 240/var(--tw-text-opacity,1))}.dark\:text-night-300:is(.dark *){--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity,1))}.dark\:text-night-500:is(.dark *){--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity,1))}.dark\:text-purple-300:is(.dark *){--tw-text-opacity:1;color:rgb(216 180 254/var(--tw-text-opacity,1))}.dark\:text-red-300:is(.dark *){--tw-text-opacity:1;color:rgb(252 165 165/var(--tw-text-opacity,1))}.dark\:text-sky-300:is(.dark *){--tw-text-opacity:1;color:rgb(125 211 252/var(--tw-text-opacity,1))}.dark\:placeholder\:text-night-500:is(.dark *)::-moz-placeholder{--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity,1))}.dark\:placeholder\:text-night-500:is(.dark *)::placeholder{--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity,1))}.dark\:hover\:border-night-600:hover:is(.dark *){--tw-border-opacity:1;border-color:rgb(42 54 84/var(--tw-border-opacity,1))}.dark\:hover\:bg-night-600:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgb(42 54 84/var(--tw-bg-opacity,1))}.dark\:hover\:bg-night-700:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgb(31 42 68/var(--tw-bg-opacity,1))}.dark\:hover\:bg-night-700\/30:hover:is(.dark *){background-color:#1f2a444d}.dark\:hover\:bg-night-700\/40:hover:is(.dark *){background-color:#1f2a4466}.dark\:hover\:text-night-300:hover:is(.dark *){--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity,1))}@media (min-width:640px){.sm\:col-span-2{grid-column:span 2/span 2}.sm\:col-span-7{grid-column:span 7/span 7}.sm\:block{display:block}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media (min-width:768px){.md\:inline-flex{display:inline-flex}}@media (min-width:1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}}@media (min-width:1280px){.xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}
|
|
127
127
|
/*$vite$:1*/</style>
|
package/src/dashboard/types.ts
CHANGED
|
@@ -144,6 +144,7 @@ export interface ScenarioSnapshot {
|
|
|
144
144
|
duration?: number; // ms
|
|
145
145
|
errorMessage?: string;
|
|
146
146
|
tracePath?: string;
|
|
147
|
+
manualReason?: string; // `# MANUAL: …` reason → Note column of a Pending manual row
|
|
147
148
|
executedDate?: string; // dd/mm/yyyy
|
|
148
149
|
testEnvironment?: string;
|
|
149
150
|
testExecutor?: string;
|