Добавлены данные по заходу на тестирование
parent
1c0cfbb411
commit
4aef89ddf0
|
|
@ -33,7 +33,7 @@ function formatCompletion(value: number | null): string {
|
|||
return `${value.toFixed(1)}%`
|
||||
}
|
||||
|
||||
function formatLeadTimeInt(value: number | null): string {
|
||||
function formatMetricInt(value: number | null): string {
|
||||
if (value === null) {
|
||||
return '—'
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ function formatLeadTimeInt(value: number | null): string {
|
|||
return String(value)
|
||||
}
|
||||
|
||||
function formatLeadTimePercentile(value: number | null): string {
|
||||
function formatMetricPercentile(value: number | null): string {
|
||||
if (value === null) {
|
||||
return '—'
|
||||
}
|
||||
|
|
@ -92,20 +92,22 @@ watch(
|
|||
<table class="sprint-table__table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="3" class="sprint-table__th-sprint">Спринт</th>
|
||||
<th rowspan="3" class="sprint-table__th-completion">Выполнение</th>
|
||||
<th rowspan="2" class="sprint-table__th-sprint">Спринт</th>
|
||||
<th rowspan="2" class="sprint-table__th-completion">Выполнение</th>
|
||||
<th colspan="5" class="sprint-table__th-group">Lead Time</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="2" class="sprint-table__th-subgroup">Границы</th>
|
||||
<th colspan="3" class="sprint-table__th-subgroup">Персентиль</th>
|
||||
<th colspan="5" class="sprint-table__th-group">Количество заходов на тестирование</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="sprint-table__th-metric">max</th>
|
||||
<th class="sprint-table__th-metric">min</th>
|
||||
<th class="sprint-table__th-metric">95</th>
|
||||
<th class="sprint-table__th-metric">80</th>
|
||||
<th class="sprint-table__th-metric">50</th>
|
||||
<th class="sprint-table__th-metric">95pp</th>
|
||||
<th class="sprint-table__th-metric">80pp</th>
|
||||
<th class="sprint-table__th-metric">50pp</th>
|
||||
<th class="sprint-table__th-metric">max</th>
|
||||
<th class="sprint-table__th-metric">min</th>
|
||||
<th class="sprint-table__th-metric">95pp</th>
|
||||
<th class="sprint-table__th-metric">80pp</th>
|
||||
<th class="sprint-table__th-metric">50pp</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -128,11 +130,16 @@ watch(
|
|||
{{ formatCompletion(sprint.sprint_completion_percentage) }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="sprint-table__metric">{{ formatLeadTimeInt(sprint.lead_time_max) }}</td>
|
||||
<td class="sprint-table__metric">{{ formatLeadTimeInt(sprint.lead_time_min) }}</td>
|
||||
<td class="sprint-table__metric">{{ formatLeadTimePercentile(sprint.lead_time_p95) }}</td>
|
||||
<td class="sprint-table__metric">{{ formatLeadTimePercentile(sprint.lead_time_p80) }}</td>
|
||||
<td class="sprint-table__metric">{{ formatLeadTimePercentile(sprint.lead_time_p50) }}</td>
|
||||
<td class="sprint-table__metric">{{ formatMetricInt(sprint.lead_time_max) }}</td>
|
||||
<td class="sprint-table__metric">{{ formatMetricInt(sprint.lead_time_min) }}</td>
|
||||
<td class="sprint-table__metric">{{ formatMetricPercentile(sprint.lead_time_p95) }}</td>
|
||||
<td class="sprint-table__metric">{{ formatMetricPercentile(sprint.lead_time_p80) }}</td>
|
||||
<td class="sprint-table__metric">{{ formatMetricPercentile(sprint.lead_time_p50) }}</td>
|
||||
<td class="sprint-table__metric">{{ formatMetricInt(sprint.test_count_max) }}</td>
|
||||
<td class="sprint-table__metric">{{ formatMetricInt(sprint.test_count_min) }}</td>
|
||||
<td class="sprint-table__metric">{{ formatMetricPercentile(sprint.test_count_p95) }}</td>
|
||||
<td class="sprint-table__metric">{{ formatMetricPercentile(sprint.test_count_p80) }}</td>
|
||||
<td class="sprint-table__metric">{{ formatMetricPercentile(sprint.test_count_p50) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -152,7 +159,7 @@ watch(
|
|||
}
|
||||
|
||||
.sprint-table__wrapper {
|
||||
overflow: hidden;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.sprint-table__table {
|
||||
|
|
@ -162,7 +169,7 @@ watch(
|
|||
|
||||
.sprint-table__table th,
|
||||
.sprint-table__table td {
|
||||
padding: 14px 18px;
|
||||
padding: 10px 14px;
|
||||
text-align: left;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
background: transparent;
|
||||
|
|
@ -170,10 +177,11 @@ watch(
|
|||
|
||||
.sprint-table__table th {
|
||||
color: #f1f4f7;
|
||||
font-size: 0.8125rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
padding: 8px 10px;
|
||||
}
|
||||
|
||||
.sprint-table__th-sprint,
|
||||
|
|
@ -186,15 +194,11 @@ watch(
|
|||
}
|
||||
|
||||
.sprint-table__th-group {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.sprint-table__th-subgroup {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.sprint-table__th-metric {
|
||||
font-size: 0.8125rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,4 +15,9 @@ export interface Sprint {
|
|||
lead_time_p95: number | null
|
||||
lead_time_p80: number | null
|
||||
lead_time_p50: number | null
|
||||
test_count_max: number | null
|
||||
test_count_min: number | null
|
||||
test_count_p95: number | null
|
||||
test_count_p80: number | null
|
||||
test_count_p50: number | null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,12 @@ final class ReportsApi {
|
|||
* lead_time_min: int|null,
|
||||
* lead_time_p95: float|null,
|
||||
* lead_time_p80: float|null,
|
||||
* lead_time_p50: float|null
|
||||
* lead_time_p50: float|null,
|
||||
* test_count_max: int|null,
|
||||
* test_count_min: int|null,
|
||||
* test_count_p95: float|null,
|
||||
* test_count_p80: float|null,
|
||||
* test_count_p50: float|null
|
||||
* }>
|
||||
*/
|
||||
public function getSprintsByTeamId(int $teamId): array {
|
||||
|
|
@ -52,13 +57,25 @@ final class ReportsApi {
|
|||
s.sprint_activate_datetime,
|
||||
s.sprint_complete_datetime,
|
||||
s.sprint_completion_percentage,
|
||||
MAX(t.lead_time_days) AS lead_time_max,
|
||||
MIN(t.lead_time_days) AS lead_time_min,
|
||||
percentile_cont(0.95) WITHIN GROUP (ORDER BY t.lead_time_days) AS lead_time_p95,
|
||||
percentile_cont(0.80) WITHIN GROUP (ORDER BY t.lead_time_days) AS lead_time_p80,
|
||||
percentile_cont(0.50) WITHIN GROUP (ORDER BY t.lead_time_days) AS lead_time_p50
|
||||
MAX(t.lead_time_days) FILTER (WHERE t.lead_time_days IS NOT NULL) AS lead_time_max,
|
||||
MIN(t.lead_time_days) FILTER (WHERE t.lead_time_days IS NOT NULL) AS lead_time_min,
|
||||
percentile_cont(0.95) WITHIN GROUP (ORDER BY t.lead_time_days)
|
||||
FILTER (WHERE t.lead_time_days IS NOT NULL) AS lead_time_p95,
|
||||
percentile_cont(0.80) WITHIN GROUP (ORDER BY t.lead_time_days)
|
||||
FILTER (WHERE t.lead_time_days IS NOT NULL) AS lead_time_p80,
|
||||
percentile_cont(0.50) WITHIN GROUP (ORDER BY t.lead_time_days)
|
||||
FILTER (WHERE t.lead_time_days IS NOT NULL) AS lead_time_p50,
|
||||
MAX(t.test_count) FILTER (WHERE e.employee_role IN (\'backend\', \'frontend\')) AS test_count_max,
|
||||
MIN(t.test_count) FILTER (WHERE e.employee_role IN (\'backend\', \'frontend\')) AS test_count_min,
|
||||
percentile_cont(0.95) WITHIN GROUP (ORDER BY t.test_count)
|
||||
FILTER (WHERE e.employee_role IN (\'backend\', \'frontend\')) AS test_count_p95,
|
||||
percentile_cont(0.80) WITHIN GROUP (ORDER BY t.test_count)
|
||||
FILTER (WHERE e.employee_role IN (\'backend\', \'frontend\')) AS test_count_p80,
|
||||
percentile_cont(0.50) WITHIN GROUP (ORDER BY t.test_count)
|
||||
FILTER (WHERE e.employee_role IN (\'backend\', \'frontend\')) AS test_count_p50
|
||||
FROM sprints s
|
||||
LEFT JOIN tasks t ON t.sprint_id = s.id AND t.lead_time_days IS NOT NULL
|
||||
LEFT JOIN tasks t ON t.sprint_id = s.id
|
||||
LEFT JOIN employees e ON e.id = t.employee_id
|
||||
WHERE s.team_id = :team_id
|
||||
GROUP BY s.id,
|
||||
s.jira_sprint_id,
|
||||
|
|
@ -85,6 +102,11 @@ final class ReportsApi {
|
|||
'lead_time_p95' => $row['lead_time_p95'] !== null ? (float) $row['lead_time_p95'] : null,
|
||||
'lead_time_p80' => $row['lead_time_p80'] !== null ? (float) $row['lead_time_p80'] : null,
|
||||
'lead_time_p50' => $row['lead_time_p50'] !== null ? (float) $row['lead_time_p50'] : null,
|
||||
'test_count_max' => $row['test_count_max'] !== null ? (int) $row['test_count_max'] : null,
|
||||
'test_count_min' => $row['test_count_min'] !== null ? (int) $row['test_count_min'] : null,
|
||||
'test_count_p95' => $row['test_count_p95'] !== null ? (float) $row['test_count_p95'] : null,
|
||||
'test_count_p80' => $row['test_count_p80'] !== null ? (float) $row['test_count_p80'] : null,
|
||||
'test_count_p50' => $row['test_count_p50'] !== null ? (float) $row['test_count_p50'] : null,
|
||||
],
|
||||
$rows
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue