Skip to content

Commit d50f422

Browse files
committed
fix(webapp): address review feedback on favorites active state and confirm settling
Two fixes from review. Arriving on a favorited org settings or account page via its favorite left that page's side menu with nothing highlighted: the shared menu item suppressed its active state whenever a favorite owned the view, but those menus never render the favorites list that would carry the highlight instead. Yielding the active state to a favorite is now opt-in, set only by the main project menu and its dashboards list. Also, if the customize sidebar save settled with no response body (for example a session-expiry redirect), the Confirm button could spin forever; that case now surfaces the save error instead.
1 parent 96452ad commit d50f422

3 files changed

Lines changed: 24 additions & 4 deletions

File tree

apps/webapp/app/components/navigation/DashboardList.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ function DashboardChildMenuItem({
184184
to={item.path}
185185
isCollapsed={isCollapsed}
186186
disableIconHover
187+
yieldActiveToFavorite
187188
action={
188189
showDragHandle ? (
189190
<div className="sidebar-drag-handle flex h-full w-full cursor-grab items-center justify-center rounded text-text-dimmed opacity-0 group-hover/menuitem:opacity-100 hover:text-text-bright active:cursor-grabbing">

apps/webapp/app/components/navigation/SideMenu.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,12 @@ export function SideMenu({
424424
}
425425
if (!customizeSubmitSeenRef.current) return; // submit hasn't been picked up yet
426426
const data = customizationFetcher.data;
427-
if (!data) return;
427+
if (!data) {
428+
// Settled with no response body (e.g. a session-expiry redirect): fail rather than spin
429+
setCustomizeConfirmPending(false);
430+
setCustomizeError("Couldn't save your changes. Please try again.");
431+
return;
432+
}
428433
if (data.success) {
429434
// Wait out the post-save revalidation so the menu behind the dialog reflects the changes
430435
if (revalidator.state !== "idle") return;
@@ -1152,6 +1157,7 @@ export function SideMenu({
11521157
to={v3EnvironmentPath(organization, project, environment)}
11531158
data-action="tasks"
11541159
isCollapsed={isCollapsed}
1160+
yieldActiveToFavorite
11551161
/>
11561162
<SideMenuItem
11571163
name="Runs"
@@ -1161,6 +1167,7 @@ export function SideMenu({
11611167
to={v3RunsPath(organization, project, environment)}
11621168
data-action="runs"
11631169
isCollapsed={isCollapsed}
1170+
yieldActiveToFavorite
11641171
/>
11651172
<SideMenuItem
11661173
name="Sessions"
@@ -1171,6 +1178,7 @@ export function SideMenu({
11711178
data-action="sessions"
11721179
badge={<NewBadge />}
11731180
isCollapsed={isCollapsed}
1181+
yieldActiveToFavorite
11741182
/>
11751183
</div>
11761184

@@ -1334,6 +1342,7 @@ function CustomizableSideMenuSection({
13341342
badge={item.badge}
13351343
isCollapsed={isCollapsed}
13361344
action={item.action}
1345+
yieldActiveToFavorite
13371346
/>
13381347
{item.after}
13391348
</Fragment>

apps/webapp/app/components/navigation/SideMenuItem.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ export function SideMenuItem({
8585
disableIconHover = false,
8686
indented = false,
8787
isActive: isActiveOverride,
88+
yieldActiveToFavorite = false,
8889
"data-action": dataAction,
8990
}: {
9091
icon?: RenderIcon;
@@ -105,13 +106,22 @@ export function SideMenuItem({
105106
indented?: boolean;
106107
/** Overrides the default pathname === to active check (e.g. favorites match on full URL). */
107108
isActive?: boolean;
109+
/**
110+
* In menus that render the Favorites section (the main project menu), an active favorite owns
111+
* the highlight, so the plain item yields its active state to it. Menus without a favorites
112+
* list (org settings, account) must not set this: they have no favorite item to carry the
113+
* highlight instead.
114+
*/
115+
yieldActiveToFavorite?: boolean;
108116
"data-action"?: string;
109117
}) {
110118
const pathName = usePathName();
111-
// When one of the user's OWN favorites owns the current view (via its marker param), it takes
112-
// the active state; markers from shared links don't count (see useActiveFavoriteId).
119+
// Only the user's OWN favorites own a view (via the marker param); markers from shared links
120+
// don't count (see useActiveFavoriteId).
113121
const activeFavoriteId = useActiveFavoriteId();
114-
const isActive = isActiveOverride ?? (pathName === to && activeFavoriteId === undefined);
122+
const isActive =
123+
isActiveOverride ??
124+
(pathName === to && (!yieldActiveToFavorite || activeFavoriteId === undefined));
115125

116126
const isIndented = indented && !isCollapsed;
117127

0 commit comments

Comments
 (0)