@@ -153,17 +132,13 @@ export default function ControlPlaneView() {
- {t('ControlPlaneView.landscapersTitle')}
-
- }
+ header={{t('McpPage.landscapersTitle')}}
noAnimation
>
@@ -172,15 +147,13 @@ export default function ControlPlaneView() {
{t('ControlPlaneView.gitOpsTitle')}
- }
+ header={{t('McpPage.gitOpsTitle')}}
noAnimation
>
diff --git a/src/spaces/onboarding/auth/AuthContextOnboarding.tsx b/src/spaces/onboarding/auth/AuthContextOnboarding.tsx
index 9091014a..9f05eb07 100644
--- a/src/spaces/onboarding/auth/AuthContextOnboarding.tsx
+++ b/src/spaces/onboarding/auth/AuthContextOnboarding.tsx
@@ -12,9 +12,7 @@ interface AuthContextOnboardingType {
logout: () => Promise;
}
-const AuthContextOnboarding = createContext(
- null,
-);
+const AuthContextOnboarding = createContext(null);
export function AuthProviderOnboarding({ children }: { children: ReactNode }) {
const [isAuthenticated, setIsAuthenticated] = useState(false);
@@ -40,22 +38,16 @@ export function AuthProviderOnboarding({ children }: { children: ReactNode }) {
} catch (_) {
/* safe to ignore */
}
- throw new Error(
- errorBody?.message ||
- `Authentication check failed with status: ${response.status}`,
- );
+ throw new Error(errorBody?.message || `Authentication check failed with status: ${response.status}`);
}
const body = await response.json();
const validationResult = MeResponseSchema.safeParse(body);
if (!validationResult.success) {
- throw new Error(
- `Auth API response validation failed: ${validationResult.error.flatten()}`,
- );
+ throw new Error(`Auth API response validation failed: ${validationResult.error.flatten()}`);
}
- const { isAuthenticated: apiIsAuthenticated, user: apiUser } =
- validationResult.data;
+ const { isAuthenticated: apiIsAuthenticated, user: apiUser } = validationResult.data;
setUser(apiUser);
setIsAuthenticated(apiIsAuthenticated);
@@ -75,10 +67,10 @@ export function AuthProviderOnboarding({ children }: { children: ReactNode }) {
const login = () => {
sessionStorage.setItem(AUTH_FLOW_SESSION_KEY, 'onboarding');
-
- window.location.replace(
- `/api/auth/onboarding/login?redirectTo=${encodeURIComponent(window.location.hash)}`,
- );
+ // The query parameters and hash fragments need to be preserved, e.g. /?sap-theme=sap_horizon#/mcp/projects
+ const { search, hash } = window.location;
+ const redirectTo = (search ? `/${search}` : '') + hash;
+ window.location.replace(`/api/auth/onboarding/login?redirectTo=${encodeURIComponent(redirectTo)}`);
};
const logout = async () => {
@@ -94,9 +86,7 @@ export function AuthProviderOnboarding({ children }: { children: ReactNode }) {
} catch (_) {
/* safe to ignore */
}
- throw new Error(
- errorBody?.message || `Logout failed with status: ${response.status}`,
- );
+ throw new Error(errorBody?.message || `Logout failed with status: ${response.status}`);
}
await refreshAuthStatus();
@@ -106,9 +96,7 @@ export function AuthProviderOnboarding({ children }: { children: ReactNode }) {
};
return (
-
+
{children}
);
@@ -117,9 +105,7 @@ export function AuthProviderOnboarding({ children }: { children: ReactNode }) {
export const useAuthOnboarding = () => {
const context = use(AuthContextOnboarding);
if (!context) {
- throw new Error(
- 'useAuthOnboarding must be used within an AuthProviderOnboarding.',
- );
+ throw new Error('useAuthOnboarding must be used within an AuthProviderOnboarding.');
}
return context;
};
diff --git a/src/spaces/onboarding/pages/ProjectPage.tsx b/src/spaces/onboarding/pages/ProjectPage.tsx
new file mode 100644
index 00000000..22b7cac6
--- /dev/null
+++ b/src/spaces/onboarding/pages/ProjectPage.tsx
@@ -0,0 +1,65 @@
+import { ObjectPage, ObjectPageTitle, Title } from '@ui5/webcomponents-react';
+import ProjectChooser from '../../../components/Projects/ProjectChooser.tsx';
+import { useParams } from 'react-router-dom';
+import ControlPlaneListAllWorkspaces from '../../../components/ControlPlanes/List/ControlPlaneListAllWorkspaces.tsx';
+import IntelligentBreadcrumbs from '../../../components/Core/IntelligentBreadcrumbs.tsx';
+import { ControlPlaneListToolbar } from '../../../components/ControlPlanes/List/ControlPlaneListToolbar.tsx';
+import { Trans, useTranslation } from 'react-i18next';
+import useApiResource from '../../../lib/api/useApiResource.ts';
+import { ListWorkspaces } from '../../../lib/api/types/crate/listWorkspaces.ts';
+import Loading from '../../../components/Shared/Loading.tsx';
+import { isNotFoundError } from '../../../lib/api/error.ts';
+import { NotFoundBanner } from '../../../components/Ui/NotFoundBanner/NotFoundBanner.tsx';
+import IllustratedError from '../../../components/Shared/IllustratedError.tsx';
+
+export default function ProjectPage() {
+ const { projectName } = useParams();
+ const { data: workspaces, error, isLoading } = useApiResource(ListWorkspaces(projectName));
+ const { t } = useTranslation();
+
+ if (isLoading) {
+ return ;
+ }
+
+ if (isNotFoundError(error)) {
+ return ;
+ }
+
+ if (error || !workspaces || !projectName) {
+ return ;
+ }
+
+ return (
+ <>
+
+ }} />
+
+ }
+ subHeader={
+
+
{t('ProjectsPage.projectHeader')}
+
+
+ }
+ breadcrumbs={}
+ actionsBar={}
+ />
+ }
+ //TODO: project chooser should be part of the breadcrumb section if possible?
+ >
+
+
+ >
+ );
+}
diff --git a/src/views/ControlPlanes/ControlPlaneListView.tsx b/src/views/ControlPlanes/ControlPlaneListView.tsx
deleted file mode 100644
index 4fe4ea43..00000000
--- a/src/views/ControlPlanes/ControlPlaneListView.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import { ObjectPage, ObjectPageTitle, Title } from '@ui5/webcomponents-react';
-import ProjectChooser from '../../components/Projects/ProjectChooser.tsx';
-import { useParams } from 'react-router-dom';
-import ControlPlaneListAllWorkspaces from '../../components/ControlPlanes/List/ControlPlaneListAllWorkspaces.tsx';
-import IntelligentBreadcrumbs from '../../components/Core/IntelligentBreadcrumbs.tsx';
-import { ControlPlaneListToolbar } from '../../components/ControlPlanes/List/ControlPlaneListToolbar.tsx';
-import { Trans, useTranslation } from 'react-i18next';
-
-export default function ControlPlaneListView() {
- const { projectName } = useParams();
- const { t } = useTranslation();
-
- return (
- <>
-
- }}
- />
-
- }
- subHeader={
-
-
- {t('ControlPlaneListView.projectHeader')}
-
-
-
- }
- breadcrumbs={}
- actionsBar={
-
- }
- />
- }
- //TODO: project chooser should be part of the breadcrumb section if possible?
- >
-
-
- >
- );
-}