Skip to content

Commit a087e56

Browse files
committed
feat: sandbox project picker with parent project name (#4510)
Redesign the project picker to show sandbox hierarchy and remove global sandbox theming from the sidebar/navbar. - Project picker button shows parent:child format with sandbox accent color and beaker icon, chevron-down dropdown indicator - Project picker overlay lists sandboxes as nested children under their parent project with tree indentation at any depth - Remove sandbox color theming from sidebar/navbar - only the picker button shows the accent color - Unify ProjectPickerButton as single React component used by both HEEx layouts and the collaborative editor - Unify global_project_picker as shared layout component - Navigation preserves current section when switching projects - Remove dead ProjectTheme module and theme preview code - Clean up stale CSS selectors
1 parent 2f1a43e commit a087e56

30 files changed

Lines changed: 517 additions & 548 deletions

File tree

assets/css/app.css

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -443,17 +443,10 @@
443443
opacity: 1;
444444
}
445445

446-
.project-picker-text,
447-
.project-picker-chevron {
448-
display: block;
449-
}
450-
451-
#project-picker-wrapper,
452446
#user-menu-wrapper {
453447
display: block;
454448
}
455449

456-
#project-picker-trigger,
457450
#user-menu-trigger {
458451
width: 100%;
459452
}
@@ -498,9 +491,7 @@
498491
display: flex;
499492
}
500493

501-
.user-menu-chevron,
502-
.project-picker-text,
503-
.project-picker-chevron {
494+
.user-menu-chevron {
504495
display: block;
505496
}
506497

@@ -556,8 +547,6 @@
556547
gap: 0;
557548
}
558549

559-
.project-picker-text,
560-
.project-picker-chevron,
561550
.user-menu-text,
562551
.user-menu-chevron {
563552
display: none;
@@ -609,7 +598,6 @@
609598
}
610599

611600
/* Wrappers stay block, elements handle centering internally */
612-
#project-picker-wrapper,
613601
#user-menu-wrapper {
614602
display: block;
615603
}

assets/js/collaborative-editor/CollaborativeEditor.tsx

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,8 @@ import { SocketProvider } from '../react/contexts/SocketProvider';
66
import type { WithActionProps } from '../react/lib/with-props';
77

88
import { AIAssistantPanelWrapper } from './components/AIAssistantPanelWrapper';
9-
import {
10-
BreadcrumbLink,
11-
BreadcrumbProjectPicker,
12-
BreadcrumbText,
13-
} from './components/Breadcrumbs';
9+
import { BreadcrumbLink, BreadcrumbText } from './components/Breadcrumbs';
10+
import { ProjectPickerButton } from '../project-picker/ProjectPickerButton';
1411
import type { MonacoHandle } from './components/CollaborativeMonaco';
1512
import { Header } from './components/Header';
1613
import { LoadingBoundary } from './components/LoadingBoundary';
@@ -37,10 +34,12 @@ export interface CollaborativeEditorDataProps {
3734
'data-workflow-name': string;
3835
'data-project-id': string;
3936
'data-project-name'?: string;
37+
'data-project-display-name'?: string;
38+
'data-project-is-sandbox'?: string;
4039
'data-project-color'?: string;
41-
'data-project-env'?: string;
4240
'data-root-project-id'?: string;
4341
'data-root-project-name'?: string;
42+
'data-project-env'?: string;
4443
'data-is-new-workflow'?: string;
4544
'data-ai-assistant-enabled'?: string;
4645
// Initial run data from server to avoid client-side race conditions
@@ -64,6 +63,9 @@ interface BreadcrumbContentProps {
6463
workflowName: string;
6564
projectIdFallback?: string;
6665
projectNameFallback?: string;
66+
projectDisplayNameFallback?: string | null;
67+
projectIsSandboxFallback?: string;
68+
projectColorFallback?: string | null;
6769
projectEnvFallback?: string;
6870
isNewWorkflow?: boolean;
6971
aiAssistantEnabled: boolean;
@@ -74,6 +76,9 @@ function BreadcrumbContent({
7476
workflowName,
7577
projectIdFallback,
7678
projectNameFallback,
79+
projectDisplayNameFallback,
80+
projectIsSandboxFallback,
81+
projectColorFallback,
7782
projectEnvFallback,
7883
isNewWorkflow = false,
7984
aiAssistantEnabled,
@@ -91,25 +96,22 @@ function BreadcrumbContent({
9196
const projectId = projectFromStore?.id ?? projectIdFallback;
9297
const projectName = projectFromStore?.name ?? projectNameFallback;
9398
const projectEnv = projectFromStore?.env ?? projectEnvFallback;
99+
const displayName = projectDisplayNameFallback ?? projectName;
100+
const projectColor = projectColorFallback ?? null;
101+
const isSandbox = projectIsSandboxFallback === 'true';
94102
const currentWorkflowName = workflowFromStore?.name ?? workflowName;
95103

96104
const handleVersionSelect = useVersionSelect();
97105

98-
const handleProjectPickerClick = (e: React.MouseEvent) => {
99-
e.preventDefault();
100-
// Dispatch the event that the global ProjectPicker listens for
101-
document.body.dispatchEvent(new CustomEvent('open-project-picker'));
102-
};
103-
104106
const breadcrumbElements = useMemo(() => {
105107
return [
106108
// Project name as picker trigger
107-
<BreadcrumbProjectPicker
109+
<ProjectPickerButton
108110
key="project-picker"
109-
onClick={handleProjectPickerClick}
110-
>
111-
{projectName}
112-
</BreadcrumbProjectPicker>,
111+
data-label={displayName ?? ''}
112+
data-is-sandbox={isSandbox ? 'true' : 'false'}
113+
data-color={projectColor ?? undefined}
114+
/>,
113115
<BreadcrumbLink href={`/projects/${projectId}/w`} key="workflows">
114116
Workflows
115117
</BreadcrumbLink>,
@@ -142,7 +144,9 @@ function BreadcrumbContent({
142144
];
143145
}, [
144146
projectId,
145-
projectName,
147+
displayName,
148+
isSandbox,
149+
projectColor,
146150
projectEnv,
147151
currentWorkflowName,
148152
workflowId,
@@ -172,9 +176,12 @@ export const CollaborativeEditor: WithActionProps<
172176
const workflowName = props['data-workflow-name'];
173177
const projectId = props['data-project-id'];
174178
const projectName = props['data-project-name'];
175-
const projectEnv = props['data-project-env'];
179+
const projectDisplayName = props['data-project-display-name'] ?? null;
180+
const projectIsSandbox = props['data-project-is-sandbox'] ?? 'false';
181+
const projectColor = props['data-project-color'] ?? null;
176182
const rootProjectId = props['data-root-project-id'] ?? null;
177183
const rootProjectName = props['data-root-project-name'] ?? null;
184+
const projectEnv = props['data-project-env'];
178185
const isNewWorkflow = props['data-is-new-workflow'] === 'true';
179186
const aiAssistantEnabled = props['data-ai-assistant-enabled'] === 'true';
180187
const initialRunData = props['data-initial-run-data'];
@@ -220,14 +227,15 @@ export const CollaborativeEditor: WithActionProps<
220227
{...(projectName !== undefined && {
221228
projectNameFallback: projectName,
222229
})}
223-
{...(projectEnv !== undefined && {
224-
projectEnvFallback: projectEnv,
230+
{...(projectDisplayName !== null && {
231+
projectDisplayNameFallback: projectDisplayName,
225232
})}
226-
{...(rootProjectId !== null && {
227-
rootProjectIdFallback: rootProjectId,
233+
projectIsSandboxFallback={projectIsSandbox}
234+
{...(projectColor !== null && {
235+
projectColorFallback: projectColor,
228236
})}
229-
{...(rootProjectName !== null && {
230-
rootProjectNameFallback: rootProjectName,
237+
{...(projectEnv !== undefined && {
238+
projectEnvFallback: projectEnv,
231239
})}
232240
/>
233241
<div className="flex-1 min-h-0 overflow-hidden relative">

assets/js/collaborative-editor/components/Breadcrumbs.tsx

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -126,22 +126,3 @@ export function BreadcrumbText({
126126
</span>
127127
);
128128
}
129-
130-
export function BreadcrumbProjectPicker({
131-
children,
132-
onClick,
133-
}: {
134-
children: React.ReactNode;
135-
onClick?: (e: React.MouseEvent) => void;
136-
}) {
137-
return (
138-
<button
139-
type="button"
140-
onClick={onClick}
141-
className="flex items-center gap-2 px-2.5 py-1.5 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50 hover:border-gray-400 cursor-pointer transition-colors"
142-
>
143-
<span className="hero-folder h-4 w-4 text-gray-500" />
144-
{children}
145-
</button>
146-
);
147-
}

0 commit comments

Comments
 (0)