Skip to content

Commit c87c651

Browse files
authored
fix(suite): Display condition results when user clicks step in execution flow (#1278)
1 parent 1658825 commit c87c651

File tree

6 files changed

+155
-28
lines changed

6 files changed

+155
-28
lines changed

storage/store/sql/sql.go

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,7 +1499,8 @@ func (s *Store) getSuiteResults(tx *sql.Tx, suiteID int64, page, pageSize int) (
14991499
resultID := data.id
15001500
// Query endpoint results for this suite result
15011501
epRows, err := tx.Query(`
1502-
SELECT
1502+
SELECT
1503+
er.endpoint_result_id,
15031504
e.endpoint_name,
15041505
er.success,
15051506
er.errors,
@@ -1514,31 +1515,73 @@ func (s *Store) getSuiteResults(tx *sql.Tx, suiteID int64, page, pageSize int) (
15141515
logr.Errorf("[sql.getSuiteResults] Failed to get endpoint results for suite_result_id=%d: %s", resultID, err.Error())
15151516
continue
15161517
}
1518+
// Map to store endpoint results by their ID for condition lookup
1519+
epResultMap := make(map[int64]*endpoint.Result)
15171520
epCount := 0
15181521
for epRows.Next() {
15191522
epCount++
1523+
var epResultID int64
15201524
var name string
15211525
var success bool
15221526
var joinedErrors string
15231527
var duration int64
15241528
var timestamp time.Time
1525-
err = epRows.Scan(&name, &success, &joinedErrors, &duration, &timestamp)
1529+
err = epRows.Scan(&epResultID, &name, &success, &joinedErrors, &duration, &timestamp)
15261530
if err != nil {
15271531
logr.Errorf("[sql.getSuiteResults] Failed to scan endpoint result: %s", err.Error())
15281532
continue
15291533
}
15301534
epResult := &endpoint.Result{
1531-
Name: name,
1532-
Success: success,
1533-
Duration: time.Duration(duration),
1534-
Timestamp: timestamp,
1535+
Name: name,
1536+
Success: success,
1537+
Duration: time.Duration(duration),
1538+
Timestamp: timestamp,
1539+
ConditionResults: []*endpoint.ConditionResult{}, // Initialize empty slice
15351540
}
15361541
if len(joinedErrors) > 0 {
15371542
epResult.Errors = strings.Split(joinedErrors, arraySeparator)
15381543
}
1544+
epResultMap[epResultID] = epResult
15391545
result.EndpointResults = append(result.EndpointResults, epResult)
15401546
}
15411547
epRows.Close()
1548+
// Fetch condition results for all endpoint results in this suite result
1549+
if len(epResultMap) > 0 {
1550+
args := make([]interface{}, 0, len(epResultMap))
1551+
condQuery := `SELECT endpoint_result_id, condition, success
1552+
FROM endpoint_result_conditions
1553+
WHERE endpoint_result_id IN (`
1554+
index := 1
1555+
for epResultID := range epResultMap {
1556+
condQuery += "$" + strconv.Itoa(index) + ","
1557+
args = append(args, epResultID)
1558+
index++
1559+
}
1560+
condQuery = condQuery[:len(condQuery)-1] + ")"
1561+
1562+
condRows, err := tx.Query(condQuery, args...)
1563+
if err != nil {
1564+
logr.Errorf("[sql.getSuiteResults] Failed to get condition results for suite_result_id=%d: %s", resultID, err.Error())
1565+
} else {
1566+
condCount := 0
1567+
for condRows.Next() {
1568+
condCount++
1569+
conditionResult := &endpoint.ConditionResult{}
1570+
var epResultID int64
1571+
if err = condRows.Scan(&epResultID, &conditionResult.Condition, &conditionResult.Success); err != nil {
1572+
logr.Errorf("[sql.getSuiteResults] Failed to scan condition result: %s", err.Error())
1573+
continue
1574+
}
1575+
if epResult, exists := epResultMap[epResultID]; exists {
1576+
epResult.ConditionResults = append(epResult.ConditionResults, conditionResult)
1577+
}
1578+
}
1579+
condRows.Close()
1580+
if condCount > 0 {
1581+
logr.Debugf("[sql.getSuiteResults] Found %d condition results for suite_result_id=%d", condCount, resultID)
1582+
}
1583+
}
1584+
}
15421585
if epCount > 0 {
15431586
logr.Debugf("[sql.getSuiteResults] Found %d endpoint results for suite_result_id=%d", epCount, resultID)
15441587
}

web/app/src/components/StepDetailsModal.vue

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,100 @@
7474
</div>
7575
</div>
7676
</div>
77+
78+
<!-- Condition Results -->
79+
<div v-if="step.result?.conditionResults?.length" class="space-y-2">
80+
<h3 class="text-sm font-medium flex items-center gap-2">
81+
<CheckCircle class="w-4 h-4" />
82+
Condition Results ({{ step.result.conditionResults.length }})
83+
</h3>
84+
<div class="space-y-2 max-h-48 overflow-y-auto">
85+
<div
86+
v-for="(conditionResult, index) in step.result.conditionResults"
87+
:key="index"
88+
class="flex items-start gap-3 p-1 rounded-lg border"
89+
:class="conditionResult.success
90+
? 'bg-green-50 dark:bg-green-900/30 border-green-200 dark:border-green-700'
91+
: 'bg-red-50 dark:bg-red-900/30 border-red-200 dark:border-red-700'"
92+
>
93+
<!-- Status icon -->
94+
<div class="flex-shrink-0 mt-0.5">
95+
<CheckCircle
96+
v-if="conditionResult.success"
97+
class="w-4 h-4 text-green-600 dark:text-green-400"
98+
/>
99+
<XCircle
100+
v-else
101+
class="w-4 h-4 text-red-600 dark:text-red-400"
102+
/>
103+
</div>
104+
105+
<!-- Condition text -->
106+
<div class="flex-1 min-w-0 flex items-center justify-between gap-3">
107+
<p class="text-sm font-mono break-all"
108+
:class="conditionResult.success
109+
? 'text-green-800 dark:text-green-200'
110+
: 'text-red-800 dark:text-red-200'">
111+
{{ conditionResult.condition }}
112+
</p>
113+
<span class="text-xs font-medium whitespace-nowrap"
114+
:class="conditionResult.success
115+
? 'text-green-600 dark:text-green-400'
116+
: 'text-red-600 dark:text-red-400'">
117+
{{ conditionResult.success ? 'Passed' : 'Failed' }}
118+
</span>
119+
</div>
120+
</div>
121+
</div>
122+
</div>
123+
124+
<!-- Endpoint Configuration -->
125+
<div v-if="step.endpoint" class="space-y-2">
126+
<h3 class="text-sm font-medium flex items-center gap-2">
127+
<Settings class="w-4 h-4" />
128+
Endpoint Configuration
129+
</h3>
130+
<div class="space-y-3 text-xs">
131+
<div v-if="step.endpoint.url">
132+
<span class="text-muted-foreground">URL:</span>
133+
<p class="font-mono mt-1 break-all">{{ step.endpoint.url }}</p>
134+
</div>
135+
<div v-if="step.endpoint.method">
136+
<span class="text-muted-foreground">Method:</span>
137+
<p class="mt-1 font-medium">{{ step.endpoint.method }}</p>
138+
</div>
139+
<div v-if="step.endpoint.interval">
140+
<span class="text-muted-foreground">Interval:</span>
141+
<p class="mt-1">{{ step.endpoint.interval }}</p>
142+
</div>
143+
<div v-if="step.endpoint.timeout">
144+
<span class="text-muted-foreground">Timeout:</span>
145+
<p class="mt-1">{{ step.endpoint.timeout }}</p>
146+
</div>
147+
</div>
148+
</div>
149+
150+
<!-- Result Errors (separate from step errors) -->
151+
<div v-if="step.result?.errors?.length" class="space-y-2">
152+
<h3 class="text-sm font-medium flex items-center gap-2 text-red-600 dark:text-red-400">
153+
<AlertCircle class="w-4 h-4" />
154+
Result Errors ({{ step.result.errors.length }})
155+
</h3>
156+
<div class="space-y-2 max-h-32 overflow-y-auto">
157+
<div v-for="(error, index) in step.result.errors" :key="index"
158+
class="p-3 bg-red-50 dark:bg-red-900/50 border border-red-200 dark:border-red-700 rounded text-sm font-mono text-red-800 dark:text-red-300 break-all">
159+
{{ error }}
160+
</div>
161+
</div>
162+
</div>
77163
</div>
78164
</div>
79165
</div>
80166
</template>
81167

82168
<script setup>
83169
import { computed } from 'vue'
84-
import { X, AlertCircle, RotateCcw, Download, CheckCircle, XCircle, SkipForward, Pause, Clock } from 'lucide-vue-next'
170+
import { X, AlertCircle, RotateCcw, Download, CheckCircle, XCircle, SkipForward, Pause, Clock, Settings } from 'lucide-vue-next'
85171
import { Button } from '@/components/ui/button'
86172
import { formatDuration } from '@/utils/format'
87173
import { prettifyTimestamp } from '@/utils/time'

web/app/src/views/SuiteDetails.vue

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
<!-- Enhanced Execution Flow -->
6969
<div class="mt-6">
7070
<h3 class="text-lg font-semibold mb-4">Execution Flow</h3>
71-
<SequentialFlowDiagram
71+
<SequentialFlowDiagram
7272
:flow-steps="flowSteps"
7373
:progress-percentage="executionProgress"
7474
:completed-steps="completedStepsCount"
@@ -132,7 +132,7 @@
132132
<Settings @refreshData="fetchData" />
133133

134134
<!-- Step Details Modal -->
135-
<StepDetailsModal
135+
<StepDetailsModal
136136
v-if="selectedStep"
137137
:step="selectedStep"
138138
:index="selectedStepIndex"
@@ -255,13 +255,10 @@ const flowSteps = computed(() => {
255255
if (!latestResult.value || !latestResult.value.endpointResults) {
256256
return []
257257
}
258-
259258
const results = latestResult.value.endpointResults
260-
261259
return results.map((result, index) => {
262260
const endpoint = suite.value?.endpoints?.[index]
263261
const nextResult = results[index + 1]
264-
265262
// Determine if this is an always-run endpoint by checking execution pattern
266263
// If a previous step failed but this one still executed, it must be always-run
267264
let isAlwaysRun = false
@@ -272,7 +269,6 @@ const flowSteps = computed(() => {
272269
break
273270
}
274271
}
275-
276272
return {
277273
name: endpoint?.name || result.name || `Step ${index + 1}`,
278274
endpoint: endpoint,
@@ -296,21 +292,17 @@ const executionProgress = computed(() => {
296292
})
297293
298294
299-
300295
// Helper functions
301296
const determineStepStatus = (result) => {
302297
if (!result) return 'not-started'
303-
304298
// Check if step was skipped
305299
if (result.conditionResults && result.conditionResults.some(c => c.condition.includes('SKIP'))) {
306300
return 'skipped'
307301
}
308-
309302
// Check if step failed but is always-run (still shows as failed but executed)
310303
if (!result.success) {
311304
return 'failed'
312305
}
313-
314306
return 'success'
315307
}
316308

web/static/css/app.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web/static/js/app.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web/static/js/chunk-vendors.js

Lines changed: 15 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)