MCPcopy
hub / github.com/coder/mux / WorkspaceMenuBar

Function WorkspaceMenuBar

src/browser/components/WorkspaceMenuBar/WorkspaceMenuBar.tsx:80–829  ·  view source on GitHub ↗
({
  workspaceId,
  projectName,
  projectPath,
  workspaceName,
  workspaceTitle,
  namedWorkspacePath,
  runtimeConfig,
  leftSidebarCollapsed,
  onToggleLeftSidebarCollapsed,
  onOpenTerminal,
})

Source from the content-addressed store, hash-verified

78} as const;
79
80export const WorkspaceMenuBar: React.FC<WorkspaceMenuBarProps> = ({
81 workspaceId,
82 projectName,
83 projectPath,
84 workspaceName,
85 workspaceTitle,
86 namedWorkspacePath,
87 runtimeConfig,
88 leftSidebarCollapsed,
89 onToggleLeftSidebarCollapsed,
90 onOpenTerminal,
91}) => {
92 const { api } = useAPI();
93 const { disableWorkspaceAgents } = useAgent();
94 const { preflightArchiveWorkspace, archiveWorkspace } = useWorkspaceActions();
95 const { workspaceMetadata } = useWorkspaceContext();
96 const workspaceHeartbeatsEnabled = useExperimentValue(EXPERIMENT_IDS.WORKSPACE_HEARTBEATS);
97 const openTerminalPopout = useOpenTerminal();
98 const openInEditor = useOpenInEditor();
99 const gitStatus = useGitStatus(workspaceId);
100 const runtimeStatus = useRuntimeStatus(workspaceId);
101 const workspaceEntry = workspaceMetadata.get(workspaceId);
102 const showMultiProjectStatus = workspaceEntry != null && isMultiProject(workspaceEntry);
103 // The workspace's metadata.projectName is the parent project (since worktrees
104 // are owned by the top-most parent). When the workspace is scoped to a
105 // sub-project we surface the hierarchy as "parent / child" so the menu bar
106 // alone reveals the sub-project context.
107 const { userProjects } = useProjectContext();
108 const subProjectPath = workspaceEntry?.subProjectPath;
109 const projectLabel =
110 subProjectPath && userProjects.has(subProjectPath)
111 ? formatProjectHierarchyLabel(subProjectPath, userProjects)
112 : projectName;
113 const runtimeStatusStore = useRuntimeStatusStoreRaw();
114 const { canInterrupt, isStarting, awaitingUserQuestion, loadedSkills, skillLoadErrors } =
115 useWorkspaceSidebarState(workspaceId);
116 const isWorking = (canInterrupt || isStarting) && !awaitingUserQuestion;
117 const { startSequence: startTutorial } = useTutorial();
118 const [editorError, setEditorError] = useState<string | null>(null);
119 const [debugLlmRequestOpen, setDebugLlmRequestOpen] = useState(false);
120 const [mcpModalOpen, setMcpModalOpen] = useState(false);
121 const [heartbeatModalOpen, setHeartbeatModalOpen] = useState(false);
122 const [availableSkills, setAvailableSkills] = useState<AgentSkillDescriptor[]>([]);
123 const [invalidSkills, setInvalidSkills] = useState<AgentSkillIssue[]>([]);
124 const isSkillsMountedRef = useRef(true);
125 const moreActionsButtonRef = useRef<HTMLButtonElement | null>(null);
126
127 const skillsRequestIdRef = useRef(0);
128 const [moreMenuOpen, setMoreMenuOpen] = useState(false);
129 const [archiveConfirmOpen, setArchiveConfirmOpen] = useState(false);
130 // Untracked paths from archive preflight that the user needs to acknowledge.
131 // When set, the confirmation dialog warns about permanent file deletion.
132 const [archiveUntrackedPaths, setArchiveUntrackedPaths] = useState<string[] | null>(null);
133 // Whether the confirmation includes an active-stream interruption warning.
134 const [archiveConfirmIsStreaming, setArchiveConfirmIsStreaming] = useState(false);
135 const [isArchiving, setIsArchiving] = useState(false);
136 const archiveError = usePopoverError();
137 const forkError = usePopoverError();

Callers

nothing calls this directly

Calls 15

useAPIFunction · 0.90
useAgentFunction · 0.90
useWorkspaceActionsFunction · 0.90
useWorkspaceContextFunction · 0.90
useOpenTerminalFunction · 0.90
useOpenInEditorFunction · 0.90
useGitStatusFunction · 0.90
useRuntimeStatusFunction · 0.90
isMultiProjectFunction · 0.90
useProjectContextFunction · 0.90
useRuntimeStatusStoreRawFunction · 0.90

Tested by

no test coverage detected