feat: StepDetail accepts RuntimeStep, renders Custom Step badge for custom steps
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { AlertTriangle, CheckCircle2, Info, Zap, Copy, Check, ExternalLink } from 'lucide-react'
|
import { AlertTriangle, CheckCircle2, Info, Zap, Copy, Check, ExternalLink } from 'lucide-react'
|
||||||
import type { ProceduralStep, StepContentType, CommandBlock } from '@/types'
|
import type { RuntimeStep, StepContentType, CommandBlock } from '@/types'
|
||||||
import { resolveVariables } from '@/lib/variableResolver'
|
import { resolveVariables } from '@/lib/variableResolver'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ const contentTypeConfig: Record<StepContentType, { icon: typeof Zap; color: stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface StepDetailProps {
|
interface StepDetailProps {
|
||||||
step: ProceduralStep
|
step: RuntimeStep
|
||||||
stepNumber: number
|
stepNumber: number
|
||||||
totalSteps: number
|
totalSteps: number
|
||||||
variables: Record<string, string>
|
variables: Record<string, string>
|
||||||
@@ -39,13 +39,18 @@ export function StepDetail({
|
|||||||
isLast,
|
isLast,
|
||||||
}: StepDetailProps) {
|
}: StepDetailProps) {
|
||||||
const [copiedIndex, setCopiedIndex] = useState<number | null>(null)
|
const [copiedIndex, setCopiedIndex] = useState<number | null>(null)
|
||||||
|
const isCustom = 'isCustom' in step && step.isCustom
|
||||||
const contentType = step.content_type || 'action'
|
const contentType = step.content_type || 'action'
|
||||||
const config = contentTypeConfig[contentType]
|
const config = contentTypeConfig[contentType]
|
||||||
const Icon = config.icon
|
const Icon = config.icon
|
||||||
|
|
||||||
// Derive verification from either flat fields or nested object
|
// Derive verification from either flat fields or nested object
|
||||||
const verificationPrompt = step.verification_prompt || step.verification?.prompt
|
const verificationPrompt = !isCustom && 'verification_prompt' in step
|
||||||
const verificationType = step.verification_type || step.verification?.type
|
? step.verification_prompt || step.verification?.prompt
|
||||||
|
: undefined
|
||||||
|
const verificationType = !isCustom && 'verification_type' in step
|
||||||
|
? step.verification_type || step.verification?.type
|
||||||
|
: undefined
|
||||||
|
|
||||||
const resolve = (text: string | undefined) => {
|
const resolve = (text: string | undefined) => {
|
||||||
if (!text) return ''
|
if (!text) return ''
|
||||||
@@ -87,14 +92,20 @@ export function StepDetail({
|
|||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<h2 className="text-lg font-semibold text-foreground">{step.title}</h2>
|
<h2 className="text-lg font-semibold text-foreground">{step.title}</h2>
|
||||||
<div className="mt-1 flex items-center gap-2">
|
<div className="mt-1 flex items-center gap-2">
|
||||||
<span className={cn('inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs', config.bg, config.color)}>
|
{isCustom ? (
|
||||||
<Icon className="h-3 w-3" />
|
<span className="inline-flex items-center gap-1 rounded-full bg-amber-400/15 px-2 py-0.5 text-xs text-amber-400">
|
||||||
{config.label}
|
✦ Custom Step
|
||||||
</span>
|
</span>
|
||||||
|
) : (
|
||||||
|
<span className={cn('inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs', config.bg, config.color)}>
|
||||||
|
<Icon className="h-3 w-3" />
|
||||||
|
{config.label}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
<span className="text-xs text-muted-foreground">
|
<span className="text-xs text-muted-foreground">
|
||||||
Step {stepNumber} of {totalSteps}
|
Step {stepNumber} of {totalSteps}
|
||||||
</span>
|
</span>
|
||||||
{step.estimated_minutes && (
|
{'estimated_minutes' in step && step.estimated_minutes && (
|
||||||
<span className="text-xs text-muted-foreground">~{step.estimated_minutes} min</span>
|
<span className="text-xs text-muted-foreground">~{step.estimated_minutes} min</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -102,7 +113,7 @@ export function StepDetail({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Warning banner */}
|
{/* Warning banner */}
|
||||||
{step.warning_text && (
|
{'warning_text' in step && step.warning_text && (
|
||||||
<div className="flex items-start gap-2 rounded-lg border border-yellow-400/20 bg-yellow-400/5 px-3 py-2.5">
|
<div className="flex items-start gap-2 rounded-lg border border-yellow-400/20 bg-yellow-400/5 px-3 py-2.5">
|
||||||
<AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-yellow-400" />
|
<AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-yellow-400" />
|
||||||
<p className="text-sm text-yellow-200">{resolve(step.warning_text)}</p>
|
<p className="text-sm text-yellow-200">{resolve(step.warning_text)}</p>
|
||||||
@@ -142,7 +153,7 @@ export function StepDetail({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Expected outcome */}
|
{/* Expected outcome */}
|
||||||
{step.expected_outcome && (
|
{'expected_outcome' in step && step.expected_outcome && (
|
||||||
<div className="rounded-lg border border-border bg-white/[0.02] p-3">
|
<div className="rounded-lg border border-border bg-white/[0.02] p-3">
|
||||||
<h4 className="mb-1 text-xs font-medium text-muted-foreground">Expected Outcome</h4>
|
<h4 className="mb-1 text-xs font-medium text-muted-foreground">Expected Outcome</h4>
|
||||||
<p className="text-sm text-muted-foreground">{resolve(step.expected_outcome)}</p>
|
<p className="text-sm text-muted-foreground">{resolve(step.expected_outcome)}</p>
|
||||||
@@ -181,7 +192,7 @@ export function StepDetail({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Notes */}
|
{/* Notes */}
|
||||||
{step.notes_enabled !== false && (
|
{(!('notes_enabled' in step) || step.notes_enabled !== false) && (
|
||||||
<div>
|
<div>
|
||||||
<label className="mb-1 block text-xs font-medium text-muted-foreground">Notes</label>
|
<label className="mb-1 block text-xs font-medium text-muted-foreground">Notes</label>
|
||||||
<textarea
|
<textarea
|
||||||
@@ -195,7 +206,7 @@ export function StepDetail({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Reference link */}
|
{/* Reference link */}
|
||||||
{step.reference_url && (
|
{'reference_url' in step && step.reference_url && (
|
||||||
<a
|
<a
|
||||||
href={resolve(step.reference_url)}
|
href={resolve(step.reference_url)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
|||||||
Reference in New Issue
Block a user