fix(fleet): navigate to editor instead of dashboard on "Open in Editor" click (#289)

The Fleet View's "Open in Editor" button on container rows was navigating
to the dashboard instead of opening the stack in the editor. Fixed by
threading the stackName through the callback chain and using a pending
ref to survive the node-switch effect reset.
This commit is contained in:
Anso
2026-03-31 10:45:54 -04:00
committed by GitHub
parent 50c29b4248
commit 71ce6b3e1b
4 changed files with 23 additions and 8 deletions
+1
View File
@@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
* **fleet:** "Open in Editor" button in Fleet View's stack drill-down now correctly navigates to the stack editor instead of the dashboard. Also passes the stack name through the callback chain so the correct file is loaded.
* **scheduled-ops:** `prune_targets` field was silently dropped when creating scheduled tasks due to missing column in the INSERT statement
### Security
Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 82 KiB

+18 -4
View File
@@ -108,6 +108,7 @@ export default function EditorLayout() {
const rawBytesRef = useRef<Record<string, { lastRx: number; lastTx: number }>>({});
const [activeTab, setActiveTab] = useState<'compose' | 'env'>('compose');
const monacoEditorRef = useRef<import('monaco-editor').editor.IStandaloneCodeEditor | null>(null);
const pendingStackLoadRef = useRef<string | null>(null);
const [createDialogOpen, setCreateDialogOpen] = useState(false);
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const [newStackName, setNewStackName] = useState('');
@@ -425,6 +426,9 @@ export default function EditorLayout() {
// Also clears any stale editor/container state that belonged to the previous node.
useEffect(() => {
if (!activeNode) return;
const pendingStack = pendingStackLoadRef.current;
pendingStackLoadRef.current = null;
setSelectedFile(null);
setContent('');
setOriginalContent('');
@@ -432,7 +436,13 @@ export default function EditorLayout() {
setOriginalEnvContent('');
setContainers([]);
setIsEditing(false);
setActiveView('dashboard');
if (pendingStack) {
loadFile(pendingStack);
} else {
setActiveView('dashboard');
}
refreshStacks();
fetchImageUpdates();
}, [activeNode?.id]); // eslint-disable-line react-hooks/exhaustive-deps
@@ -1786,11 +1796,15 @@ export default function EditorLayout() {
) : activeView === 'global-observability' ? (
<GlobalObservabilityView />
) : activeView === 'fleet' ? (
<FleetView onNavigateToNode={(nodeId) => {
<FleetView onNavigateToNode={(nodeId, stackName) => {
const node = nodes.find(n => n.id === nodeId);
if (node) {
setActiveNode(node);
setActiveView('dashboard');
if (activeNode?.id === nodeId) {
loadFile(stackName);
} else {
pendingStackLoadRef.current = stackName;
setActiveNode(node);
}
}
}} />
) : activeView === 'audit-log' ? (
+4 -4
View File
@@ -189,7 +189,7 @@ function ContainerRow({ container, nodeId, onNavigate }: {
function StackSection({ stackName, nodeId, onNavigate }: {
stackName: string;
nodeId: number;
onNavigate: (nodeId: number) => void;
onNavigate: (nodeId: number, stackName: string) => void;
}) {
const [expanded, setExpanded] = useState(false);
const [containers, setContainers] = useState<StackContainer[] | null>(null);
@@ -247,7 +247,7 @@ function StackSection({ stackName, nodeId, onNavigate }: {
key={c.Id ?? containerName(c)}
container={c}
nodeId={nodeId}
onNavigate={onNavigate}
onNavigate={(nid) => onNavigate(nid, stackName)}
/>
))
) : (
@@ -259,7 +259,7 @@ function StackSection({ stackName, nodeId, onNavigate }: {
);
}
function NodeCard({ node, onNavigate }: { node: FleetNode; onNavigate: (nodeId: number) => void }) {
function NodeCard({ node, onNavigate }: { node: FleetNode; onNavigate: (nodeId: number, stackName: string) => void }) {
const { isPro } = useLicense();
const [expanded, setExpanded] = useState(false);
const [stacks, setStacks] = useState<string[] | null>(node.stacks);
@@ -431,7 +431,7 @@ function NodeCard({ node, onNavigate }: { node: FleetNode; onNavigate: (nodeId:
// --- Main Component ---
interface FleetViewProps {
onNavigateToNode: (nodeId: number) => void;
onNavigateToNode: (nodeId: number, stackName: string) => void;
}
export function FleetView({ onNavigateToNode }: FleetViewProps) {