mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-12 04:37:44 +02:00
[aidan] refactor/workflow-cards: use radius and status design tokens, polish card chrome
This commit is contained in:
@@ -213,7 +213,7 @@ export default function EditAgentView({ workflow, steps, isFixMode = false, onEd
|
||||
title={canSave ? undefined : 'Add at least one step before saving'}
|
||||
sx={{
|
||||
fontSize: '0.8rem', fontWeight: 700, color: '#fff', bgcolor: c.accent.primary,
|
||||
px: 1.2, py: 0.35, borderRadius: 999, cursor: canSave ? 'pointer' : 'not-allowed',
|
||||
px: 1.2, py: 0.35, borderRadius: c.radius.full, cursor: canSave ? 'pointer' : 'not-allowed',
|
||||
opacity: canSave ? 1 : 0.45,
|
||||
'&:hover': { filter: 'brightness(1.05)' },
|
||||
}}>
|
||||
|
||||
@@ -139,7 +139,7 @@ export default function SchedulePopover({
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.12, ease: 'easeOut' }}
|
||||
transition={{ duration: 0.14, ease: 'easeOut' }}
|
||||
style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column' }}>
|
||||
{mode === 'search' && (
|
||||
<Box sx={{ flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0 }}>
|
||||
|
||||
@@ -179,8 +179,8 @@ export default function ScheduleThisPopover({ anchorEl, onClose, sessionId, sess
|
||||
display: 'flex', flexDirection: 'column', gap: 0.4,
|
||||
px: 1, py: 0.75, mb: 0.75,
|
||||
borderRadius: `${c.radius.md}px`,
|
||||
bgcolor: c.status.warningBg || c.bg.elevated,
|
||||
border: `1px solid ${(c.status.warning || c.text.muted) + '60'}`,
|
||||
bgcolor: c.status.warningBg,
|
||||
border: `1px solid ${c.status.warning + '60'}`,
|
||||
}}>
|
||||
<Typography sx={{ fontSize: '0.78rem', fontWeight: 700, color: c.text.primary }}>
|
||||
This chat is already scheduled.
|
||||
|
||||
@@ -472,7 +472,7 @@ const WorkflowCard: React.FC<Props> = ({
|
||||
? '2px solid #3b82f6'
|
||||
: isRunning
|
||||
? `1px solid ${c.accent.primary}80`
|
||||
: `1px solid ${c.border.subtle}`;
|
||||
: `1px solid ${c.border.strong}`;
|
||||
|
||||
const shadow = isHighlighted
|
||||
? `0 0 0 3px ${c.accent.primary}50, 0 0 20px ${c.accent.primary}35, 0 0 40px ${c.accent.primary}15`
|
||||
@@ -480,7 +480,7 @@ const WorkflowCard: React.FC<Props> = ({
|
||||
? c.shadow.lg
|
||||
: isSelected
|
||||
? `0 0 0 1px #3b82f6, ${c.shadow.md}`
|
||||
: c.shadow.md;
|
||||
: c.shadow.sm;
|
||||
|
||||
return (
|
||||
<Box
|
||||
@@ -514,7 +514,7 @@ const WorkflowCard: React.FC<Props> = ({
|
||||
width: displayW,
|
||||
height: autoHeight ? 'auto' : displayH,
|
||||
maxHeight: autoHeight ? 'min(82vh, 760px)' : undefined,
|
||||
borderRadius: '14px',
|
||||
borderRadius: 3,
|
||||
border,
|
||||
bgcolor: c.bg.surface,
|
||||
boxShadow: shadow,
|
||||
@@ -541,7 +541,7 @@ const WorkflowCard: React.FC<Props> = ({
|
||||
onPointerUp={handleDragPointerUp}
|
||||
sx={{
|
||||
display: 'flex', alignItems: 'center', gap: 1,
|
||||
px: 2, py: 1.4,
|
||||
px: 2, pt: 2, pb: 1.4,
|
||||
cursor: isDragging ? 'grabbing' : 'grab',
|
||||
touchAction: 'none', userSelect: 'none',
|
||||
flexShrink: 0,
|
||||
@@ -549,7 +549,7 @@ const WorkflowCard: React.FC<Props> = ({
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<DragIndicatorIcon sx={{ fontSize: 18, color: c.text.muted }} />
|
||||
<DragIndicatorIcon sx={{ fontSize: 16, color: c.text.ghost, mr: -0.5 }} />
|
||||
{isDraft ? (
|
||||
// Draft state: title is inline-editable. Patches the openCard's
|
||||
// draft.title so PreviewView picks it up on Save. Saved cards
|
||||
@@ -610,9 +610,9 @@ const WorkflowCard: React.FC<Props> = ({
|
||||
data-no-drag
|
||||
onClick={(e) => { e.stopPropagation(); onClose(); }}
|
||||
onPointerDown={(e) => e.stopPropagation()}
|
||||
sx={{ p: 0.5, color: c.text.secondary, '&:hover': { color: c.status.error, bgcolor: c.status.errorBg } }}
|
||||
sx={{ p: 0.5, color: c.text.ghost, '&:hover': { color: c.status.error, bgcolor: c.status.errorBg } }}
|
||||
>
|
||||
<CloseIcon sx={{ fontSize: 17 }} />
|
||||
<CloseIcon sx={{ fontSize: 16 }} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
||||
@@ -633,7 +633,6 @@ const WorkflowCard: React.FC<Props> = ({
|
||||
workflow={null}
|
||||
runs={null}
|
||||
fallbackModel={card?.draft?.model}
|
||||
fallbackMode={card?.draft?.mode}
|
||||
fallbackSourceSessionId={card?.draft?.source_session_id}
|
||||
/>
|
||||
<Box sx={{ flex: 1 }} />
|
||||
@@ -842,7 +841,7 @@ const WorkflowCard: React.FC<Props> = ({
|
||||
<Box sx={{
|
||||
position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%,-50%)',
|
||||
fontSize: '1.4rem', fontWeight: 700, color: c.accent.primary,
|
||||
bgcolor: c.bg.surface, px: 1.2, py: 0.5, borderRadius: 999,
|
||||
bgcolor: c.bg.surface, px: 1.2, py: 0.5, borderRadius: c.radius.full,
|
||||
boxShadow: c.shadow.md,
|
||||
animation: 'first-success-pop 1.4s ease-out forwards',
|
||||
'@keyframes first-success-pop': {
|
||||
@@ -944,11 +943,10 @@ function EditAgentSubtitle({ session }: { session: import('@/shared/state/agents
|
||||
);
|
||||
}
|
||||
|
||||
function SubtitleRow({ workflow, runs, fallbackModel, fallbackMode, fallbackSourceSessionId }: {
|
||||
function SubtitleRow({ workflow, runs, fallbackModel, fallbackSourceSessionId }: {
|
||||
workflow: Workflow | null;
|
||||
runs: import('@/shared/state/workflowsSlice').WorkflowRun[] | null;
|
||||
fallbackModel?: string;
|
||||
fallbackMode?: string;
|
||||
fallbackSourceSessionId?: string | null;
|
||||
}) {
|
||||
const c = useClaudeTokens();
|
||||
@@ -957,8 +955,8 @@ function SubtitleRow({ workflow, runs, fallbackModel, fallbackMode, fallbackSour
|
||||
// model/mode and use its work time for the "28s" so the subtitle reads the
|
||||
// same as the source chat card did.
|
||||
const sourceSession = useAppSelector((s) => fallbackSourceSessionId ? s.agents.sessions[fallbackSourceSessionId] : undefined);
|
||||
// Match Image #34/#35/#36/#38/#40: "Claude Opus 4.6 agent 28s".
|
||||
// Spaces between fields, all in muted text.
|
||||
// Reads "Claude Opus 4.6 28s": model then work time, spaces between,
|
||||
// all muted. Mode is omitted to match the chat card's subtitle.
|
||||
const effModel = workflow?.model || fallbackModel || '';
|
||||
const modelLabel = React.useMemo(() => {
|
||||
if (!effModel) return '';
|
||||
@@ -969,7 +967,6 @@ function SubtitleRow({ workflow, runs, fallbackModel, fallbackMode, fallbackSour
|
||||
}
|
||||
return effModel;
|
||||
}, [effModel, modelsByProvider]);
|
||||
const modeLabel = workflow?.mode || fallbackMode || '';
|
||||
const duration = React.useMemo(() => {
|
||||
const finished = (runs || []).find((r) => r.finished_at);
|
||||
if (finished && finished.finished_at) {
|
||||
@@ -989,7 +986,6 @@ function SubtitleRow({ workflow, runs, fallbackModel, fallbackMode, fallbackSour
|
||||
return (
|
||||
<Box sx={{ display: 'inline-flex', alignItems: 'center', gap: 1.25, fontSize: '0.82rem', color: c.text.muted, minWidth: 0, overflow: 'hidden' }}>
|
||||
{modelLabel && <Box component="span" sx={{ whiteSpace: 'nowrap' }}>{modelLabel}</Box>}
|
||||
{modeLabel && <Box component="span" sx={{ whiteSpace: 'nowrap' }}>{modeLabel}</Box>}
|
||||
{duration && <Box component="span" sx={{ whiteSpace: 'nowrap' }}>{duration}</Box>}
|
||||
</Box>
|
||||
);
|
||||
@@ -1030,7 +1026,7 @@ function RunningHeader({ workflowId }: { workflowId: string }) {
|
||||
onClick={controlsDisabled ? undefined : onStop}
|
||||
role="button"
|
||||
aria-disabled={controlsDisabled}
|
||||
sx={{ display: 'inline-flex', alignItems: 'center', gap: 0.35, fontSize: '0.82rem', fontWeight: 600, px: 1, py: 0.4, color: c.text.secondary, cursor: controlsDisabled ? 'default' : 'pointer', borderRadius: 999, opacity: controlsDisabled && !stopPending ? 0.55 : 1, '&:hover': controlsDisabled ? {} : { color: c.text.primary, bgcolor: c.bg.elevated } }}>
|
||||
sx={{ display: 'inline-flex', alignItems: 'center', gap: 0.35, fontSize: '0.82rem', fontWeight: 600, px: 1, py: 0.4, color: c.text.secondary, cursor: controlsDisabled ? 'default' : 'pointer', borderRadius: c.radius.full, opacity: controlsDisabled && !stopPending ? 0.55 : 1, '&:hover': controlsDisabled ? {} : { color: c.text.primary, bgcolor: c.bg.elevated } }}>
|
||||
{stopPending ? <CircularProgress size={14} thickness={5} sx={{ color: c.text.secondary }} /> : <StopRounded sx={{ fontSize: 15 }} />}
|
||||
Stop
|
||||
</Box>
|
||||
@@ -1042,7 +1038,7 @@ function RunningHeader({ workflowId }: { workflowId: string }) {
|
||||
sx={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 0.35,
|
||||
fontSize: '0.82rem', fontWeight: 700,
|
||||
px: 1.1, py: 0.4, borderRadius: 999,
|
||||
px: 1.1, py: 0.4, borderRadius: c.radius.full,
|
||||
bgcolor: c.accent.primary, color: '#fff', cursor: controlsDisabled ? 'default' : 'pointer',
|
||||
opacity: controlsDisabled && !pausePending ? 0.55 : 1,
|
||||
'&:hover': controlsDisabled ? {} : { filter: 'brightness(1.05)' },
|
||||
|
||||
@@ -85,7 +85,7 @@ export function ActionBtn({ label, tone, disabled, onClick, icon }: { label: str
|
||||
display: 'inline-flex', alignItems: 'center', gap: 0.4,
|
||||
fontSize: '0.78rem', fontWeight: 600,
|
||||
px: 1, py: 0.35,
|
||||
borderRadius: 999,
|
||||
borderRadius: c.radius.full,
|
||||
cursor: disabled ? 'not-allowed' : 'pointer',
|
||||
color: palette.color,
|
||||
bgcolor: palette.bg,
|
||||
@@ -267,7 +267,7 @@ export function PreviewView({ workflowId, steps, sourceSessionId, initialDraft,
|
||||
sx={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 0.5,
|
||||
fontSize: '0.88rem', fontWeight: 700,
|
||||
px: 1.75, py: 0.6, borderRadius: 999,
|
||||
px: 1.75, py: 0.6, borderRadius: c.radius.full,
|
||||
color: '#fff', bgcolor: c.accent.primary,
|
||||
cursor: busy ? 'wait' : canSave ? 'pointer' : 'not-allowed',
|
||||
opacity: busy || !canSave ? 0.6 : 1,
|
||||
@@ -300,7 +300,7 @@ export function PreviewView({ workflowId, steps, sourceSessionId, initialDraft,
|
||||
role="button"
|
||||
onClick={canSave ? onSaveDraft : undefined}
|
||||
title={canSave ? undefined : 'Add at least one step before saving'}
|
||||
sx={{ fontSize: '0.84rem', fontWeight: 700, color: '#fff', bgcolor: c.accent.primary, borderRadius: 999, cursor: busy ? 'wait' : canSave ? 'pointer' : 'not-allowed', px: 1.5, py: 0.6, opacity: busy || !canSave ? 0.6 : 1, '&:hover': { filter: 'brightness(1.06)' } }}>
|
||||
sx={{ fontSize: '0.84rem', fontWeight: 700, color: '#fff', bgcolor: c.accent.primary, borderRadius: c.radius.full, cursor: busy ? 'wait' : canSave ? 'pointer' : 'not-allowed', px: 1.5, py: 0.6, opacity: busy || !canSave ? 0.6 : 1, '&:hover': { filter: 'brightness(1.06)' } }}>
|
||||
Save
|
||||
</Box>
|
||||
</DialogActions>
|
||||
@@ -466,7 +466,7 @@ export function SavedView({ workflow, steps, runs, activeRunId }: { workflow: Wo
|
||||
sx={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 0.5,
|
||||
fontSize: '0.88rem', fontWeight: 700,
|
||||
px: 1.75, py: 0.6, borderRadius: 999,
|
||||
px: 1.75, py: 0.6, borderRadius: c.radius.full,
|
||||
color: '#fff', bgcolor: c.accent.primary,
|
||||
cursor: 'pointer',
|
||||
'&:hover': { bgcolor: c.accent.primary, filter: 'brightness(1.06)' },
|
||||
@@ -499,12 +499,12 @@ export function SavedView({ workflow, steps, runs, activeRunId }: { workflow: Wo
|
||||
display: 'inline-flex', alignItems: 'center', gap: 0.45,
|
||||
fontSize: '0.82rem', fontWeight: 600,
|
||||
px: 1.25, py: 0.5,
|
||||
borderRadius: 999,
|
||||
borderRadius: c.radius.full,
|
||||
cursor: 'pointer',
|
||||
color: c.text.secondary,
|
||||
bgcolor: 'transparent',
|
||||
border: `1px solid ${c.border.medium}`,
|
||||
'&:hover': { bgcolor: c.bg.elevated, borderColor: c.border.strong || c.border.medium, color: c.text.primary },
|
||||
'&:hover': { bgcolor: c.bg.elevated, borderColor: c.border.strong, color: c.text.primary },
|
||||
}}>
|
||||
<EditOutlined sx={{ fontSize: 15 }} />
|
||||
Edit
|
||||
@@ -596,7 +596,7 @@ function AuditTraceLink({ workflowId }: { workflowId: string }) {
|
||||
<Box onClick={open} role="button" sx={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 0.3,
|
||||
fontSize: '0.7rem', color: c.text.muted, cursor: 'pointer',
|
||||
px: 0.5, py: 0.25, borderRadius: 0.75,
|
||||
px: 0.5, py: 0.25, borderRadius: c.radius.sm,
|
||||
'&:hover': { color: c.accent.primary, bgcolor: c.bg.elevated },
|
||||
}}>
|
||||
<HistoryIcon sx={{ fontSize: 12 }} />
|
||||
@@ -712,7 +712,7 @@ export function HistoryList({ runs, onOpen, showWorkflow = false, workflowTitleF
|
||||
color: filter === k ? c.accent.primary : c.text.muted,
|
||||
bgcolor: filter === k ? c.accent.primary + '14' : 'transparent',
|
||||
border: `1px solid ${filter === k ? c.accent.primary + '40' : c.border.subtle}`,
|
||||
px: 0.7, py: 0.2, borderRadius: 999, cursor: 'pointer',
|
||||
px: 0.75, py: 0.3, borderRadius: c.radius.full, cursor: 'pointer',
|
||||
'&:hover': { color: c.accent.primary },
|
||||
}}>
|
||||
{k === 'all' ? 'All' : k === 'failure' ? 'Failures only' : 'Ran late only'}
|
||||
@@ -733,8 +733,8 @@ export function HistoryList({ runs, onOpen, showWorkflow = false, workflowTitleF
|
||||
<Box key={r.id}>
|
||||
<Box
|
||||
onClick={() => setExpandedId(expanded ? null : r.id)}
|
||||
sx={{ display: 'flex', alignItems: 'center', gap: 1.25, py: 0.6, px: 0.5, cursor: 'pointer', borderRadius: 0.75, '&:hover': { bgcolor: c.bg.elevated } }}>
|
||||
<Box sx={{ fontSize: '0.72rem', fontWeight: 700, color: statusColor(r.status, c), bgcolor: statusBg(r.status, c), px: 0.8, py: 0.3, borderRadius: 0.75, minWidth: 64, textAlign: 'center' }}>
|
||||
sx={{ display: 'flex', alignItems: 'center', gap: 1.25, py: 0.6, px: 0.5, cursor: 'pointer', borderRadius: c.radius.sm, '&:hover': { bgcolor: c.bg.elevated } }}>
|
||||
<Box sx={{ fontSize: '0.72rem', fontWeight: 700, color: statusColor(r.status, c), bgcolor: statusBg(r.status, c), px: 0.8, py: 0.3, borderRadius: c.radius.sm, minWidth: 64, textAlign: 'center' }}>
|
||||
{labelForStatus(r.status)}
|
||||
</Box>
|
||||
{showWorkflow && workflowTitleFor ? (
|
||||
@@ -753,7 +753,7 @@ export function HistoryList({ runs, onOpen, showWorkflow = false, workflowTitleF
|
||||
<Box sx={{ fontSize: '0.7rem', color: c.text.ghost, transform: expanded ? 'rotate(180deg)' : 'none', transition: 'transform 0.15s ease' }}>▾</Box>
|
||||
</Box>
|
||||
{expanded && (
|
||||
<Box sx={{ ml: 8, mt: 0.25, mb: 0.75, p: 1, bgcolor: c.bg.elevated, borderRadius: 0.75, border: `1px solid ${c.border.subtle}` }}>
|
||||
<Box sx={{ ml: 8, mt: 0.25, mb: 0.75, p: 1, bgcolor: c.bg.elevated, borderRadius: c.radius.sm, border: `1px solid ${c.border.subtle}` }}>
|
||||
{r.error ? (
|
||||
<Typography sx={{ fontSize: '0.78rem', color: c.status.error, lineHeight: 1.4 }}>{r.error}</Typography>
|
||||
) : (
|
||||
@@ -784,11 +784,11 @@ export function HistoryDetail({ run, onBack }: { run: WorkflowRun | null; onBack
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<Box onClick={onBack} role="button" sx={{ fontSize: '0.82rem', color: c.text.muted, cursor: 'pointer', '&:hover': { color: c.accent.primary } }}>← back</Box>
|
||||
<Box sx={{ fontSize: '0.72rem', fontWeight: 700, color: statusColor(run.status, c), bgcolor: statusBg(run.status, c), px: 0.8, py: 0.3, borderRadius: 0.75 }}>{labelForStatus(run.status)}</Box>
|
||||
<Box sx={{ fontSize: '0.72rem', fontWeight: 700, color: statusColor(run.status, c), bgcolor: statusBg(run.status, c), px: 0.8, py: 0.3, borderRadius: c.radius.sm }}>{labelForStatus(run.status)}</Box>
|
||||
<Typography sx={{ fontSize: '0.88rem', color: c.text.primary, fontWeight: 600 }}>{formatRunDate(run.started_at)}</Typography>
|
||||
</Box>
|
||||
{run.error && (
|
||||
<Typography sx={{ fontSize: '0.85rem', color: c.status.error, bgcolor: c.status.errorBg, p: 1, borderRadius: 0.75 }}>{run.error}</Typography>
|
||||
<Typography sx={{ fontSize: '0.85rem', color: c.status.error, bgcolor: c.status.errorBg, p: 1, borderRadius: c.radius.sm }}>{run.error}</Typography>
|
||||
)}
|
||||
<Typography sx={{ fontSize: '0.85rem', color: c.text.secondary, lineHeight: 1.5 }}>Started {formatRunDate(run.started_at)}, finished {run.finished_at ? formatRunDate(run.finished_at) : 'in progress'}.</Typography>
|
||||
{run.session_id && (
|
||||
|
||||
@@ -3,6 +3,7 @@ import Box from '@mui/material/Box';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import InputBase from '@mui/material/InputBase';
|
||||
import Fade from '@mui/material/Fade';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
|
||||
@@ -108,14 +109,14 @@ function TimeSavedBadge() {
|
||||
<Tooltip title={`${count} workflow runs completed for you. Rough estimate of ~3 min saved per run vs. doing it by hand.`}>
|
||||
<Box sx={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 0.5,
|
||||
ml: 1, px: 0.85, py: 0.2,
|
||||
ml: 1, px: 0.75, py: 0.3,
|
||||
fontSize: '0.74rem', fontWeight: 600,
|
||||
color: c.text.secondary,
|
||||
bgcolor: 'transparent',
|
||||
border: `1px solid ${c.border.subtle}`,
|
||||
borderRadius: 999,
|
||||
borderRadius: c.radius.full,
|
||||
}}>
|
||||
<Box sx={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 14, height: 14, borderRadius: '50%', bgcolor: (c.status.success || c.accent.primary) + '22', color: c.status.success || c.accent.primary, fontSize: 9, fontWeight: 800 }}>✓</Box>
|
||||
<Box sx={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 14, height: 14, borderRadius: '50%', bgcolor: c.status.success + '22', color: c.status.success, fontSize: 9, fontWeight: 800 }}>✓</Box>
|
||||
<span style={{ color: c.text.primary }}>{count}</span>
|
||||
<span style={{ color: c.text.muted }}>·</span>
|
||||
<span style={{ color: c.text.secondary }}>{timeLabel} back</span>
|
||||
@@ -344,14 +345,14 @@ const WorkflowsHubCard: React.FC<Props> = ({
|
||||
? `2px solid ${c.accent.primary}`
|
||||
: isSelected
|
||||
? '2px solid #3b82f6'
|
||||
: `1px solid ${c.border.medium}`;
|
||||
: `1px solid ${c.border.strong}`;
|
||||
const shadow = isHighlighted
|
||||
? `0 0 0 3px ${c.accent.primary}50, 0 0 20px ${c.accent.primary}35, 0 0 40px ${c.accent.primary}15`
|
||||
: (isDragging || isResizing)
|
||||
? c.shadow.lg
|
||||
: isSelected
|
||||
? `0 0 0 1px #3b82f6, ${c.shadow.md}`
|
||||
: c.shadow.md;
|
||||
: c.shadow.sm;
|
||||
const noTransition = isDragging || isResizing || (isSelected && !!multiDragDelta);
|
||||
|
||||
return (
|
||||
@@ -380,7 +381,7 @@ const WorkflowsHubCard: React.FC<Props> = ({
|
||||
height: dh,
|
||||
bgcolor: c.bg.surface,
|
||||
border,
|
||||
borderRadius: `${c.radius.lg}px`,
|
||||
borderRadius: 3,
|
||||
boxShadow: shadow,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
@@ -408,15 +409,15 @@ const WorkflowsHubCard: React.FC<Props> = ({
|
||||
points right, matching the Workflows brand mark. */}
|
||||
<CallSplitRoundedIcon sx={{ fontSize: 16, transform: 'rotate(90deg)' }} />
|
||||
</Box>
|
||||
<Typography sx={{ flex: 1, fontWeight: 700, fontSize: '0.88rem', color: c.text.primary }}>Workflows</Typography>
|
||||
<Typography sx={{ flex: 1, fontWeight: 600, fontSize: '0.95rem', color: c.text.primary }}>Workflows</Typography>
|
||||
<IconButton
|
||||
size="small"
|
||||
data-no-drag
|
||||
onClick={(e) => { e.stopPropagation(); dispatch(closeWorkflowsHub()); }}
|
||||
onPointerDown={(e) => e.stopPropagation()}
|
||||
sx={{ p: 0.35, color: c.text.ghost, '&:hover': { color: c.status.error, bgcolor: c.status.errorBg } }}
|
||||
sx={{ p: 0.5, color: c.text.ghost, '&:hover': { color: c.status.error, bgcolor: c.status.errorBg } }}
|
||||
>
|
||||
<CloseIcon sx={{ fontSize: 15 }} />
|
||||
<CloseIcon sx={{ fontSize: 16 }} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
|
||||
@@ -433,9 +434,9 @@ const WorkflowsHubCard: React.FC<Props> = ({
|
||||
data-no-drag
|
||||
sx={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 0.4,
|
||||
fontSize: '0.85rem', fontWeight: 600, color: c.text.primary,
|
||||
fontSize: '0.82rem', fontWeight: 600, color: c.text.primary,
|
||||
bgcolor: c.bg.elevated, border: `1px solid ${c.border.subtle}`,
|
||||
px: 1, py: 0.4, borderRadius: `${c.radius.md}px`, cursor: 'pointer',
|
||||
px: 1, py: 0.35, borderRadius: `${c.radius.md}px`, cursor: 'pointer',
|
||||
'&:hover': { borderColor: c.accent.primary, color: c.accent.primary },
|
||||
}}
|
||||
>
|
||||
@@ -448,11 +449,11 @@ const WorkflowsHubCard: React.FC<Props> = ({
|
||||
data-no-drag
|
||||
sx={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 0.4, ml: 0.5,
|
||||
fontSize: '0.8rem', fontWeight: 600,
|
||||
color: paused ? c.status.warning || c.accent.primary : c.text.secondary,
|
||||
bgcolor: paused ? (c.status.warningBg || c.bg.elevated) : 'transparent',
|
||||
border: `1px solid ${paused ? (c.status.warning || c.accent.primary) + '60' : c.border.subtle}`,
|
||||
px: 0.85, py: 0.3, borderRadius: `${c.radius.md}px`, cursor: 'pointer',
|
||||
fontSize: '0.82rem', fontWeight: 600,
|
||||
color: c.text.secondary,
|
||||
bgcolor: paused ? c.bg.elevated : 'transparent',
|
||||
border: `1px solid ${paused ? c.border.medium : c.border.subtle}`,
|
||||
px: 1, py: 0.35, borderRadius: `${c.radius.md}px`, cursor: 'pointer',
|
||||
'&:hover': { color: c.text.primary, borderColor: c.border.medium },
|
||||
}}>
|
||||
<Switch size="small" checked={paused} sx={{ pointerEvents: 'none', mr: -0.5, ml: -0.5 }} />
|
||||
@@ -468,7 +469,7 @@ const WorkflowsHubCard: React.FC<Props> = ({
|
||||
sx={{
|
||||
fontSize: '0.82rem', fontWeight: 500, color: c.text.secondary,
|
||||
border: `1px solid ${c.border.subtle}`,
|
||||
px: 1.1, py: 0.35, borderRadius: `${c.radius.md}px`, cursor: 'pointer',
|
||||
px: 1, py: 0.35, borderRadius: `${c.radius.md}px`, cursor: 'pointer',
|
||||
'&:hover': { color: c.text.primary, borderColor: c.border.medium },
|
||||
}}>Today</Box>
|
||||
<IconButton size="small" data-no-drag onClick={() => setRefDate(addDays(refDate, view === 'Month' ? -28 : -7))} sx={{ p: 0.3 }}><ChevronLeftIcon sx={{ fontSize: 18 }} /></IconButton>
|
||||
@@ -495,7 +496,7 @@ const WorkflowsHubCard: React.FC<Props> = ({
|
||||
{view}
|
||||
<KeyboardArrowDownIcon sx={{ fontSize: 16 }} />
|
||||
</Box>
|
||||
{viewOpen && (
|
||||
<Fade in={viewOpen} timeout={{ enter: 200, exit: 220 }} unmountOnExit>
|
||||
<Box sx={{ position: 'absolute', top: '100%', right: 0, mt: 0.5, bgcolor: c.bg.surface, border: `1px solid ${c.border.subtle}`, borderRadius: `${c.radius.md}px`, boxShadow: c.shadow.md, zIndex: 5, minWidth: 110 }}>
|
||||
{(['List', 'Week', 'Month'] as const).map((v) => (
|
||||
<Box
|
||||
@@ -507,7 +508,7 @@ const WorkflowsHubCard: React.FC<Props> = ({
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
)}
|
||||
</Fade>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -686,7 +687,7 @@ function SidebarSection({ title, items, onPick, scheduled, onContext, onSchedule
|
||||
<Box
|
||||
onClick={(e) => toggleEnabled(w, e)}
|
||||
sx={{
|
||||
width: 14, height: 14, borderRadius: '3px', flexShrink: 0,
|
||||
width: 14, height: 14, borderRadius: c.radius.sm, flexShrink: 0,
|
||||
border: `1.5px solid ${w.schedule.enabled ? c.accent.primary : c.border.medium}`,
|
||||
bgcolor: w.schedule.enabled ? c.accent.primary : 'transparent',
|
||||
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
|
||||
@@ -702,7 +703,7 @@ function SidebarSection({ title, items, onPick, scheduled, onContext, onSchedule
|
||||
<Box
|
||||
onClick={(e) => { e.stopPropagation(); onSchedule?.(w, e.currentTarget); }}
|
||||
sx={{
|
||||
width: 16, height: 16, borderRadius: '4px', flexShrink: 0,
|
||||
width: 16, height: 16, borderRadius: c.radius.sm, flexShrink: 0,
|
||||
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
|
||||
color: c.text.muted, cursor: 'pointer',
|
||||
'&:hover': { color: c.accent.primary, bgcolor: c.bg.elevated },
|
||||
@@ -720,7 +721,7 @@ function SidebarSection({ title, items, onPick, scheduled, onContext, onSchedule
|
||||
)}
|
||||
</Typewriter>
|
||||
{scheduled && (!w.schedule.enabled || allPaused) && (
|
||||
<Box sx={{ flexShrink: 0, px: 0.6, py: 0.1, borderRadius: '3px', bgcolor: c.bg.elevated, color: c.text.muted, fontSize: '0.62rem', fontWeight: 600, lineHeight: 1.5, letterSpacing: '0.02em' }}>Paused</Box>
|
||||
<Box sx={{ flexShrink: 0, px: 0.6, py: 0.1, borderRadius: c.radius.sm, bgcolor: c.bg.elevated, color: c.text.muted, fontSize: '0.62rem', fontWeight: 600, lineHeight: 1.5, letterSpacing: '0.02em' }}>Paused</Box>
|
||||
)}
|
||||
</Box>
|
||||
))}
|
||||
|
||||
@@ -36,7 +36,7 @@ export function ActionBtn({ label, tone, disabled, onClick, icon }: { label: str
|
||||
sx={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 0.45,
|
||||
fontSize: LABEL_FS, fontWeight: 600, px: 1.25, py: 0.5,
|
||||
borderRadius: 999,
|
||||
borderRadius: c.radius.full,
|
||||
cursor: disabled ? 'not-allowed' : 'pointer',
|
||||
color: palette.color,
|
||||
bgcolor: palette.bg,
|
||||
|
||||
@@ -48,7 +48,7 @@ export type LastRunStatus = NonNullable<Workflow['last_run_status']>;
|
||||
export function statusDotColor(status: LastRunStatus | null | undefined, c: ReturnType<typeof useClaudeTokens>) {
|
||||
switch (status) {
|
||||
case 'success': return c.status.success;
|
||||
case 'ran_late': return c.status.warning || '#f59e0b';
|
||||
case 'ran_late': return c.status.warning;
|
||||
case 'failure': return c.status.error;
|
||||
case 'running': return c.accent.primary;
|
||||
case 'skipped': return c.text.muted;
|
||||
@@ -75,7 +75,7 @@ export function StatusDot({ status }: { status: LastRunStatus | null | undefined
|
||||
<Tooltip title={status ? `Last run: ${word.toLowerCase()}` : 'This workflow has never run.'}>
|
||||
<Box sx={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 0.4,
|
||||
height: 18, px: 0.6, borderRadius: 999,
|
||||
height: 18, px: 0.75, borderRadius: c.radius.full,
|
||||
bgcolor: status === 'failure' ? c.status.errorBg : status === 'ran_late' ? c.status.warningBg : status === 'success' ? c.status.successBg : c.bg.elevated,
|
||||
border: `1px solid ${dotColor}55`,
|
||||
flexShrink: 0,
|
||||
@@ -163,7 +163,7 @@ export function PermissionChip({ workflow }: { workflow: Workflow }) {
|
||||
color: c.text.secondary,
|
||||
bgcolor: c.bg.elevated,
|
||||
border: `1px solid ${c.border.subtle}`,
|
||||
px: 0.85, py: 0.3, borderRadius: 999,
|
||||
px: 0.75, py: 0.3, borderRadius: c.radius.full,
|
||||
}}>
|
||||
{tiers.map((t, i) => (
|
||||
<React.Fragment key={i}>
|
||||
@@ -204,7 +204,7 @@ export function ScheduleChip({ workflow }: { workflow: Workflow }) {
|
||||
color: enabled ? c.accent.primary : c.text.muted,
|
||||
bgcolor: enabled ? c.accent.primary + '14' : c.bg.elevated,
|
||||
border: `1px solid ${enabled ? c.accent.primary + '40' : c.border.subtle}`,
|
||||
px: 0.85, py: 0.3, borderRadius: 999,
|
||||
px: 0.75, py: 0.3, borderRadius: c.radius.full,
|
||||
cursor: enabled ? 'pointer' : 'default',
|
||||
'&:hover': enabled ? { bgcolor: c.accent.primary + '22' } : undefined,
|
||||
}}>
|
||||
@@ -354,7 +354,7 @@ function chipSx(c: ReturnType<typeof useClaudeTokens>) {
|
||||
color: c.text.secondary,
|
||||
bgcolor: c.bg.elevated,
|
||||
border: `1px solid ${c.border.subtle}`,
|
||||
px: 0.75, py: 0.3, borderRadius: 999,
|
||||
px: 0.75, py: 0.3, borderRadius: c.radius.full,
|
||||
} as const;
|
||||
}
|
||||
|
||||
@@ -433,10 +433,10 @@ export function StreakBadge({ runs }: { runs: WorkflowRun[] | undefined }) {
|
||||
<Box sx={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 0.3,
|
||||
fontSize: '0.72rem', fontWeight: 700,
|
||||
color: c.status.warning || '#f59e0b',
|
||||
bgcolor: (c.status.warningBg || c.bg.elevated),
|
||||
border: `1px solid ${(c.status.warning || '#f59e0b') + '60'}`,
|
||||
px: 0.7, py: 0.2, borderRadius: 999,
|
||||
color: c.status.success,
|
||||
bgcolor: c.status.successBg,
|
||||
border: `1px solid ${c.status.success + '60'}`,
|
||||
px: 0.75, py: 0.3, borderRadius: c.radius.full,
|
||||
}}>
|
||||
🔥 {n}
|
||||
</Box>
|
||||
|
||||
Reference in New Issue
Block a user