@ai-qa/workflow 2.0.17 → 2.0.18

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.
@@ -1,242 +1,254 @@
1
1
  <% layout='layouts/main' %>
2
- <% title='Dashboard' %>
3
-
4
- <div class="hero">
5
- <h1>AI QA Pipeline </h1>
6
- <p>User Story → Test Plan → Test Generation → Execution → Self-Healing → Report</p>
7
- <% if (project) { %>
8
- <p class="hero-project">
9
- Project: <strong>
10
- <%= project.name %>
11
- </strong>
12
- <% if (stats.lastRunStatus==='passed' ) { %><span class="badge badge-pass" style="margin-left:0.5rem;">Last
13
- Run ✅</span>
2
+ <% title='Dashboard' %>
3
+
4
+ <div class="hero">
5
+ <h1>Orchestrator QA</h1>
6
+ <p>User Story → Test Plan → Test Generation → Execution → Self-Healing → Report</p>
7
+ <% if (project) { %>
8
+ <p class="hero-project">
9
+ Project: <strong><%= project.name %></strong>
10
+ <% if (stats.lastRunStatus==='passed' ) { %><span class="badge badge-pass" style="margin-left:0.5rem;">Last Run ✅</span><% } %>
11
+ <% if (stats.lastRunStatus==='failed' ) { %><span class="badge badge-fail" style="margin-left:0.5rem;">Last Run ❌</span><% } %>
12
+ </p>
13
+ <% } %>
14
+ </div>
15
+
16
+ <% if (!project) { %>
17
+ <div class="empty-state">
18
+ <div style="font-size:3rem;margin-bottom:1rem;">🚀</div>
19
+ <h3>Aucun projet configuré</h3>
20
+ <p>Pointez le dashboard vers votre projet pour voir les données.</p>
21
+ <a href="/projects/add" class="btn btn-primary" style="margin-top:0.5rem;">Configurer un projet</a>
22
+ </div>
23
+ <% } else { %>
24
+
25
+ <!-- ─── Stats cliquables ─── -->
26
+ <div class="stats-row">
27
+ <a href="/stories?project=<%= project.id %>" class="stat-card" style="text-decoration:none;color:inherit;display:block;cursor:pointer;">
28
+ <div class="stat-number"><%= stats.stories %></div>
29
+ <div class="stat-label">User Stories</div>
30
+ </a>
31
+ <a href="/stories?project=<%= project.id %>&filter=planned" class="stat-card" style="text-decoration:none;color:inherit;display:block;cursor:pointer;">
32
+ <div class="stat-number"><%= stats.plans %></div>
33
+ <div class="stat-label">Test Plans</div>
34
+ </a>
35
+ <a href="/stories?project=<%= project.id %>&filter=tested" class="stat-card" style="text-decoration:none;color:inherit;display:block;cursor:pointer;">
36
+ <div class="stat-number"><%= stats.specs %></div>
37
+ <div class="stat-label">Test Specs</div>
38
+ </a>
39
+ <a href="/runs?project=<%= project.id %>" class="stat-card" style="text-decoration:none;color:inherit;display:block;cursor:pointer;">
40
+ <div class="stat-number"><%= stats.runs %></div>
41
+ <div class="stat-label">Executions</div>
42
+ </a>
43
+ <a href="/analytics?project=<%= project.id %>" class="stat-card" style="text-decoration:none;color:inherit;display:block;cursor:pointer;">
44
+ <div class="stat-number <%= stats.passRate >= 80 ? 'text-success' : stats.passRate >= 50 ? 'text-warning' : stats.runs > 0 ? 'text-danger' : '' %>">
45
+ <%= stats.runs > 0 ? stats.passRate + '%' : '—' %>
46
+ </div>
47
+ <div class="stat-label">Pass Rate</div>
48
+ </a>
49
+ </div>
50
+
51
+ <!-- ─── Activités récentes (stories) ─── -->
52
+ <% if (stats.storiesList && stats.storiesList.length > 0) { %>
53
+ <div class="card">
54
+ <h3>📋 Activités récentes</h3>
55
+ <table class="info-table">
56
+ <thead>
57
+ <tr>
58
+ <th>User Story</th>
59
+ <th>Plan</th>
60
+ <th>Test</th>
61
+ <th>Actions</th>
62
+ </tr>
63
+ </thead>
64
+ <tbody>
65
+ <% stats.storiesList.slice(0, 10).forEach(s => { %>
66
+ <tr>
67
+ <td><a href="/stories/<%= s.name %>?project=<%= project.id %>" style="font-weight:600;"><%= s.name.replace('.md', '') %></a></td>
68
+ <td>
69
+ <% if (s.hasPlan) { %><span class="badge badge-plan">✅ Planned</span>
70
+ <% } else { %><span class="badge badge-draft">⏳ Pending</span><% } %>
71
+ </td>
72
+ <td>
73
+ <% if (s.hasSpec) { %><span class="badge badge-spec">✅ Tested</span>
74
+ <% } else if (s.hasPlan) { %><span class="badge badge-draft">⏳ Pending</span>
75
+ <% } else { %><span class="badge badge-draft">—</span><% } %>
76
+ </td>
77
+ <td>
78
+ <a href="/stories/<%= s.name %>?project=<%= project.id %>" class="btn btn-sm">View</a>
79
+ <% if (s.hasSpec) { %>
80
+ <button class="btn btn-sm btn-primary" onclick="quickExecute('<%= project.id %>', '<%= s.name %>')">▶ Run</button>
14
81
  <% } %>
15
- <% if (stats.lastRunStatus==='failed' ) { %><span class="badge badge-fail"
16
- style="margin-left:0.5rem;">Last Run ❌</span>
17
- <% } %>
18
- </p>
19
- <% } %>
82
+ </td>
83
+ </tr>
84
+ <% }) %>
85
+ </tbody>
86
+ </table>
87
+ </div>
88
+ <% } %>
89
+
90
+ <!-- ─── Latest Run Summary ─── -->
91
+ <% if (stats.latestRun) { %>
92
+ <div class="card card-lavender">
93
+ <h3>⚡ Dernière exécution</h3>
94
+ <div style="display:flex;gap:2rem;flex-wrap:wrap;">
95
+ <div><strong>Test:</strong> <%= stats.latestRun.testName || 'All' %></div>
96
+ <div><strong>Durée:</strong> <%= stats.latestRun.duration ? (stats.latestRun.duration / 1000).toFixed(1) + 's' : 'N/A' %></div>
97
+ <div><strong>Passed:</strong> <%= stats.latestRun.passedCount %></div>
98
+ <div><strong>Failed:</strong> <%= stats.latestRun.failedCount %></div>
99
+ <div>
100
+ <a href="/runs/<%= stats.latestRun.id %>?project=<%= project.id %>" class="btn btn-sm">Details</a>
101
+ <a href="/export/report/<%= stats.latestRun.id %>?project=<%= project.id %>" class="btn btn-sm">📥 Report</a>
102
+ </div>
20
103
  </div>
21
-
22
- <% if (!project) { %>
23
- <!-- ─── No project state ─── -->
24
- <div class="empty-state">
25
- <div style="font-size:3rem;margin-bottom:1rem;">🚀</div>
26
- <h3>Dashboard prêt — aucun projet configuré</h3>
27
- <p>Ce dashboard est une template. Pointez-le vers votre dossier de test pour voir vos données.</p>
28
- <a href="/projects/add" class="btn btn-primary" style="margin-top:0.5rem;">Configurer un projet</a>
104
+ </div>
105
+ <% } %>
106
+
107
+ <!-- ─── Pipeline flow ─── -->
108
+ <div class="pipeline-flow">
109
+ <h2>Pipeline</h2>
110
+ <div class="flow-steps">
111
+ <div class="flow-step <%= stats.stories > 0 ? 'step-active' : '' %>">
112
+ <div class="step-icon">📝</div>
113
+ <div class="step-name">User Story</div>
114
+ <div class="step-desc"><%= stats.stories %> story<%= stats.stories !== 1 ? 's' : '' %></div>
29
115
  </div>
30
-
31
- <% } else { %>
32
-
33
- <!-- ─── Real stats from project folder ─── -->
34
- <div class="stats-row">
35
- <div class="stat-card">
36
- <div class="stat-number">
37
- <%= stats.stories %>
38
- </div>
39
- <div class="stat-label">User Stories</div>
40
- </div>
41
- <div class="stat-card">
42
- <div class="stat-number">
43
- <%= stats.plans %>
44
- </div>
45
- <div class="stat-label">Test Plans</div>
46
- </div>
47
- <div class="stat-card">
48
- <div class="stat-number">
49
- <%= stats.specs %>
50
- </div>
51
- <div class="stat-label">Test Specs</div>
52
- </div>
53
- <div class="stat-card">
54
- <div class="stat-number">
55
- <%= stats.runs %>
56
- </div>
57
- <div class="stat-label">Executions</div>
58
- </div>
59
- <div class="stat-card">
60
- <div
61
- class="stat-number <%= stats.passRate >= 80 ? 'text-success' : stats.passRate >= 50 ? 'text-warning' : stats.runs > 0 ? 'text-danger' : '' %>">
62
- <%= stats.runs> 0 ? stats.passRate + '%' : '—' %>
63
- </div>
64
- <div class="stat-label">Pass Rate</div>
65
- </div>
66
- </div>
67
-
68
- <!-- ─── Pipeline flow ─── -->
69
- <div class="pipeline-flow">
70
- <h2>Pipeline</h2>
71
- <div class="flow-steps">
72
- <div class="flow-step <%= stats.stories > 0 ? 'step-active' : '' %>">
73
- <div class="step-icon">📝</div>
74
- <div class="step-name">User Story</div>
75
- <div class="step-desc">
76
- <%= stats.stories %> story<%= stats.stories !==1 ? 's' : '' %>
77
- </div>
78
- </div>
79
- <div class="flow-arrow">→</div>
80
- <div class="flow-step <%= stats.plans > 0 ? 'step-active' : '' %>">
81
- <div class="step-icon">📋</div>
82
- <div class="step-name">Plan</div>
83
- <div class="step-desc">
84
- <%= stats.plans %> plan<%= stats.plans !==1 ? 's' : '' %>
85
- </div>
86
- </div>
87
- <div class="flow-arrow">→</div>
88
- <div class="flow-step <%= stats.specs > 0 ? 'step-active' : '' %>">
89
- <div class="step-icon">🧪</div>
90
- <div class="step-name">Generate</div>
91
- <div class="step-desc">
92
- <%= stats.specs %> spec<%= stats.specs !==1 ? 's' : '' %>
93
- </div>
94
- </div>
95
- <div class="flow-arrow">→</div>
96
- <div class="flow-step <%= stats.runs > 0 ? 'step-active' : '' %>">
97
- <div class="step-icon">⚡</div>
98
- <div class="step-name">Execute</div>
99
- <div class="step-desc">
100
- <%= stats.runs %> run<%= stats.runs !==1 ? 's' : '' %>
101
- </div>
102
- </div>
103
- <div class="flow-arrow">→</div>
104
- <div class="flow-step">
105
- <div class="step-icon">🛠️</div>
106
- <div class="step-name">Heal</div>
107
- <div class="step-desc">Auto-fix failures</div>
108
- </div>
109
- <div class="flow-arrow">→</div>
110
- <div class="flow-step">
111
- <div class="step-icon">📊</div>
112
- <div class="step-name">Report</div>
113
- <div class="step-desc">Comprehensive results</div>
114
- </div>
115
- </div>
116
- </div>
117
-
118
- <!-- ─── Quick links ─── -->
119
- <div class="quick-links-row">
120
- <a href="/stories?project=<%= project.id %>" class="quick-link-card">
121
- <div class="ql-icon">📝</div>
122
- <div class="ql-label">Stories <span class="badge badge-project">
123
- <%= stats.stories %>
124
- </span></div>
125
- </a>
126
- <a href="/runs?project=<%= project.id %>" class="quick-link-card">
127
- <div class="ql-icon">⚡</div>
128
- <div class="ql-label">Runs <span class="badge badge-project">
129
- <%= stats.runs %>
130
- </span></div>
131
- </a>
132
- <a href="/analytics?project=<%= project.id %>" class="quick-link-card">
133
- <div class="ql-icon">📊</div>
134
- <div class="ql-label">Analytics</div>
135
- </a>
136
- <a href="/projects/<%= project.id %>" class="quick-link-card">
137
- <div class="ql-icon">⚙️</div>
138
- <div class="ql-label">Pipeline</div>
139
- </a>
140
- </div>
141
-
142
- <% if (stats.stories===0) { %>
143
- <div class="alert alert-info" style="margin-top:1.5rem;">
144
- 💡 <strong>Aucune user story trouvée</strong> dans <code><%= project.path %>/user-story/</code>.
145
- Ajoutez un fichier <code>.md</code> pour commencer.
146
- </div>
147
- <% } %>
148
-
149
- <% } %>
150
-
151
- <style>
152
- .hero-project {
153
- color: var(--text-muted);
154
- font-size: 0.95rem;
155
- margin-top: 0.5rem;
156
- }
157
-
158
- /* Active pipeline step */
159
- .step-active {
160
- border-color: var(--primary);
161
- background: rgba(99, 102, 241, 0.08);
162
- }
163
-
164
- .step-active .step-name {
165
- color: var(--primary);
166
- }
167
-
168
- /* Quick links row */
169
- .quick-links-row {
170
- display: flex;
171
- gap: 1rem;
172
- flex-wrap: wrap;
173
- margin: 2rem 0;
174
- }
175
-
176
- .quick-link-card {
177
- flex: 1;
178
- min-width: 140px;
179
- background: var(--surface);
180
- border: 1px solid var(--border);
181
- border-radius: var(--radius);
182
- padding: 1.25rem 1rem;
183
- text-align: center;
184
- text-decoration: none;
185
- color: var(--text);
186
- transition: border-color 0.2s, transform 0.15s;
187
- }
188
-
189
- .quick-link-card:hover {
190
- border-color: var(--primary);
191
- transform: translateY(-2px);
192
- }
193
-
194
- .ql-icon {
195
- font-size: 1.75rem;
196
- margin-bottom: 0.4rem;
197
- }
198
-
199
- .ql-label {
200
- font-size: 0.9rem;
201
- font-weight: 600;
202
- display: flex;
203
- align-items: center;
204
- justify-content: center;
205
- gap: 0.4rem;
206
- }
207
-
208
- /* Info alert */
209
- .alert-info {
210
- background: #1e1b4b;
211
- border: 1px solid #3730a3;
212
- color: #a5b4fc;
213
- }
214
-
215
- @media (max-width: 768px) {
216
- .stats-row {
217
- flex-wrap: wrap;
218
- }
219
-
220
- .stat-card {
221
- flex: 1 1 calc(50% - 0.5rem);
222
- min-width: unset;
223
- }
224
-
225
- .quick-links-row {
226
- gap: 0.75rem;
227
- }
228
-
229
- .quick-link-card {
230
- min-width: calc(50% - 0.375rem);
231
- }
232
-
233
- .flow-steps {
234
- flex-direction: column;
235
- align-items: flex-start;
236
- }
237
-
238
- .flow-arrow {
239
- transform: rotate(90deg);
240
- }
241
- }
242
- </style>
116
+ <div class="flow-arrow">→</div>
117
+ <div class="flow-step <%= stats.plans > 0 ? 'step-active' : '' %>">
118
+ <div class="step-icon">📋</div>
119
+ <div class="step-name">Plan</div>
120
+ <div class="step-desc"><%= stats.plans %> plan<%= stats.plans !== 1 ? 's' : '' %></div>
121
+ </div>
122
+ <div class="flow-arrow">→</div>
123
+ <div class="flow-step <%= stats.specs > 0 ? 'step-active' : '' %>">
124
+ <div class="step-icon">🧪</div>
125
+ <div class="step-name">Generate</div>
126
+ <div class="step-desc"><%= stats.specs %> spec<%= stats.specs !== 1 ? 's' : '' %></div>
127
+ </div>
128
+ <div class="flow-arrow">→</div>
129
+ <div class="flow-step <%= stats.runs > 0 ? 'step-active' : '' %>">
130
+ <div class="step-icon">⚡</div>
131
+ <div class="step-name">Execute</div>
132
+ <div class="step-desc"><%= stats.runs %> run<%= stats.runs !== 1 ? 's' : '' %></div>
133
+ </div>
134
+ <div class="flow-arrow">→</div>
135
+ <div class="flow-step">
136
+ <div class="step-icon">🛠️</div>
137
+ <div class="step-name">Heal</div>
138
+ <div class="step-desc">Auto-fix failures</div>
139
+ </div>
140
+ <div class="flow-arrow">→</div>
141
+ <div class="flow-step">
142
+ <div class="step-icon">📊</div>
143
+ <div class="step-name">Report</div>
144
+ <div class="step-desc">Comprehensive results</div>
145
+ </div>
146
+ </div>
147
+ </div>
148
+
149
+ <!-- ─── Quick Actions ─── -->
150
+ <div class="quick-links-row">
151
+ <a href="/stories?project=<%= project.id %>" class="quick-link-card">
152
+ <div class="ql-icon">📝</div>
153
+ <div class="ql-label">Stories <span class="badge badge-project"><%= stats.stories %></span></div>
154
+ </a>
155
+ <a href="/runs?project=<%= project.id %>" class="quick-link-card">
156
+ <div class="ql-icon">⚡</div>
157
+ <div class="ql-label">Runs <span class="badge badge-project"><%= stats.runs %></span></div>
158
+ </a>
159
+ <a href="/analytics?project=<%= project.id %>" class="quick-link-card">
160
+ <div class="ql-icon">📊</div>
161
+ <div class="ql-label">Analytics</div>
162
+ </a>
163
+ <a href="/projects/<%= project.id %>" class="quick-link-card">
164
+ <div class="ql-icon">⚙️</div>
165
+ <div class="ql-label">Pipeline Orchestrator</div>
166
+ </a>
167
+ <% if (stats.hasAllure) { %>
168
+ <a href="/allure-report?project=<%= project.id %>" class="quick-link-card" target="_blank">
169
+ <div class="ql-icon">📈</div>
170
+ <div class="ql-label">Allure Report</div>
171
+ </a>
172
+ <% } %>
173
+ </div>
174
+
175
+ <% if (stats.stories === 0) { %>
176
+ <div class="alert alert-info" style="margin-top:1.5rem;">
177
+ 💡 <strong>Aucune user story trouvée</strong> dans <code><%= project.path %>/user-story/</code>.
178
+ Ajoutez un fichier <code>.md</code> pour commencer.
179
+ </div>
180
+ <% } %>
181
+ <% } %>
182
+
183
+ <script>
184
+ async function quickExecute(projectId, storyName) {
185
+ window.location.href = `/stories/${encodeURIComponent(storyName)}?project=${projectId}&autoRun=true`;
186
+ }
187
+ </script>
188
+
189
+ <style>
190
+ .hero-project {
191
+ color: var(--text-muted);
192
+ font-size: 0.95rem;
193
+ margin-top: 0.5rem;
194
+ }
195
+ .step-active {
196
+ border-color: var(--primary);
197
+ background: rgba(99, 102, 241, 0.08);
198
+ }
199
+ .step-active .step-name {
200
+ color: var(--primary);
201
+ }
202
+ .quick-links-row {
203
+ display: flex;
204
+ gap: 1rem;
205
+ flex-wrap: wrap;
206
+ margin: 2rem 0;
207
+ }
208
+ .quick-link-card {
209
+ flex: 1;
210
+ min-width: 140px;
211
+ background: var(--surface);
212
+ border: 1px solid var(--border);
213
+ border-radius: var(--radius);
214
+ padding: 1.25rem 1rem;
215
+ text-align: center;
216
+ text-decoration: none;
217
+ color: var(--text);
218
+ transition: border-color 0.2s, transform 0.15s;
219
+ }
220
+ .quick-link-card:hover {
221
+ border-color: var(--primary);
222
+ transform: translateY(-2px);
223
+ }
224
+ .ql-icon {
225
+ font-size: 1.75rem;
226
+ margin-bottom: 0.4rem;
227
+ }
228
+ .ql-label {
229
+ font-size: 0.9rem;
230
+ font-weight: 600;
231
+ display: flex;
232
+ align-items: center;
233
+ justify-content: center;
234
+ gap: 0.4rem;
235
+ }
236
+ .alert-info {
237
+ background: #1e1b4b;
238
+ border: 1px solid #3730a3;
239
+ color: #a5b4fc;
240
+ }
241
+ .stat-card:hover {
242
+ border-color: var(--primary) !important;
243
+ transform: translateY(-2px);
244
+ box-shadow: var(--shadow-2);
245
+ }
246
+ @media (max-width: 768px) {
247
+ .stats-row { flex-wrap: wrap; }
248
+ .stat-card { flex: 1 1 calc(50% - 0.5rem); min-width: unset; }
249
+ .quick-links-row { gap: 0.75rem; }
250
+ .quick-link-card { min-width: calc(50% - 0.375rem); }
251
+ .flow-steps { flex-direction: column; align-items: flex-start; }
252
+ .flow-arrow { transform: rotate(90deg); }
253
+ }
254
+ </style>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title><%= title || 'QA Dashboard' %> — AI QA Pipeline</title>
6
+ <title><%= title || 'QA Dashboard' %> — Orchestrator QA</title>
7
7
  <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@500;600;700&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">
8
8
  <link rel="stylesheet" href="/css/style.css">
9
9
  <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
@@ -12,13 +12,14 @@
12
12
  <body>
13
13
  <nav class="navbar">
14
14
  <div class="nav-inner">
15
- <a href="/" class="nav-brand">AI QA Pipeline</a>
15
+ <a href="/" class="nav-brand">Orchestrator QA</a>
16
16
  <div class="nav-links">
17
17
  <a href="/projects">Projects</a>
18
18
  <a href="/stories">Stories</a>
19
19
  <a href="/runs">Runs</a>
20
20
  <a href="/review">Review</a>
21
21
  <a href="/analytics">Analytics</a>
22
+ <a href="/terminal">Terminal</a>
22
23
  <a href="/data">Test Data</a>
23
24
  <button onclick="location.reload()" class="btn-refresh" title="Refresh">↻</button>
24
25
  </div>