diff --git a/frontend/src/components/layouts/main-sidebar.test.tsx b/frontend/src/components/layouts/main-sidebar.test.tsx
new file mode 100644
index 00000000..a9ea1f78
--- /dev/null
+++ b/frontend/src/components/layouts/main-sidebar.test.tsx
@@ -0,0 +1,62 @@
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { MemoryRouter, Route, Routes, useLocation } from 'react-router-dom';
+import { describe, expect, it, vi } from 'vitest';
+
+vi.mock('@/providers/user-provider', () => ({
+ useUser: () => ({ authInfo: { user: { mail: 'me@example.com', name: 'Test User', type: 'local' } }, logout: vi.fn() }),
+}));
+vi.mock('@/hooks/use-theme', () => ({ useTheme: () => ({ setTheme: vi.fn(), theme: 'system' }) }));
+vi.mock('@/providers/favorites-provider', () => ({
+ useFavorites: () => ({ addFavoriteFlow: vi.fn(), favoriteFlowIds: [], removeFavoriteFlow: vi.fn() }),
+}));
+vi.mock('@/providers/sidebar-flows-provider', () => ({ useSidebarFlows: () => ({ flows: [] }) }));
+vi.mock('@/features/resources/use-resources-upload', () => ({
+ useResourcesUpload: () => ({ fileInputKey: 'k', fileInputProps: {}, openFilePicker: vi.fn() }),
+}));
+
+import { SidebarProvider } from '@/components/ui/sidebar';
+
+import { MainSidebar } from './main-sidebar';
+
+function FromProbe() {
+ const location = useLocation();
+
+ return {(location.state as null | { from?: string })?.from ?? 'none'};
+}
+
+function renderSidebar() {
+ return render(
+
+
+
+
+
+ dashboard} path="/dashboard" />
+ } path="/settings" />
+ } path="/settings/account" />
+
+ ,
+ );
+}
+
+describe('MainSidebar settings entry points', () => {
+ it('the Settings link carries the current path as the return origin', async () => {
+ const user = userEvent.setup();
+ renderSidebar();
+
+ await user.click(screen.getByRole('link', { name: 'Settings' }));
+
+ expect(screen.getByTestId('from')).toHaveTextContent('/dashboard');
+ });
+
+ it('the Profile menu item carries the current path as the return origin', async () => {
+ const user = userEvent.setup();
+ renderSidebar();
+
+ await user.click(screen.getByRole('button', { name: /Test User/ }));
+ await user.click(screen.getByRole('menuitem', { name: 'Profile' }));
+
+ expect(screen.getByTestId('from')).toHaveTextContent('/dashboard');
+ });
+});
diff --git a/frontend/src/components/layouts/main-sidebar.tsx b/frontend/src/components/layouts/main-sidebar.tsx
index 1fb0c0d2..10c7bcf8 100644
--- a/frontend/src/components/layouts/main-sidebar.tsx
+++ b/frontend/src/components/layouts/main-sidebar.tsx
@@ -18,7 +18,7 @@ import {
UserIcon,
} from 'lucide-react';
import { useMemo } from 'react';
-import { Link, useMatch, useParams } from 'react-router-dom';
+import { Link, useLocation, useMatch, useParams } from 'react-router-dom';
import type { Flow } from '@/providers/sidebar-flows-provider';
import type { Theme } from '@/providers/theme-provider';
@@ -61,6 +61,7 @@ interface FlowMenuItemProps {
}
export function MainSidebar() {
+ const location = useLocation();
const isDashboardActive = useMatch('/dashboard');
const isFlowsActive = useMatch('/flows/*');
const isTemplatesActive = useMatch('/templates/*');
@@ -268,7 +269,10 @@ export function MainSidebar() {
asChild
isActive={!!isSettingsActive}
>
-
+
Settings
@@ -354,7 +358,10 @@ export function MainSidebar() {
-
+
Profile
diff --git a/frontend/src/components/layouts/settings-layout.test.tsx b/frontend/src/components/layouts/settings-layout.test.tsx
new file mode 100644
index 00000000..87736f7a
--- /dev/null
+++ b/frontend/src/components/layouts/settings-layout.test.tsx
@@ -0,0 +1,44 @@
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { MemoryRouter, Route, Routes } from 'react-router-dom';
+import { describe, expect, it } from 'vitest';
+
+import SettingsLayout from './settings-layout';
+
+function renderAt(entry: { pathname: string; state?: unknown }) {
+ return render(
+
+
+ } path="/settings">
+ account} path="account" />
+ providers} path="providers" />
+
+
+ ,
+ );
+}
+
+const backToApp = () => screen.getByRole('link', { name: /Back to App/ });
+
+describe('SettingsLayout "Back to App"', () => {
+ it('returns to the page the user came from', () => {
+ renderAt({ pathname: '/settings/account', state: { from: '/dashboard' } });
+
+ expect(backToApp()).toHaveAttribute('href', '/dashboard');
+ });
+
+ it('falls back to /flows when there is no origin', () => {
+ renderAt({ pathname: '/settings/account' });
+
+ expect(backToApp()).toHaveAttribute('href', '/flows');
+ });
+
+ it('keeps the origin after switching settings sub-tabs (which drop location.state)', async () => {
+ const user = userEvent.setup();
+ renderAt({ pathname: '/settings/account', state: { from: '/dashboard' } });
+
+ await user.click(screen.getByRole('link', { name: 'Providers' }));
+
+ expect(backToApp()).toHaveAttribute('href', '/dashboard');
+ });
+});
diff --git a/frontend/src/components/layouts/settings-layout.tsx b/frontend/src/components/layouts/settings-layout.tsx
index 28a34274..ef5f7715 100644
--- a/frontend/src/components/layouts/settings-layout.tsx
+++ b/frontend/src/components/layouts/settings-layout.tsx
@@ -1,5 +1,5 @@
import { ArrowLeft, FileText, Key, Plug, Settings as SettingsIcon, User } from 'lucide-react';
-import { useMemo } from 'react';
+import { useMemo, useState } from 'react';
import { NavLink, Outlet, useLocation, useParams } from 'react-router-dom';
import { Separator } from '@/components/ui/separator';
@@ -17,6 +17,7 @@ import {
SidebarProvider,
SidebarTrigger,
} from '@/components/ui/sidebar';
+import { getSafeReturnUrl } from '@/lib/utils/auth';
export interface MenuItem {
icon?: React.ReactNode;
@@ -97,10 +98,15 @@ function SettingsHeader() {
}
function SettingsLayout() {
+ const location = useLocation();
+ const [returnUrl] = useState(() =>
+ getSafeReturnUrl((location.state as null | { from?: string })?.from ?? null, '/flows'),
+ );
+
return (
-
+
@@ -112,7 +118,7 @@ function SettingsLayout() {
);
}
-function SettingsSidebar() {
+function SettingsSidebar({ returnUrl }: { returnUrl: string }) {
return (
@@ -143,7 +149,7 @@ function SettingsSidebar() {
-
+
Back to App