feat(FN-3000): harden research lifecycle with idempotent cancel/retry and S
This merge hardens the research feature across the stack with idempotent cancel/retry logic and SSE support for real-time updates in `research-orchestrator` and `sse.ts`, while also applying UX improvements to `PlanningModeModal` and `ResearchTaskActionModal`. The core `research-store` received sign Fusion-Task-Id: FN-3000
This commit is contained in:
@@ -20,8 +20,6 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--space-xs);
|
gap: var(--space-xs);
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
font-size: 0.75rem;
|
|
||||||
letter-spacing: 0.03em;
|
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,4 +32,22 @@
|
|||||||
.research-task-action-modal {
|
.research-task-action-modal {
|
||||||
width: min(100%, calc(100vw - (var(--space-md) * 2)));
|
width: min(100%, calc(100vw - (var(--space-md) * 2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.research-task-action-modal__body {
|
||||||
|
gap: var(--space-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.research-task-action-modal__preview {
|
||||||
|
padding: var(--space-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.research-task-action-modal .modal-actions {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: var(--space-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.research-task-action-modal .modal-actions .btn {
|
||||||
|
min-height: calc(var(--space-lg) * 2 + var(--space-xs));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,10 +92,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.research-view__history-item {
|
.research-view__history-item {
|
||||||
border: var(--btn-border-width) solid var(--border);
|
|
||||||
border-radius: var(--radius-sm);
|
|
||||||
background: var(--surface);
|
|
||||||
color: var(--text);
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: var(--space-sm);
|
padding: var(--space-sm);
|
||||||
min-height: calc(var(--space-lg) * 2 + var(--space-xs));
|
min-height: calc(var(--space-lg) * 2 + var(--space-xs));
|
||||||
@@ -104,22 +100,6 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: var(--space-xs);
|
gap: var(--space-xs);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: border-color var(--transition-fast), box-shadow var(--transition-fast), background-color var(--transition-fast), transform var(--transition-fast);
|
|
||||||
}
|
|
||||||
|
|
||||||
.research-view__history-item:hover {
|
|
||||||
background: var(--card-hover);
|
|
||||||
border-color: var(--todo);
|
|
||||||
}
|
|
||||||
|
|
||||||
.research-view__history-item:focus-visible {
|
|
||||||
outline: none;
|
|
||||||
border-color: var(--todo);
|
|
||||||
box-shadow: var(--focus-ring-strong);
|
|
||||||
}
|
|
||||||
|
|
||||||
.research-view__history-item:active {
|
|
||||||
transform: scale(0.97);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.research-view__history-item--active {
|
.research-view__history-item--active {
|
||||||
@@ -208,12 +188,10 @@
|
|||||||
.research-view__stat-label {
|
.research-view__stat-label {
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: 0.6875rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.research-view__stat-value {
|
.research-view__stat-value {
|
||||||
font-family: var(--font-mono);
|
font-family: var(--font-mono);
|
||||||
font-size: 0.8125rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.research-view__state--error {
|
.research-view__state--error {
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ export function ResearchView({ projectId, addToast, onOpenSettings, readinessVer
|
|||||||
<button
|
<button
|
||||||
key={run.id}
|
key={run.id}
|
||||||
type="button"
|
type="button"
|
||||||
className={`research-view__history-item${selectedRunId === run.id ? " research-view__history-item--active" : ""}`}
|
className={`research-view__history-item card${selectedRunId === run.id ? " research-view__history-item--active" : ""}`}
|
||||||
onClick={() => setSelectedRunId(run.id)}
|
onClick={() => setSelectedRunId(run.id)}
|
||||||
>
|
>
|
||||||
<span className="card-id">{run.id}</span>
|
<span className="card-id">{run.id}</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user