ShadowWolf1999 commited on
Commit
9e71caf
·
verified ·
1 Parent(s): cdadb6f

重新开始设计 我给你一个我之前的页面 {% block head_extra %}

Browse files

<style>
/* --- 1. Jira风格 核心变量 --- */
:root {
--jira-bg: #F4F5F7; /* 页面背景灰 */
--jira-card-bg: #FFFFFF; /* 卡片白 */
--jira-text: #172B4D; /* 深蓝黑文字 */
--jira-text-sub: #5E6C84; /* 次级灰文字 */
--jira-border: #DFE1E6; /* 边框灰 */
--jira-blue: #0052CC; /* 主色蓝 */
--jira-purple: #6554C0; /* AI/自动化紫 */
--jira-green: #00875A; /* 通过绿 */
--jira-red: #DE350B; /* 失败红 */
--jira-yellow: #FF991F; /* 警告黄 */
}
/* --- 新增:筛选栏样式 --- */
.filter-bar {
display: flex;
gap: 10px;
margin-bottom: 1rem;
align-items: center;
}
.filter-btn {
background: transparent;
border: 1px solid transparent;
color: #42526E;
font-weight: 500;
font-size: 0.85rem;
padding: 4px 10px;
border-radius: 3px;
transition: all 0.2s;
}
.filter-btn:hover { background: rgba(9,30,66,0.08); }
.filter-btn.active {
background: #DEEBFF;
color: #0052CC;
font-weight: bold;
}
.search-input {
border: none;
border-bottom: 2px solid var(--jira-border);
background: transparent;
padding: 4px 0;
font-size: 0.85rem;
width: 150px;
transition: border-color 0.2s;
}
.search-input:focus {
outline: none;
border-bottom-color: var(--jira-blue);
}

/* --- 新增:分类图标样式 --- */
.type-icon {
width: 20px;
height: 20px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 3px;
margin-right: 8px;
font-size: 12px;
}
.type-manual { background: #EAE6FF; color: #403294; } /* 紫色 - 人工 */
.type-ui { background: #E3FCEF; color: #006644; } /* 绿色 - UI Auto */
.type-api { background: #DEEBFF; color: #0747A6; } /* 蓝色 - API Auto */
.type-perf { background: #FFF0B3; color: #172B4D; } /* 黄色 - 性能 */

/* 状态条 */
.status-indicator { position: absolute; left: 0; top: 0; bottom: 0; width: 4px; z-index: 10; }
.status-pass { background-color: var(--jira-green); }
.status-fail { background-color: var(--jira-red); }
.status-none { background-color: var(--jira-border); }

.hidden-row { display: none !important; }

body {
background-color: var(--jira-bg);
color: var(--jira-text);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
}
/* --- Description 折叠优化 --- */
.description-box {
position: relative;
transition: max-height 0.3s ease;
}

/* 折叠状态 */
.description-box.collapsed {
max-height: 120px; /* 默认只显示约 4-5 行 */
overflow: hidden;
}

/* 折叠时的底部渐变遮罩 */
.description-box.collapsed::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 50px;
background: linear-gradient(to bottom, rgba(255,255,255,0), var(--jira-card-bg) 90%);
pointer-events: none;
}

/* Markdown 内容样式微调 */
.md-content {
color: var(--jira-text);
font-size: 0.95rem;
line-height: 1.6;
}
.md-content p { margin-bottom: 0.8rem; }
.md-content ul, .md-content ol { padding-left: 1.5rem; margin-bottom: 0.8rem; }
.md-content code { background: rgba(9, 30, 66, 0.08); padding: 2px 4px; border-radius: 3px; font-family: monospace; font-size: 0.85em; color: #DE350B; }
.md-content pre { background: #F4F5F7; padding: 10px; border-radius: 4px; overflow-x: auto; }

/* --- 2. 布局组件 --- */
.jira-card {
background: var(--jira-card-bg);
border: 1px solid var(--jira-border);
border-radius: 4px;
box-shadow: 0 1px 1px rgba(9, 30, 66, 0.25);
margin-bottom: 1rem;
transition: box-shadow 0.2s;
}

/* Sticky Sidebar: 关键样式,让右侧面板悬浮 */
.sticky-sidebar {
position: -webkit-sticky;
position: sticky;
top: 1.5rem; /* 距离顶部的间距 */
z-index: 100;
}

/* --- 3. 文本与标签 --- */
.jira-header-label {
font-size: 0.75rem;
font-weight: 700;
text-transform: uppercase;
color: var(--jira-text-sub);
margin-bottom: 0.25rem;
letter-spacing: 0.5px;
}

.jira-id-badge {
font-family: 'Consolas', 'Monaco', monospace;
background: rgba(9, 30, 66, 0.06);
color: var(--jira-text);
padding: 2px 6px;
border-radius: 3px;
font-size: 0.75rem;
cursor: pointer;
transition: all 0.2s;
border: 1px solid transparent;
}
.jira-id-badge:hover {
background: #DEEBFF;
color: var(--jira-blue);
border-color: #B3D4FF;
}

/* --- 4. 测试用例列表 (Accordion) --- */
.accordion-item {
border: 1px solid var(--jira-border);
margin-bottom: 8px;
border-radius: 4px !important;
overflow: hidden;
position: relative; /* 为了定位左侧状态条 */
}

.accordion-button {
padding: 0.75rem 1rem 0.75rem 1.5rem; /* 左侧留出空间给状态条 */
background: var(--jira-card-bg);
color: var(--jira-text);
box-shadow: none !important;
}
.accordion-button:not(.collapsed) {
background-color: #F4F5F7;
color: var(--jira-blue);
}
.accordion-button::after {
background-size: 0.8rem;
opacity: 0.6;
}

/* 左侧状态条 */
.status-indicator {
position: absolute;
left: 0; top: 0; bottom: 0;
width: 4px;
z-index: 10;
}
.status-pass { background-color: var(--jira-green); }
.status-fail { background-color: var(--jira-red); }
.status-none { background-color: var(--jira-border); }

/* --- 5. 表单与输入框 --- */
.editable-field:disabled, .editable-field:read-only {
background-color: transparent;
border-color: transparent;
padding-left: 0;
resize: none;
color: var(--jira-text);
cursor: default;
}
.editable-field:focus {
box-shadow: 0 0 0 2px #4C9AFF;
background-color: #fff;
}

/* 代码风格的文本域 (Steps) */
.steps-area {
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
font-size: 0.85rem;
background-color: #FAFBFC;
line-height: 1.5;
border-color: var(--jira-border);
}

/* --- 6. AI 控制台 --- */
.console-box {
background: #091E42;
color: #36B37E;
font-family: 'Consolas', monospace;
font-size: 0.75rem;
line-height: 1.5;
border-radius: 4px;
min-height: 200px;
max-height: 300px;
overflow-y: auto;
}

/* Toast 位置 */
.toast-container { position: fixed; bottom: 20px; right: 20px; z-index: 9999; }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid px-4 py-3">
<!-- Toast Container -->
<div class="toast-container position-fixed bottom-0 end-0 p-3" style="z-index: 9999"></div>

<!-- Header (保留) -->
<div class="row mb-3">
<div class="col-12">
<nav aria-label="breadcrumb">
<ol class="breadcrumb mb-1 small text-muted">
<li class="breadcrumb-item">Projects</li>
<li class="breadcrumb-item">{{ userstory.module.project.name }}</li>
<li class="breadcrumb-item active">Board</li>
</ol>
</nav>
<div class="d-flex justify-content-between align-items-center">
<h1 class="h5 fw-bold mb-0 text-dark">
<span class="text-muted fw-normal me-2">US-{{ userstory.id }}</span>{{ userstory.title }}
</h1>
<!-- 统计信息 -->
<div class="text-muted small">
<span id="count-display" class="fw-bold text-dark">{{ userstory.test_cases|length }}</span> issues
</div>
</div>
</div>
</div>

<div class="row">
<!-- Main List -->
<div class="col-lg-8">

<!-- Description Panel (保留原有逻辑,此处略简写) -->
<div class="jira-card p-3 mb-4 bg-white border rounded">
<h6 class="text-muted text-uppercase small fw-bold mb-2">Description</h6>
<div class="text-muted small">{{ userstory.description }}</div>
</div>

<!-- JIRA STYLE FILTER BAR [新增功能] -->
<div class="filter-bar">
<input type="text" class="search-input" id="text-filter" placeholder="Search text..." onkeyup="applyFilters()">

<!-- Stage Filter -->
<div class="dropdown">
<button class="btn filter-btn dropdown-toggle" type="button" data-bs-toggle="dropdown" id="btn-stage">
Stage: All
</button>
<ul class="dropdown-menu shadow-sm" style="font-size: 0.85rem;">
<li><a class="dropdown-item" href="#" onclick="setFilter('stage', 'all', 'All')">All</a></li>
<li><a class="dropdown-item" href="#" onclick="setFilter('stage', 'SIT', 'SIT')">SIT</a></li>
<li><a class="dropdown-item" href="#" onclick="setFilter('stage', 'UAT', 'UAT')">UAT</a></li>
<li><a class="dropdown-item" href="#" onclick="setFilter('stage', 'PVT', 'PVT')">PVT</a></li>
</ul>
</div>

<!-- Category Filter -->
<div class="dropdown">
<button class="btn filter-btn dropdow

Files changed (3) hide show
  1. components/testcase-dashboard.js +206 -262
  2. index.html +3 -11
  3. style.css +16 -95
components/testcase-dashboard.js CHANGED
@@ -4,316 +4,260 @@ class TestcaseDashboard extends HTMLElement {
4
  this.shadowRoot.innerHTML = `
5
  <style>
6
  :host {
 
 
 
 
 
 
 
 
 
 
 
7
  display: block;
8
  font-family: 'Inter', sans-serif;
9
- --primary: #6366f1;
10
- --primary-dark: #4f46e5;
11
  width: 100%;
 
 
12
  }
 
13
  .header {
14
- background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
15
  color: white;
16
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
17
- width: 100%;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  }
19
- .phase-tab {
20
- transition: all 0.3s ease;
21
- border-bottom: 3px solid transparent;
 
 
 
 
 
22
  cursor: pointer;
23
  }
24
-
25
- .phase-tab.active {
26
- border-bottom-color: var(--primary);
27
- color: var(--primary);
28
- font-weight: 600;
29
  }
30
- .pill {
31
- display: inline-flex;
32
- align-items: center;
33
- font-size: 0.75rem;
34
  font-weight: 600;
35
- padding: 0.25rem 0.75rem;
36
- border-radius: 9999px;
37
- text-transform: capitalize;
38
- line-height: 1;
39
  }
40
 
41
- table {
42
- width: 100%;
43
- border-collapse: collapse;
 
 
 
44
  }
45
 
46
- th, td {
47
- padding: 0.75rem 1.5rem;
48
- text-align: left;
49
- border-bottom: 1px solid #e5e7eb;
 
 
50
  }
51
 
52
- th {
53
- font-weight: 600;
54
- color: #6b7280;
55
- background-color: #f9fafb;
56
- text-transform: uppercase;
57
- letter-spacing: 0.05em;
58
- font-size: 0.75rem;
 
 
 
 
 
59
  }
60
 
61
- tr:hover {
62
- background-color: #f9fafb;
 
 
 
 
 
 
63
  }
64
 
65
- button {
66
- transition: all 0.2s ease;
 
 
67
  }
68
 
69
- button:hover {
70
- transform: translateY(-1px);
 
 
 
71
  }
72
- </style>
73
- <div class="min-h-screen w-full">
74
- <!-- Header -->
75
- <header class="header py-8 px-6 shadow-lg w-full">
76
- <div class="container mx-auto w-full">
77
- <div class="flex items-center justify-between">
78
- <div>
79
- <h1 class="text-3xl font-bold flex items-center">
80
- <i data-feather="activity" class="mr-3"></i>
81
- TestCase Visualizer Pro
82
- </h1>
83
- <p class="mt-2 opacity-90">Visualize your FSD test cases with clarity</p>
84
- </div>
85
- <div class="flex items-center space-x-4">
86
- <button class="bg-white text-indigo-700 px-4 py-2 rounded-lg font-medium flex items-center">
87
- <i data-feather="plus" class="mr-2"></i>
88
- Add Test Case
89
- </button>
90
- </div>
91
- </div>
92
- </div>
93
- </header>
94
-
95
- <!-- Main Content -->
96
- <main class="container mx-auto py-8 px-6 w-full">
97
- <!-- Filters -->
98
- <div class="bg-white rounded-xl shadow-md p-6 mb-8">
99
- <div class="flex flex-wrap items-center justify-between gap-4">
100
- <div class="flex items-center space-x-4">
101
- <div>
102
- <label class="block text-sm font-medium text-gray-700 mb-1">Test Type</label>
103
- <select class="border border-gray-300 rounded-lg px-4 py-2 w-48">
104
- <option>All Types</option>
105
- <option>Unit Tests</option>
106
- <option>Integration Tests</option>
107
- <option>E2E Tests</option>
108
- <option>Component Tests</option>
109
- </select>
110
- </div>
111
-
112
- <div>
113
- <label class="block text-sm font-medium text-gray-700 mb-1">Status</label>
114
- <select class="border border-gray-300 rounded-lg px-4 py-2 w-48">
115
- <option>All Statuses</option>
116
- <option>Passed</option>
117
- <option>Failed</option>
118
- <option>Pending</option>
119
- <option>Skipped</option>
120
- </select>
121
- </div>
122
- </div>
123
 
124
- <div class="flex items-center">
125
- <button class="bg-indigo-600 text-white px-4 py-2 rounded-lg font-medium flex items-center">
126
- <i data-feather="filter" class="mr-2"></i>
127
- Apply Filters
128
- </button>
129
- </div>
130
- </div>
131
- </div>
132
-
133
- <!-- Phase Tabs -->
134
- <div class="flex border-b border-gray-200 mb-6">
135
- <button class="phase-tab px-6 py-3 active">Design Phase</button>
136
- <button class="phase-tab px-6 py-3">Development Phase</button>
137
- <button class="phase-tab px-6 py-3">Testing Phase</button>
138
- <button class="phase-tab px-6 py-3">Deployment Phase</button>
139
- </div>
140
-
141
- <!-- Test Case Stats -->
142
- <div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
143
- <div class="bg-white rounded-xl shadow-md p-6">
144
- <div class="flex items-center justify-between">
145
- <div>
146
- <p class="text-gray-500">Total Test Cases</p>
147
- <h3 class="text-3xl font-bold mt-2">128</h3>
148
- </div>
149
- <div class="bg-indigo-100 p-3 rounded-full">
150
- <i data-feather="list" class="text-indigo-600"></i>
151
- </div>
152
- </div>
153
- </div>
154
-
155
- <div class="bg-white rounded-xl shadow-md p-6">
156
- <div class="flex items-center justify-between">
157
- <div>
158
- <p class="text-gray-500">Passed</p>
159
- <h3 class="text-3xl font-bold mt-2 text-green-600">98</h3>
160
- </div>
161
- <div class="bg-green-100 p-3 rounded-full">
162
- <i data-feather="check-circle" class="text-green-600"></i>
163
- </div>
164
- </div>
165
  </div>
166
-
167
- <div class="bg-white rounded-xl shadow-md p-6">
168
- <div class="flex items-center justify-between">
169
- <div>
170
- <p class="text-gray-500">Failed</p>
171
- <h3 class="text-3xl font-bold mt-2 text-red-600">12</h3>
172
- </div>
173
- <div class="bg-red-100 p-3 rounded-full">
174
- <i data-feather="x-circle" class="text-red-600"></i>
175
- </div>
176
- </div>
177
  </div>
178
-
179
- <div class="bg-white rounded-xl shadow-md p-6">
180
- <div class="flex items-center justify-between">
181
- <div>
182
- <p class="text-gray-500">Pending</p>
183
- <h3 class="text-3xl font-bold mt-2 text-yellow-600">18</h3>
184
- </div>
185
- <div class="bg-yellow-100 p-3 rounded-full">
186
- <i data-feather="clock" class="text-yellow-600"></i>
187
- </div>
188
  </div>
189
  </div>
190
- </div>
191
-
192
- <!-- Test Case List -->
193
- <div class="bg-white rounded-xl shadow-md overflow-hidden">
194
- <div class="overflow-x-auto">
195
- <table class="min-w-full divide-y divide-gray-200">
196
- <thead class="bg-gray-50">
197
- <tr>
198
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th>
199
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Test Case</th>
200
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>
201
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Phase</th>
202
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
203
- <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
204
- </tr>
205
- </thead>
206
- <tbody class="bg-white divide-y divide-gray-200">
207
- ${this.generateTestCases()}
208
- </tbody>
209
- </table>
210
- </div>
211
- </div>
212
- </main>
213
  </div>
214
  `;
215
-
216
- // Initialize feather icons
217
- setTimeout(() => {
218
- if (window.feather) {
219
- window.feather.replace();
220
- }
221
- }, 100);
222
-
223
- // Add event listeners for tabs
224
- const tabs = this.shadowRoot.querySelectorAll('.phase-tab');
225
- tabs.forEach(tab => {
226
- tab.addEventListener('click', () => {
227
- tabs.forEach(t => t.classList.remove('active'));
228
- tab.classList.add('active');
229
- });
230
- });
231
  }
232
-
233
  generateTestCases() {
234
  const testCases = [
235
  {
236
  id: 'TC-001',
237
- name: 'User authentication validation',
238
- type: 'Unit Test',
239
- phase: 'Design',
240
- status: 'Passed'
 
241
  },
242
  {
243
  id: 'TC-002',
244
- name: 'API endpoint response time',
245
- type: 'Integration Test',
246
- phase: 'Development',
247
- status: 'Failed'
 
248
  },
249
  {
250
  id: 'TC-003',
251
- name: 'Checkout flow E2E',
252
- type: 'E2E Test',
253
- phase: 'Testing',
254
- status: 'Pending'
255
- },
256
- {
257
- id: 'TC-004',
258
- name: 'UI component rendering',
259
- type: 'Component Test',
260
- phase: 'Design',
261
- status: 'Passed'
262
- },
263
- {
264
- id: 'TC-005',
265
- name: 'Database migration',
266
- type: 'Integration Test',
267
- phase: 'Deployment',
268
- status: 'Skipped'
269
  }
270
  ];
271
-
272
- return testCases.map(testCase => `
273
- <tr class="testcase-card hover:bg-gray-50">
274
- <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${testCase.id}</td>
275
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${testCase.name}</td>
276
- <td class="px-6 py-4 whitespace-nowrap">
277
- <span class="pill ${this.getTypeClass(testCase.type)}">
278
- ${testCase.type}
279
- </span>
280
- </td>
281
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${testCase.phase}</td>
282
- <td class="px-6 py-4 whitespace-nowrap">
283
- <span class="pill ${this.getStatusClass(testCase.status)}">
284
- ${testCase.status}
285
- </span>
286
- </td>
287
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
288
- <button class="text-indigo-600 hover:text-indigo-900 mr-3">
289
- <i data-feather="eye"></i>
290
- </button>
291
- <button class="text-gray-600 hover:text-gray-900">
292
- <i data-feather="more-vertical"></i>
293
- </button>
294
- </td>
295
- </tr>
296
  `).join('');
297
  }
298
-
299
- getTypeClass(type) {
300
- const classes = {
301
- 'Unit Test': 'bg-blue-100 text-blue-800',
302
- 'Integration Test': 'bg-purple-100 text-purple-800',
303
- 'E2E Test': 'bg-green-100 text-green-800',
304
- 'Component Test': 'bg-yellow-100 text-yellow-800'
305
- };
306
- return classes[type] || 'bg-gray-100 text-gray-800';
 
 
 
 
 
 
 
 
 
 
 
307
  }
308
-
309
- getStatusClass(status) {
310
- const classes = {
311
- 'Passed': 'bg-green-100 text-green-800',
312
- 'Failed': 'bg-red-100 text-red-800',
313
- 'Pending': 'bg-yellow-100 text-yellow-800',
314
- 'Skipped': 'bg-gray-100 text-gray-800'
315
  };
316
- return classes[status] || 'bg-gray-100 text-gray-800';
317
  }
318
  }
319
 
 
4
  this.shadowRoot.innerHTML = `
5
  <style>
6
  :host {
7
+ --jira-bg: #F4F5F7;
8
+ --jira-card-bg: #FFFFFF;
9
+ --jira-text: #172B4D;
10
+ --jira-text-sub: #5E6C84;
11
+ --jira-border: #DFE1E6;
12
+ --jira-blue: #0052CC;
13
+ --jira-purple: #6554C0;
14
+ --jira-green: #00875A;
15
+ --jira-red: #DE350B;
16
+ --jira-yellow: #FF991F;
17
+
18
  display: block;
19
  font-family: 'Inter', sans-serif;
 
 
20
  width: 100%;
21
+ min-height: 100vh;
22
+ background: var(--jira-bg);
23
  }
24
+
25
  .header {
26
+ background: linear-gradient(135deg, var(--jira-blue) 0%, var(--jira-purple) 100%);
27
  color: white;
28
+ padding: 1.5rem 2rem;
29
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
30
+ }
31
+
32
+ .filter-bar {
33
+ display: flex;
34
+ gap: 0.75rem;
35
+ padding: 1rem;
36
+ background: var(--jira-card-bg);
37
+ border-radius: 4px;
38
+ margin: 1rem 0;
39
+ box-shadow: 0 1px 1px rgba(9, 30, 66, 0.25);
40
+ }
41
+
42
+ .search-input {
43
+ border: none;
44
+ border-bottom: 2px solid var(--jira-border);
45
+ padding: 0.5rem 0;
46
+ width: 200px;
47
+ transition: border-color 0.2s;
48
+ }
49
+
50
+ .search-input:focus {
51
+ outline: none;
52
+ border-bottom-color: var(--jira-blue);
53
  }
54
+
55
+ .filter-btn {
56
+ background: transparent;
57
+ border: 1px solid transparent;
58
+ color: var(--jira-text-sub);
59
+ font-weight: 500;
60
+ padding: 0.5rem 1rem;
61
+ border-radius: 4px;
62
  cursor: pointer;
63
  }
64
+
65
+ .filter-btn:hover {
66
+ background: rgba(9,30,66,0.08);
 
 
67
  }
68
+
69
+ .filter-btn.active {
70
+ background: #DEEBFF;
71
+ color: var(--jira-blue);
72
  font-weight: 600;
 
 
 
 
73
  }
74
 
75
+ .testcase-card {
76
+ background: var(--jira-card-bg);
77
+ border: 1px solid var(--jira-border);
78
+ border-radius: 4px;
79
+ margin-bottom: 0.75rem;
80
+ box-shadow: 0 1px 1px rgba(9, 30, 66, 0.25);
81
  }
82
 
83
+ .status-indicator {
84
+ width: 4px;
85
+ height: 100%;
86
+ position: absolute;
87
+ left: 0;
88
+ top: 0;
89
  }
90
 
91
+ .status-pass { background: var(--jira-green); }
92
+ .status-fail { background: var(--jira-red); }
93
+ .status-none { background: var(--jira-border); }
94
+
95
+ .type-icon {
96
+ width: 24px;
97
+ height: 24px;
98
+ border-radius: 4px;
99
+ display: inline-flex;
100
+ align-items: center;
101
+ justify-content: center;
102
+ margin-right: 0.75rem;
103
  }
104
 
105
+ .type-manual { background: #EAE6FF; color: #403294; }
106
+ .type-ui { background: #E3FCEF; color: #006644; }
107
+ .type-api { background: #DEEBFF; color: #0747A6; }
108
+
109
+ .container {
110
+ max-width: 1400px;
111
+ margin: 0 auto;
112
+ padding: 0 2rem;
113
  }
114
 
115
+ .grid {
116
+ display: grid;
117
+ grid-template-columns: 1fr 300px;
118
+ gap: 1.5rem;
119
  }
120
 
121
+ .stats-card {
122
+ background: var(--jira-card-bg);
123
+ border-radius: 4px;
124
+ padding: 1rem;
125
+ box-shadow: 0 1px 1px rgba(9, 30, 66, 0.25);
126
  }
127
+ </style>
128
+
129
+ <div class="header">
130
+ <div class="container">
131
+ <h1>TestCase Visualizer Pro</h1>
132
+ <p>Visualize your FSD test cases with clarity</p>
133
+ </div>
134
+ </div>
135
+
136
+ <div class="container">
137
+ <div class="grid">
138
+ <main>
139
+ <div class="filter-bar">
140
+ <input type="text" class="search-input" placeholder="Search test cases...">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
 
142
+ <select class="filter-btn">
143
+ <option>All Stages</option>
144
+ <option>SIT</option>
145
+ <option>UAT</option>
146
+ <option>PVT</option>
147
+ </select>
148
+
149
+ <select class="filter-btn">
150
+ <option>All Types</option>
151
+ <option>Manual</option>
152
+ <option>UI Auto</option>
153
+ <option>API Auto</option>
154
+ </select>
155
+
156
+ <select class="filter-btn">
157
+ <option>All Statuses</option>
158
+ <option>Passed</option>
159
+ <option>Failed</option>
160
+ <option>Pending</option>
161
+ </select>
162
+
163
+ <button class="filter-btn active">Clear Filters</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  </div>
165
+
166
+ <div class="testcase-list">
167
+ ${this.generateTestCases()}
 
 
 
 
 
 
 
 
168
  </div>
169
+ </main>
170
+
171
+ <aside>
172
+ <div class="stats-card">
173
+ <h3>Statistics</h3>
174
+ <div class="stats-grid">
175
+ ${this.generateStats()}
 
 
 
176
  </div>
177
  </div>
178
+ </aside>
179
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  </div>
181
  `;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  }
183
+
184
  generateTestCases() {
185
  const testCases = [
186
  {
187
  id: 'TC-001',
188
+ title: 'User authentication validation',
189
+ type: 'Manual',
190
+ status: 'Passed',
191
+ stage: 'SIT',
192
+ priority: 'High'
193
  },
194
  {
195
  id: 'TC-002',
196
+ title: 'API endpoint response validation',
197
+ type: 'API Auto',
198
+ status: 'Failed',
199
+ stage: 'UAT',
200
+ priority: 'Medium'
201
  },
202
  {
203
  id: 'TC-003',
204
+ title: 'UI component rendering test',
205
+ type: 'UI Auto',
206
+ status: 'Pending',
207
+ stage: 'PVT',
208
+ priority: 'Low'
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  }
210
  ];
211
+
212
+ return testCases.map(tc => `
213
+ <div class="testcase-card">
214
+ <div class="status-indicator status-${tc.status.toLowerCase()}"></div>
215
+ <div class="p-4">
216
+ <div class="flex items-center">
217
+ <div class="type-icon type-${tc.type.toLowerCase().replace(' ', '-')}">
218
+ ${this.getTypeIcon(tc.type)}
219
+ </div>
220
+ <div>
221
+ <div class="font-medium">${tc.title}</div>
222
+ <div class="text-sm text-gray-600">${tc.id} • ${tc.stage}</div>
223
+ </div>
224
+ <div class="ml-auto">
225
+ <span class="priority-badge">${tc.priority}</span>
226
+ </div>
227
+ </div>
228
+ </div>
229
+ </div>
 
 
 
 
 
 
230
  `).join('');
231
  }
232
+
233
+ generateStats() {
234
+ return `
235
+ <div class="stat-item">
236
+ <div class="stat-value">24</div>
237
+ <div class="stat-label">Total</div>
238
+ </div>
239
+ <div class="stat-item">
240
+ <div class="stat-value text-green-600">18</div>
241
+ <div class="stat-label">Passed</div>
242
+ </div>
243
+ <div class="stat-item">
244
+ <div class="stat-value text-red-600">3</div>
245
+ <div class="stat-label">Failed</div>
246
+ </div>
247
+ <div class="stat-item">
248
+ <div class="stat-value text-yellow-600">3</div>
249
+ <div class="stat-label">Pending</div>
250
+ </div>
251
+ `;
252
  }
253
+
254
+ getTypeIcon(type) {
255
+ const icons = {
256
+ 'Manual': '👨‍💻',
257
+ 'UI Auto': '🖥️',
258
+ 'API Auto': '🔌'
 
259
  };
260
+ return icons[type] || '📋';
261
  }
262
  }
263
 
index.html CHANGED
@@ -1,3 +1,4 @@
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
@@ -8,20 +9,11 @@
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
11
- <script src="https://cdn.tailwindcss.com"></script>
12
- <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
13
  <link rel="stylesheet" href="style.css">
14
  </head>
15
- <body class="bg-gray-50">
16
  <testcase-dashboard></testcase-dashboard>
17
 
18
  <script src="components/testcase-dashboard.js"></script>
19
- <script>
20
- document.addEventListener('DOMContentLoaded', function() {
21
- if (window.feather) {
22
- feather.replace();
23
- }
24
- });
25
- </script>
26
  </body>
27
- </html>
 
1
+
2
  <!DOCTYPE html>
3
  <html lang="en">
4
  <head>
 
9
  <link rel="preconnect" href="https://fonts.googleapis.com">
10
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
 
 
12
  <link rel="stylesheet" href="style.css">
13
  </head>
14
+ <body>
15
  <testcase-dashboard></testcase-dashboard>
16
 
17
  <script src="components/testcase-dashboard.js"></script>
 
 
 
 
 
 
 
18
  </body>
19
+ </html>
style.css CHANGED
@@ -1,116 +1,37 @@
1
 
2
- :root {
3
- --primary: #6366f1;
4
- --primary-dark: #4f46e5;
5
- --secondary: #f9fafb;
6
- --success: #10b981;
7
- --danger: #ef4444;
8
- --warning: #f59e0b;
9
- --info: #3b82f6;
10
- --light: #f8fafc;
11
- --dark: #1f2937;
12
- }
13
-
14
- * {
15
- box-sizing: border-box;
16
- margin: 0;
17
- padding: 0;
18
- }
19
- /* Base styles */
20
  body {
 
21
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
22
  'Helvetica Neue', Arial, sans-serif;
23
  line-height: 1.5;
24
- color: var(--dark);
25
- background-color: #f8fafc;
26
- }
27
-
28
- /* Custom styles for test case visualization */
29
- .testcase-card {
30
- transition: all 0.3s ease;
31
- }
32
-
33
- .testcase-card:hover {
34
- background-color: #f8f9fa;
35
- }
36
-
37
- .pill {
38
- display: inline-block;
39
- font-size: 0.75rem;
40
- font-weight: 600;
41
- padding: 0.25rem 0.75rem;
42
- border-radius: 9999px;
43
- text-transform: capitalize;
44
- }
45
-
46
- /* Animation for test case status */
47
- @keyframes pulse {
48
- 0%, 100% {
49
- opacity: 1;
50
- }
51
- 50% {
52
- opacity: 0.5;
53
- }
54
- }
55
-
56
- .pulse-animation {
57
- animation: pulse 2s infinite;
58
- }
59
-
60
- /* Shadow DOM styles */
61
- .testcase-dashboard::part(header) {
62
- background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
63
- color: white;
64
- }
65
-
66
- .testcase-dashboard::part(phase-tab) {
67
- transition: all 0.3s ease;
68
- border-bottom: 3px solid transparent;
69
- }
70
-
71
- .testcase-dashboard::part(phase-tab-active) {
72
- border-bottom-color: var(--primary);
73
- color: var(--primary);
74
- font-weight: 600;
75
  }
76
 
77
  /* Utility classes */
78
- .bg-primary {
79
- background-color: var(--primary);
80
- }
81
-
82
- .text-primary {
83
- color: var(--primary);
84
- }
85
-
86
- .bg-success {
87
- background-color: var(--success);
88
- }
89
-
90
- .text-success {
91
- color: var(--success);
92
  }
93
 
94
- .bg-danger {
95
- background-color: var(--danger);
96
  }
97
 
98
- .text-danger {
99
- color: var(--danger);
100
  }
101
 
102
- .bg-warning {
103
- background-color: var(--warning);
104
  }
105
 
106
- .text-warning {
107
- color: var(--warning);
108
  }
109
 
110
- .bg-info {
111
- background-color: var(--info);
112
  }
113
 
114
- .text-info {
115
- color: var(--info);
116
  }
 
1
 
2
+ /* Base styles that will apply to the whole document */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  body {
4
+ margin: 0;
5
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
6
  'Helvetica Neue', Arial, sans-serif;
7
  line-height: 1.5;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  }
9
 
10
  /* Utility classes */
11
+ .flex {
12
+ display: flex;
 
 
 
 
 
 
 
 
 
 
 
 
13
  }
14
 
15
+ .items-center {
16
+ align-items: center;
17
  }
18
 
19
+ .justify-between {
20
+ justify-content: space-between;
21
  }
22
 
23
+ .ml-auto {
24
+ margin-left: auto;
25
  }
26
 
27
+ .text-green-600 {
28
+ color: #00875A;
29
  }
30
 
31
+ .text-red-600 {
32
+ color: #DE350B;
33
  }
34
 
35
+ .text-yellow-600 {
36
+ color: #FF991F;
37
  }