[aidan] ux/workflows: remove redundant save workflow button

The Edit Agent already has Discard/Save controls in its strip, so the
header "Save Workflow" button was a duplicate save path. Remove it and
its pulse/edit-session-id wiring; the model/time subtitle stays.
This commit is contained in:
abccodes
2026-06-17 19:19:40 -07:00
parent 4646147834
commit 8ef855a50c
@@ -9,7 +9,6 @@ import CloseIcon from '@mui/icons-material/Close';
import HistoryIcon from '@mui/icons-material/HistoryRounded';
import PlayArrowIcon from '@mui/icons-material/PlayArrowRounded';
import DragIndicatorIcon from '@mui/icons-material/DragIndicator';
import AutoAwesomeOutlinedIcon from '@mui/icons-material/AutoAwesomeOutlined';
import InputBase from '@mui/material/InputBase';
import { useClaudeTokens } from '@/shared/styles/ThemeContext';
import { useAppDispatch, useAppSelector } from '@/shared/hooks';
@@ -196,25 +195,13 @@ const WorkflowCard: React.FC<Props> = ({
const isDraft = card?.view === 'preview' && !workflow;
const steps = (workflow?.steps || card?.draft?.steps || []) as Workflow['steps'];
// Edit-agent chrome lives in the card header: the model/time subtitle and
// the Save Workflow button. EditAgentView owns the live session and reports
// its id up here. The Save button pulses once when a turn finishes adding a
// step, nudging the user that there's something worth saving.
// Edit-agent chrome lives in the card header: the model/time subtitle.
// EditAgentView owns the live session and reports its id up here so the
// subtitle can render the live model + work time. Saving is handled by the
// Discard/Save controls inside EditAgentView itself.
const isEditAgentView = card?.view === 'edit_agent' || card?.view === 'fix_agent';
const showHeaderSaveWorkflow = isEditAgentView && !(card?.view === 'edit_agent' && workflow?.source_session_id);
const [editSessionId, setEditSessionId] = useState<string | null>(null);
const editSession = useAppSelector((s) => editSessionId ? s.agents.sessions[editSessionId] : undefined);
const [savePulseNonce, setSavePulseNonce] = useState(0);
const prevEditStatusRef = useRef<string | undefined>(undefined);
useEffect(() => {
const status = editSession?.status;
const prev = prevEditStatusRef.current;
const wasRunning = prev === 'running' || prev === 'waiting_approval';
if (wasRunning && status === 'completed' && steps.length > 0) {
setSavePulseNonce((n) => n + 1);
}
prevEditStatusRef.current = status;
}, [editSession?.status, steps.length]);
// ---- Card drag via title bar ----
const DRAG_THRESHOLD = 3;
@@ -517,47 +504,6 @@ const WorkflowCard: React.FC<Props> = ({
</>
)}
{runs && runs.length > 0 && <RunSparkline runs={runs} />}
{!isDraft && workflow && showHeaderSaveWorkflow && (
<Tooltip title={steps.length > 0 ? 'Save the workflow and close the editor' : 'Add at least one step before saving'}>
<Box
role="button"
data-no-drag
onClick={(e) => {
e.stopPropagation();
if (steps.length === 0) { setRunToast('Add at least one step to your workflow first.'); return; }
dispatch(updateWorkflowCard({ workflowId, patch: { view: 'saved' } }));
}}
onPointerDown={(e) => e.stopPropagation()}
sx={{
display: 'inline-flex', alignItems: 'center', gap: 0.5,
fontSize: '0.78rem', fontWeight: 700,
px: 1.1, py: 0.5,
borderRadius: `${c.radius.md}px`,
cursor: 'pointer',
...(steps.length > 0 ? {
color: '#fff',
bgcolor: c.accent.primary,
border: `1px solid ${c.accent.primary}`,
boxShadow: `0 0 0 0 ${c.accent.primary}00`,
animation: savePulseNonce > 0 ? `workflow-save-pulse-${savePulseNonce} 0.95s ease-out 1` : 'none',
[`@keyframes workflow-save-pulse-${savePulseNonce}`]: {
'0%': { boxShadow: `0 0 0 0 ${c.accent.primary}55`, transform: 'scale(1)' },
'55%': { boxShadow: `0 0 0 8px ${c.accent.primary}00`, transform: 'scale(1.035)' },
'100%': { boxShadow: `0 0 0 0 ${c.accent.primary}00`, transform: 'scale(1)' },
},
'&:hover': { filter: 'brightness(1.05)' },
} : {
color: c.text.muted,
bgcolor: c.bg.elevated,
border: `1px solid ${c.border.subtle}`,
}),
}}
>
<AutoAwesomeOutlinedIcon sx={{ fontSize: 14 }} />
Save Workflow
</Box>
</Tooltip>
)}
<IconButton
size="small"
data-no-drag