mcprigor 1.0.0-rc.3 → 1.0.0
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/LICENSE +186 -1
- package/README.md +24 -10
- package/dist/cli.js +0 -0
- package/dist/data.js +14 -21
- package/dist/data.js.map +1 -1
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +2 -1
- package/dist/session.js.map +1 -1
- package/dist/trace.d.ts.map +1 -1
- package/dist/trace.js +2 -1
- package/dist/trace.js.map +1 -1
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +129 -33
- package/dist/workspace.js.map +1 -1
- package/dist/xlsx.d.ts +6 -0
- package/dist/xlsx.d.ts.map +1 -0
- package/dist/xlsx.js +199 -0
- package/dist/xlsx.js.map +1 -0
- package/docs/ENGINEER-SETUP.md +1 -1
- package/docs/GETTING-STARTED.md +1 -1
- package/docs/README.md +1 -1
- package/package.json +2 -2
- package/workspace-assets/app.js +550 -1
- package/workspace-assets/index.html +143 -1
- package/workspace-assets/style.css +225 -1
|
@@ -1 +1,143 @@
|
|
|
1
|
-
<!doctype html
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>MCP Rigor — QA Workspace</title>
|
|
7
|
+
<link rel="stylesheet" href="/style.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<header>
|
|
11
|
+
<div class="brand">
|
|
12
|
+
<svg class="logo" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 12l5 5L20 6" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
13
|
+
<strong>MCP Rigor</strong>
|
|
14
|
+
<span class="divider"></span>
|
|
15
|
+
<span class="sub">QA Workspace</span>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="header-right">
|
|
18
|
+
<span id="version" class="pill"></span>
|
|
19
|
+
<span id="connection" class="conn"><span class="dot"></span>Connecting…</span>
|
|
20
|
+
</div>
|
|
21
|
+
</header>
|
|
22
|
+
|
|
23
|
+
<main>
|
|
24
|
+
<aside class="sidebar">
|
|
25
|
+
<button id="new" class="primary block">+ New test file</button>
|
|
26
|
+
<div class="search-row">
|
|
27
|
+
<input id="filter" type="search" placeholder="Filter files…" aria-label="Filter test files">
|
|
28
|
+
<button id="refresh" class="icon" title="Refresh list" aria-label="Refresh list">↻</button>
|
|
29
|
+
</div>
|
|
30
|
+
<nav id="suites" aria-label="Test suites"></nav>
|
|
31
|
+
<div id="batch-bar" class="batch-bar" hidden>
|
|
32
|
+
<span id="batch-count"></span>
|
|
33
|
+
<div class="batch-actions">
|
|
34
|
+
<button id="batch-validate" title="Validate selected files">Validate</button>
|
|
35
|
+
<button id="batch-parity" title="Run parity on selected files">Parity</button>
|
|
36
|
+
<button id="batch-run" class="primary" title="Run tests in selected files">▶ Run</button>
|
|
37
|
+
</div>
|
|
38
|
+
<button id="batch-clear" class="ghost small">Clear selection</button>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="sidebar-foot">
|
|
41
|
+
<a href="https://mcprigor.com/docs/plain-language-cookbook.html" target="_blank" rel="noreferrer">📖 Cookbook — copy-ready examples</a>
|
|
42
|
+
</div>
|
|
43
|
+
</aside>
|
|
44
|
+
|
|
45
|
+
<section class="workbench">
|
|
46
|
+
<div class="toolbar">
|
|
47
|
+
<span id="filename" class="filename" title="Double-click to rename">No file open</span><button id="rename" class="icon" title="Rename file" hidden>✏️</button>
|
|
48
|
+
<span id="dirty" class="dirty"></span>
|
|
49
|
+
<span class="spacer"></span>
|
|
50
|
+
<button id="save" title="Save (⌘S / Ctrl+S)">Save</button>
|
|
51
|
+
<button id="validate" title="Check wording without running">Validate</button>
|
|
52
|
+
<button id="parity" title="Compare targets declared in this suite">Parity</button>
|
|
53
|
+
<button id="run" class="primary" title="Run tests (⌘⏎ / Ctrl+Enter)">▶ Run tests</button>
|
|
54
|
+
</div>
|
|
55
|
+
<div id="editor-wrap" class="editor-wrap">
|
|
56
|
+
<div id="gutter" class="gutter" aria-hidden="true"></div>
|
|
57
|
+
<div class="editor-stack">
|
|
58
|
+
<pre id="highlight" class="highlight" aria-hidden="true"><code id="highlight-code"></code></pre>
|
|
59
|
+
<textarea id="editor" spellcheck="false" autocomplete="off" autocapitalize="off" aria-label="Natural-language MCP test editor"></textarea>
|
|
60
|
+
<div id="suggest" class="suggest" hidden></div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
<div id="welcome" class="welcome" hidden>
|
|
64
|
+
<div class="welcome-card">
|
|
65
|
+
<h1>Test your MCP server in plain English</h1>
|
|
66
|
+
<p>No test code. No AI interpreting your words. The same sentence always runs the same test.</p>
|
|
67
|
+
<ol>
|
|
68
|
+
<li><strong>Create a test file</strong> — it opens pre-filled with a working example.</li>
|
|
69
|
+
<li><strong>Point it at your server</strong> — set the <code>Server:</code> line to your MCP server command, or use <code>MCP URL:</code> for a deployed endpoint.</li>
|
|
70
|
+
<li><strong>Validate, then run</strong> — green means your server keeps its promises.</li>
|
|
71
|
+
</ol>
|
|
72
|
+
<button id="welcome-new" class="primary large">+ Create your first test file</button>
|
|
73
|
+
<p class="hint">Already have <code>.mcpr</code> or YAML suites in this folder? They appear in the list on the left.</p>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
<div id="diagnostics" class="diagnostics" role="status" aria-live="polite" hidden></div>
|
|
77
|
+
</section>
|
|
78
|
+
|
|
79
|
+
<aside class="results">
|
|
80
|
+
<div class="results-tabs" role="tablist">
|
|
81
|
+
<button id="tab-run" class="tab active" role="tab" aria-selected="true">Run</button>
|
|
82
|
+
<button id="tab-history" class="tab" role="tab" aria-selected="false">History</button>
|
|
83
|
+
<button id="tab-trends" class="tab" role="tab" aria-selected="false">Trends</button>
|
|
84
|
+
<span class="spacer"></span>
|
|
85
|
+
<span id="run-badge" class="badge" hidden></span>
|
|
86
|
+
</div>
|
|
87
|
+
<div class="results-search">
|
|
88
|
+
<input id="results-filter" type="search" placeholder="Search tests and results…" aria-label="Search tests and results">
|
|
89
|
+
</div>
|
|
90
|
+
<div id="panel-run" class="panel" role="tabpanel">
|
|
91
|
+
<div id="run-list"></div>
|
|
92
|
+
<pre id="output" class="output"><span class="muted">Nothing has run yet.
|
|
93
|
+
Open a test file and click ▶ Run tests — or select several files
|
|
94
|
+
with their checkboxes and run them together.</span></pre>
|
|
95
|
+
</div>
|
|
96
|
+
<div id="panel-history" class="panel" role="tabpanel" hidden>
|
|
97
|
+
<div id="history-list" class="history-list"><p class="muted pad">No runs recorded yet. History appears after the first ▶ Run.</p></div>
|
|
98
|
+
</div>
|
|
99
|
+
<div id="panel-trends" class="panel" role="tabpanel" hidden>
|
|
100
|
+
<div id="trends" class="trends"><p class="muted pad">Trends appear after a few runs.</p></div>
|
|
101
|
+
</div>
|
|
102
|
+
</aside>
|
|
103
|
+
</main>
|
|
104
|
+
|
|
105
|
+
<footer>
|
|
106
|
+
<span id="workspace"></span>
|
|
107
|
+
<span class="foot-right">Natural language and YAML share one runtime model</span>
|
|
108
|
+
</footer>
|
|
109
|
+
|
|
110
|
+
<dialog id="new-dialog">
|
|
111
|
+
<form method="dialog" id="new-form">
|
|
112
|
+
<h3>New test file</h3>
|
|
113
|
+
<p>Created from a working example you can edit right away.</p>
|
|
114
|
+
<label for="new-name">File name</label>
|
|
115
|
+
<input id="new-name" type="text" placeholder="e.g. checkout tests" autocomplete="off" required pattern="[A-Za-z0-9][A-Za-z0-9 ._-]{0,80}">
|
|
116
|
+
<p class="dialog-hint"><code>.mcpr</code> is added automatically.</p>
|
|
117
|
+
<p id="new-error" class="dialog-error" hidden></p>
|
|
118
|
+
<div class="dialog-actions">
|
|
119
|
+
<button type="button" id="new-cancel" class="ghost">Cancel</button>
|
|
120
|
+
<button type="submit" class="primary" id="new-create">Create file</button>
|
|
121
|
+
</div>
|
|
122
|
+
</form>
|
|
123
|
+
</dialog>
|
|
124
|
+
|
|
125
|
+
<dialog id="rename-dialog">
|
|
126
|
+
<form method="dialog" id="rename-form">
|
|
127
|
+
<h3>Rename file</h3>
|
|
128
|
+
<p>History and trends follow the new name automatically.</p>
|
|
129
|
+
<label for="rename-name">New file name</label>
|
|
130
|
+
<input id="rename-name" type="text" autocomplete="off" required pattern="[A-Za-z0-9][A-Za-z0-9 ._-]{0,80}">
|
|
131
|
+
<p class="dialog-hint">The extension stays the same.</p>
|
|
132
|
+
<p id="rename-error" class="dialog-error" hidden></p>
|
|
133
|
+
<div class="dialog-actions">
|
|
134
|
+
<button type="button" id="rename-cancel" class="ghost">Cancel</button>
|
|
135
|
+
<button type="submit" class="primary">Rename</button>
|
|
136
|
+
</div>
|
|
137
|
+
</form>
|
|
138
|
+
</dialog>
|
|
139
|
+
|
|
140
|
+
<div id="toast" class="toast" role="status" hidden></div>
|
|
141
|
+
<script type="module" src="/app.js"></script>
|
|
142
|
+
</body>
|
|
143
|
+
</html>
|
|
@@ -1 +1,225 @@
|
|
|
1
|
-
:root{
|
|
1
|
+
:root{
|
|
2
|
+
--bg:#0d1512; --bg-raised:#131e19; --bg-panel:#17241e; --bg-input:#0a110e;
|
|
3
|
+
--line:#24352c; --line-soft:#1c2a23;
|
|
4
|
+
--text:#e8f4ec; --text-dim:#9db8a8; --text-faint:#647d6f;
|
|
5
|
+
--accent:#34d27b; --accent-strong:#22b566; --accent-soft:rgba(52,210,123,.12);
|
|
6
|
+
--amber:#eec35c; --amber-soft:rgba(238,195,92,.1);
|
|
7
|
+
--red:#ff7a6e; --red-soft:rgba(255,122,110,.1);
|
|
8
|
+
--mono:"SF Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
|
|
9
|
+
--sans:Inter,ui-sans-serif,system-ui,-apple-system,sans-serif;
|
|
10
|
+
}
|
|
11
|
+
*{box-sizing:border-box}
|
|
12
|
+
html,body{height:100%}
|
|
13
|
+
body{margin:0;font:14px/1.55 var(--sans);color:var(--text);background:var(--bg);display:grid;grid-template-rows:54px 1fr 32px;overflow:hidden}
|
|
14
|
+
|
|
15
|
+
/* ---------- header / footer ---------- */
|
|
16
|
+
header{display:flex;align-items:center;justify-content:space-between;padding:0 18px;background:var(--bg-raised);border-bottom:1px solid var(--line)}
|
|
17
|
+
.brand{display:flex;align-items:center;gap:10px}
|
|
18
|
+
.logo{width:22px;height:22px;color:var(--accent);background:var(--accent-soft);border-radius:6px;padding:3px}
|
|
19
|
+
.brand strong{font-size:15.5px;letter-spacing:-.01em}
|
|
20
|
+
.divider{width:1px;height:18px;background:var(--line)}
|
|
21
|
+
.sub{color:var(--text-dim);font-size:13px}
|
|
22
|
+
.header-right{display:flex;align-items:center;gap:12px}
|
|
23
|
+
.pill{font:11.5px var(--mono);color:var(--text-dim);border:1px solid var(--line);border-radius:99px;padding:2px 9px}
|
|
24
|
+
.conn{display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--text-dim)}
|
|
25
|
+
.dot{width:7px;height:7px;border-radius:50%;background:var(--amber);transition:background .3s}
|
|
26
|
+
.conn.ok .dot{background:var(--accent);box-shadow:0 0 6px rgba(52,210,123,.6)}
|
|
27
|
+
footer{display:flex;align-items:center;justify-content:space-between;padding:0 18px;background:var(--bg-raised);border-top:1px solid var(--line);font-size:11.5px;color:var(--text-faint)}
|
|
28
|
+
|
|
29
|
+
/* ---------- layout ---------- */
|
|
30
|
+
main{display:grid;grid-template-columns:250px minmax(420px,1fr) minmax(320px,36%);min-height:0}
|
|
31
|
+
|
|
32
|
+
/* ---------- sidebar ---------- */
|
|
33
|
+
.sidebar{display:flex;flex-direction:column;gap:10px;padding:14px 12px;background:var(--bg-raised);border-right:1px solid var(--line);min-height:0}
|
|
34
|
+
.search-row{display:flex;gap:6px}
|
|
35
|
+
#filter{flex:1;min-width:0;background:var(--bg-input);border:1px solid var(--line);border-radius:8px;color:var(--text);padding:7px 10px;font-size:13px;outline:none}
|
|
36
|
+
#filter:focus{border-color:var(--accent-strong)}
|
|
37
|
+
#filter::placeholder{color:var(--text-faint)}
|
|
38
|
+
nav{flex:1;overflow-y:auto;min-height:0;display:flex;flex-direction:column;gap:2px;margin:0 -4px;padding:0 4px}
|
|
39
|
+
nav button{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:none;border:0;border-radius:8px;color:var(--text-dim);padding:8px 10px;font-size:13px;cursor:pointer;overflow:hidden}
|
|
40
|
+
nav button .file-icon{flex:none;font-size:11px;opacity:.7}
|
|
41
|
+
nav button .file-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
42
|
+
nav button:hover{background:var(--bg-panel);color:var(--text)}
|
|
43
|
+
nav button.active{background:var(--accent-soft);color:var(--accent)}
|
|
44
|
+
.empty{color:var(--text-faint);font-size:12.5px;margin:8px 4px;line-height:1.6}
|
|
45
|
+
.sidebar-foot{border-top:1px solid var(--line-soft);padding-top:10px}
|
|
46
|
+
.sidebar-foot a{color:var(--text-dim);font-size:12px;text-decoration:none}
|
|
47
|
+
.sidebar-foot a:hover{color:var(--accent)}
|
|
48
|
+
|
|
49
|
+
/* ---------- buttons ---------- */
|
|
50
|
+
button{font:13px var(--sans);cursor:pointer;border-radius:8px;border:1px solid var(--line);background:var(--bg-panel);color:var(--text);padding:7px 13px;transition:background .12s,border-color .12s,opacity .12s}
|
|
51
|
+
button:hover{background:#1d2e26;border-color:#31463a}
|
|
52
|
+
button:focus-visible{outline:2px solid var(--accent-strong);outline-offset:1px}
|
|
53
|
+
button.primary{background:var(--accent-strong);border-color:var(--accent-strong);color:#04160c;font-weight:600}
|
|
54
|
+
button.primary:hover{background:var(--accent)}
|
|
55
|
+
button.ghost{background:none;border-color:var(--line)}
|
|
56
|
+
button.icon{padding:7px 10px;color:var(--text-dim)}
|
|
57
|
+
button.block{width:100%}
|
|
58
|
+
button.large{padding:11px 22px;font-size:14.5px;border-radius:10px}
|
|
59
|
+
button:disabled{opacity:.38;cursor:not-allowed}
|
|
60
|
+
button:disabled:hover{background:var(--bg-panel);border-color:var(--line)}
|
|
61
|
+
button.primary:disabled:hover{background:var(--accent-strong);border-color:var(--accent-strong)}
|
|
62
|
+
|
|
63
|
+
/* ---------- workbench ---------- */
|
|
64
|
+
.workbench{display:grid;grid-template-rows:48px 1fr auto;min-width:0;min-height:0;background:var(--bg);position:relative}
|
|
65
|
+
.toolbar{display:flex;align-items:center;gap:8px;padding:0 14px;background:var(--bg-raised);border-bottom:1px solid var(--line)}
|
|
66
|
+
.filename{font:12.5px var(--mono);color:var(--text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:34%}
|
|
67
|
+
.filename.open{color:var(--text)}
|
|
68
|
+
.dirty{font-size:11.5px;color:var(--amber)}
|
|
69
|
+
.spacer{flex:1}
|
|
70
|
+
|
|
71
|
+
/* ---------- editor with highlight + gutter ---------- */
|
|
72
|
+
.editor-wrap{display:flex;min-height:0;overflow:hidden}
|
|
73
|
+
.gutter{flex:none;width:46px;overflow:hidden;background:var(--bg-raised);border-right:1px solid var(--line-soft);color:var(--text-faint);font:13px/1.65 var(--mono);text-align:right;padding:16px 10px 16px 0;user-select:none;white-space:pre}
|
|
74
|
+
.editor-stack{position:relative;flex:1;min-width:0;overflow:hidden}
|
|
75
|
+
.highlight,.editor-stack textarea{margin:0;border:0;padding:16px 18px;font:13.5px/1.65 var(--mono);tab-size:2;white-space:pre-wrap;word-break:break-word;overflow-y:auto}
|
|
76
|
+
.highlight{position:absolute;inset:0;pointer-events:none;color:var(--text)}
|
|
77
|
+
.editor-stack textarea{position:absolute;inset:0;width:100%;height:100%;resize:none;outline:none;background:transparent;color:transparent;caret-color:var(--accent)}
|
|
78
|
+
.editor-stack textarea::selection{background:rgba(52,210,123,.22)}
|
|
79
|
+
.editor-stack textarea::placeholder{color:var(--text-faint)}
|
|
80
|
+
/* syntax colors */
|
|
81
|
+
.tok-key{color:#7ee2a8}
|
|
82
|
+
.tok-str{color:#f0d488}
|
|
83
|
+
.tok-num{color:#8ecbff}
|
|
84
|
+
.tok-cmt{color:#5b7365;font-style:italic}
|
|
85
|
+
.tok-field{color:#c7b3ff}
|
|
86
|
+
|
|
87
|
+
/* ---------- welcome ---------- */
|
|
88
|
+
.welcome{position:absolute;inset:48px 0 0;display:flex;align-items:center;justify-content:center;background:var(--bg);z-index:5;overflow:auto;padding:24px}
|
|
89
|
+
.welcome-card{max-width:520px;background:var(--bg-panel);border:1px solid var(--line);border-radius:16px;padding:34px 38px}
|
|
90
|
+
.welcome-card h1{font-size:21px;letter-spacing:-.02em;margin:0 0 8px}
|
|
91
|
+
.welcome-card>p{color:var(--text-dim);margin:0 0 18px;font-size:14px}
|
|
92
|
+
.welcome-card ol{margin:0 0 22px;padding-left:22px;display:grid;gap:12px;color:var(--text-dim);font-size:13.5px}
|
|
93
|
+
.welcome-card ol strong{color:var(--text)}
|
|
94
|
+
.welcome-card code{font:12px var(--mono);background:var(--bg-input);border:1px solid var(--line-soft);border-radius:5px;padding:1.5px 6px;color:#7ee2a8}
|
|
95
|
+
.hint{margin:14px 0 0;font-size:12.5px;color:var(--text-faint)}
|
|
96
|
+
|
|
97
|
+
/* ---------- diagnostics ---------- */
|
|
98
|
+
.diagnostics{padding:10px 16px;font-size:13px;white-space:pre-wrap;border-top:1px solid var(--line);background:var(--bg-raised);color:var(--text-dim);max-height:130px;overflow:auto}
|
|
99
|
+
.diagnostics.ok{color:var(--accent);background:var(--accent-soft)}
|
|
100
|
+
.diagnostics.warn{color:var(--amber);background:var(--amber-soft)}
|
|
101
|
+
.diagnostics.err{color:var(--red);background:var(--red-soft)}
|
|
102
|
+
|
|
103
|
+
/* ---------- results ---------- */
|
|
104
|
+
.results{display:flex;flex-direction:column;min-height:0;background:var(--bg-input);border-left:1px solid var(--line)}
|
|
105
|
+
.results-head{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--line-soft)}
|
|
106
|
+
.results-head h2{margin:0;font-size:11.5px;text-transform:uppercase;letter-spacing:.1em;color:var(--text-faint)}
|
|
107
|
+
.badge{font-size:11.5px;font-weight:600;border-radius:99px;padding:3px 10px}
|
|
108
|
+
.badge.running{background:var(--amber-soft);color:var(--amber)}
|
|
109
|
+
.badge.passed{background:var(--accent-soft);color:var(--accent)}
|
|
110
|
+
.badge.failed{background:var(--red-soft);color:var(--red)}
|
|
111
|
+
.output{flex:1;margin:0;overflow:auto;padding:14px 16px;font:12.5px/1.6 var(--mono);white-space:pre-wrap;word-break:break-word;color:var(--text-dim)}
|
|
112
|
+
.output .muted{color:var(--text-faint)}
|
|
113
|
+
.output .out-pass{color:var(--accent)}
|
|
114
|
+
.output .out-fail{color:var(--red)}
|
|
115
|
+
.output .out-head{color:var(--text);font-weight:600}
|
|
116
|
+
|
|
117
|
+
/* ---------- dialog ---------- */
|
|
118
|
+
dialog{border:1px solid var(--line);border-radius:14px;background:var(--bg-panel);color:var(--text);padding:26px 28px;width:min(420px,90vw)}
|
|
119
|
+
dialog::backdrop{background:rgba(4,10,7,.7);backdrop-filter:blur(2px)}
|
|
120
|
+
dialog h3{margin:0 0 6px;font-size:16.5px}
|
|
121
|
+
dialog p{margin:0 0 16px;color:var(--text-dim);font-size:13px}
|
|
122
|
+
dialog label{display:block;font-size:12.5px;color:var(--text-dim);margin-bottom:6px}
|
|
123
|
+
dialog input{width:100%;background:var(--bg-input);border:1px solid var(--line);border-radius:8px;color:var(--text);padding:9px 12px;font-size:14px;outline:none}
|
|
124
|
+
dialog input:focus{border-color:var(--accent-strong)}
|
|
125
|
+
.dialog-hint{margin:8px 0 0!important;font-size:12px!important;color:var(--text-faint)!important}
|
|
126
|
+
.dialog-hint code,.hint code{font:11px var(--mono);background:var(--bg-input);border:1px solid var(--line-soft);border-radius:4px;padding:1px 5px;color:#7ee2a8}
|
|
127
|
+
.dialog-error{margin:10px 0 0!important;font-size:12.5px!important;color:var(--red)!important}
|
|
128
|
+
.dialog-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:20px}
|
|
129
|
+
|
|
130
|
+
/* ---------- toast ---------- */
|
|
131
|
+
.toast{position:fixed;bottom:46px;left:50%;transform:translateX(-50%);background:var(--bg-panel);border:1px solid var(--line);border-radius:10px;color:var(--text);font-size:13px;padding:10px 18px;box-shadow:0 8px 30px rgba(0,0,0,.5);z-index:50;animation:toast-in .18s ease-out}
|
|
132
|
+
@keyframes toast-in{from{opacity:0;transform:translate(-50%,8px)}to{opacity:1;transform:translate(-50%,0)}}
|
|
133
|
+
|
|
134
|
+
/* ---------- responsive ---------- */
|
|
135
|
+
@media(max-width:1020px){main{grid-template-columns:210px 1fr}.results{display:none}}
|
|
136
|
+
@media(max-width:640px){main{grid-template-columns:1fr}.sidebar{display:none}}
|
|
137
|
+
[hidden]{display:none!important}
|
|
138
|
+
|
|
139
|
+
/* ---------- multi-select ---------- */
|
|
140
|
+
.suite-row{display:flex;align-items:center;gap:2px}
|
|
141
|
+
.suite-row input[type=checkbox]{flex:none;width:14px;height:14px;margin:0 2px 0 6px;accent-color:var(--accent-strong);cursor:pointer}
|
|
142
|
+
.suite-row button{flex:1;min-width:0}
|
|
143
|
+
.batch-bar{border-top:1px solid var(--line-soft);padding-top:10px;display:flex;flex-direction:column;gap:8px}
|
|
144
|
+
#batch-count{font-size:12px;color:var(--text-dim)}
|
|
145
|
+
.batch-actions{display:flex;gap:6px}
|
|
146
|
+
.batch-actions button{flex:1;padding:6px 4px;font-size:12.5px}
|
|
147
|
+
button.small{padding:4px 8px;font-size:11.5px;color:var(--text-faint)}
|
|
148
|
+
|
|
149
|
+
/* ---------- results tabs ---------- */
|
|
150
|
+
.results-tabs{display:flex;align-items:center;gap:2px;padding:8px 10px 0;border-bottom:1px solid var(--line-soft)}
|
|
151
|
+
.tab{background:none;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--text-faint);font-size:12.5px;padding:6px 10px 8px}
|
|
152
|
+
.tab:hover{background:none;color:var(--text-dim)}
|
|
153
|
+
.tab.active{color:var(--accent);border-bottom-color:var(--accent)}
|
|
154
|
+
.results-tabs .badge{margin:0 6px 6px 0}
|
|
155
|
+
.results-search{padding:8px 10px;border-bottom:1px solid var(--line-soft)}
|
|
156
|
+
#results-filter{width:100%;background:var(--bg-raised);border:1px solid var(--line);border-radius:8px;color:var(--text);padding:6px 10px;font-size:12.5px;outline:none}
|
|
157
|
+
#results-filter:focus{border-color:var(--accent-strong)}
|
|
158
|
+
#results-filter::placeholder{color:var(--text-faint)}
|
|
159
|
+
.panel{flex:1;min-height:0;overflow:auto;display:flex;flex-direction:column}
|
|
160
|
+
.pad{padding:14px 16px}
|
|
161
|
+
.muted{color:var(--text-faint)}
|
|
162
|
+
|
|
163
|
+
/* ---------- run list (batch) ---------- */
|
|
164
|
+
#run-list:empty{display:none}
|
|
165
|
+
#run-list{border-bottom:1px solid var(--line-soft)}
|
|
166
|
+
.run-item{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:none;border:0;border-radius:0;padding:8px 14px;font:12.5px var(--mono);color:var(--text-dim);cursor:pointer}
|
|
167
|
+
.run-item:hover{background:var(--bg-panel)}
|
|
168
|
+
.run-item.selected{background:var(--accent-soft)}
|
|
169
|
+
.run-item .st{flex:none;width:14px}
|
|
170
|
+
.run-item .st.pass{color:var(--accent)}
|
|
171
|
+
.run-item .st.fail{color:var(--red)}
|
|
172
|
+
.run-item .st.running{color:var(--amber)}
|
|
173
|
+
.run-item .nm{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
174
|
+
.run-item .ms{flex:none;color:var(--text-faint);font-size:11px}
|
|
175
|
+
|
|
176
|
+
/* ---------- history ---------- */
|
|
177
|
+
.history-list{display:flex;flex-direction:column}
|
|
178
|
+
.h-entry{border-bottom:1px solid var(--line-soft);padding:10px 14px}
|
|
179
|
+
.h-head{display:flex;align-items:center;gap:8px;font-size:12.5px;cursor:pointer}
|
|
180
|
+
.h-head .st{width:14px}
|
|
181
|
+
.h-head .st.pass{color:var(--accent)}
|
|
182
|
+
.h-head .st.fail{color:var(--red)}
|
|
183
|
+
.h-head .suite{font-family:var(--mono);color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}
|
|
184
|
+
.h-head .when{color:var(--text-faint);font-size:11px;flex:none}
|
|
185
|
+
.h-tests{margin:6px 0 0 22px;display:none;flex-direction:column;gap:3px}
|
|
186
|
+
.h-entry.open .h-tests{display:flex}
|
|
187
|
+
.h-test{display:flex;gap:8px;font:11.5px var(--mono);color:var(--text-dim)}
|
|
188
|
+
.h-test .st{width:12px}
|
|
189
|
+
.h-test .st.pass{color:var(--accent)}
|
|
190
|
+
.h-test .st.fail{color:var(--red)}
|
|
191
|
+
.h-test .err{color:var(--red);opacity:.85}
|
|
192
|
+
|
|
193
|
+
/* ---------- trends ---------- */
|
|
194
|
+
.trends{padding:12px 14px;display:flex;flex-direction:column;gap:14px}
|
|
195
|
+
.t-suite{background:var(--bg-panel);border:1px solid var(--line-soft);border-radius:10px;padding:12px 14px}
|
|
196
|
+
.t-name{font:12.5px var(--mono);color:var(--text);margin-bottom:8px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
197
|
+
.t-row{display:flex;align-items:center;gap:10px}
|
|
198
|
+
.spark{display:flex;align-items:flex-end;gap:2px;height:30px}
|
|
199
|
+
.spark i{width:7px;border-radius:2px 2px 0 0;min-height:4px}
|
|
200
|
+
.spark i.pass{background:var(--accent-strong)}
|
|
201
|
+
.spark i.fail{background:var(--red)}
|
|
202
|
+
.t-stats{font-size:11.5px;color:var(--text-dim);display:flex;flex-direction:column;gap:2px}
|
|
203
|
+
.t-rate{font-weight:600;color:var(--text)}
|
|
204
|
+
.t-test-list{margin-top:10px;border-top:1px solid var(--line-soft);padding-top:8px;display:flex;flex-direction:column;gap:4px}
|
|
205
|
+
.t-test{display:flex;align-items:center;gap:8px;font:11.5px var(--mono);color:var(--text-dim)}
|
|
206
|
+
.t-test .bar{flex:1;height:5px;background:var(--red-soft);border-radius:3px;overflow:hidden}
|
|
207
|
+
.t-test .bar i{display:block;height:100%;background:var(--accent-strong)}
|
|
208
|
+
.t-test .pct{flex:none;width:38px;text-align:right}
|
|
209
|
+
.mark{background:rgba(238,195,92,.28);border-radius:2px;color:inherit}
|
|
210
|
+
|
|
211
|
+
/* ---------- autocomplete ---------- */
|
|
212
|
+
.suggest{position:absolute;z-index:20;min-width:280px;max-width:430px;max-height:236px;overflow:auto;background:var(--bg-panel);border:1px solid var(--line);border-radius:10px;box-shadow:0 10px 34px rgba(0,0,0,.55);padding:4px}
|
|
213
|
+
.suggest button{display:block;width:100%;text-align:left;background:none;border:0;border-radius:6px;padding:6px 10px;font:12.5px var(--mono);color:var(--text-dim);cursor:pointer}
|
|
214
|
+
.suggest button .desc{display:block;font:11px var(--sans);color:var(--text-faint);margin-top:1px}
|
|
215
|
+
.suggest button.sel{background:var(--accent-soft);color:var(--accent)}
|
|
216
|
+
.suggest button.sel .desc{color:var(--text-dim)}
|
|
217
|
+
.suggest b{color:var(--accent);font-weight:600}
|
|
218
|
+
/* inline error line */
|
|
219
|
+
.line-err{display:inline-block;width:100%;background:var(--red-soft);border-radius:3px}
|
|
220
|
+
/* rename */
|
|
221
|
+
.filename{cursor:pointer}
|
|
222
|
+
#rename{font-size:11px;padding:4px 7px}
|
|
223
|
+
nav .suite-row button .rn{display:none;flex:none;font-size:10px;opacity:.6;padding:0 2px}
|
|
224
|
+
nav .suite-row:hover button .rn{display:inline}
|
|
225
|
+
nav .suite-row button .rn:hover{opacity:1}
|