Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | 1x 3x 3x 3x 3x 3x 3x 1x 2x 16x | /**
* LifecycleSpine (Epic 14 Phase B — Story 14.B.1; FR8, UX-DR2).
*
* Horizontal 8-state stepper: completed = green check, current = highlighted
* with "Step N of 8". Reuses the existing workflow helpers (this is NOT
* `WorkflowProgressBar`, which is a %-bar — the spine is a discrete stepper).
* The `compact` seam (a "Step N/8" bar) is wired for Phase G mobile.
*/
import React from 'react';
import { Box, Stepper, Step, StepLabel, Typography, LinearProgress } from '@mui/material';
import { useTranslation } from 'react-i18next';
import {
WORKFLOW_STATE_ORDER,
getWorkflowStepNumber,
getWorkflowProgress,
getWorkflowStateLabel,
} from '@/utils/workflow/workflowState';
interface LifecycleSpineProps {
workflowState: string;
/** Mobile (Phase G): collapse to a "Step N/8" bar instead of the full stepper. */
compact?: boolean;
}
export const LifecycleSpine: React.FC<LifecycleSpineProps> = ({
workflowState,
compact = false,
}) => {
const { t } = useTranslation('events');
const total = WORKFLOW_STATE_ORDER.length;
const stepNumber = getWorkflowStepNumber(workflowState); // 1..8, 0 if invalid
const activeIndex = stepNumber > 0 ? stepNumber - 1 : 0;
const stepOfLabel = t('eventPage.cockpit.spine.stepOf', 'Step {{current}} of {{total}}', {
current: stepNumber || 1,
total,
});
if (compact) {
return (
<Box
data-testid="cockpit-lifecycle-spine"
data-workflow-state={workflowState}
aria-label={stepOfLabel}
>
<Typography variant="subtitle2" gutterBottom>
{stepOfLabel}
</Typography>
<LinearProgress
variant="determinate"
value={getWorkflowProgress(workflowState)}
sx={{ height: 8, borderRadius: 1 }}
/>
</Box>
);
}
return (
<Box data-testid="cockpit-lifecycle-spine" data-workflow-state={workflowState}>
<Typography variant="subtitle2" color="text.secondary" gutterBottom>
{stepOfLabel}
</Typography>
<Stepper activeStep={activeIndex} alternativeLabel aria-label={stepOfLabel}>
{WORKFLOW_STATE_ORDER.map((state, i) => (
<Step key={state} completed={i < activeIndex}>
<StepLabel aria-current={i === activeIndex ? 'step' : undefined}>
{getWorkflowStateLabel(state, t)}
</StepLabel>
</Step>
))}
</Stepper>
</Box>
);
};
|