Skip to content

Commit 8c8ff7f

Browse files
authored
Merge branch 'main' into ft/logo
2 parents 16912d5 + e3eba14 commit 8c8ff7f

File tree

13 files changed

+780
-749
lines changed

13 files changed

+780
-749
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ RUN npm prune --omit=dev
1818

1919

2020
# PRODUCTION STAGE
21-
FROM gcr.io/distroless/nodejs24-debian12@sha256:e6af293a96996c2a6d1e8a440600518ec614571a91356a38c55f316ff1ee9924 AS production
21+
FROM gcr.io/distroless/nodejs24-debian12@sha256:b8be532fe81829b3803c832989cba7f42de62b2fbc8c7599cae30f378882ea12 AS production
2222
WORKDIR /usr/src/app
2323

2424
# Copy built files

package-lock.json

Lines changed: 546 additions & 589 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,20 @@
3434
"@fastify/static": "8.2.0",
3535
"@fastify/vite": "8.2.0",
3636
"@hookform/resolvers": "5.2.2",
37-
"@sentry/node": "10.11.0",
38-
"@sentry/react": "10.11.0",
37+
"@sentry/node": "10.14.0",
38+
"@sentry/react": "10.14.0",
3939
"@sentry/vite-plugin": "4.3.0",
4040
"@ui5/webcomponents": "2.14.0",
4141
"@ui5/webcomponents-fiori": "2.14.0",
4242
"@ui5/webcomponents-icons": "2.14.0",
4343
"@ui5/webcomponents-react": "2.14.1",
4444
"@ui5/webcomponents-react-charts": "2.14.1",
45-
"@xyflow/react": "12.8.4",
45+
"@xyflow/react": "12.8.5",
4646
"clsx": "2.1.1",
4747
"dagre": "0.8.5",
4848
"diff": "^8.0.2",
4949
"dotenv": "17.2.2",
50-
"fastify": "5.6.0",
50+
"fastify": "5.6.1",
5151
"fastify-plugin": "5.0.1",
5252
"graphql": "16.11.0",
5353
"graphql-config": "5.1.5",
@@ -57,29 +57,29 @@
5757
"react": "19.1.1",
5858
"react-dom": "19.1.1",
5959
"react-error-boundary": "6.0.0",
60-
"react-hook-form": "7.62.0",
60+
"react-hook-form": "7.63.0",
6161
"react-i18next": "15.7.3",
6262
"react-router-dom": "7.9.1",
6363
"react-syntax-highlighter": "15.6.6",
6464
"react-time-ago": "7.3.5",
6565
"swr": "2.3.6",
6666
"yaml": "2.8.1",
67-
"zod": "4.1.8"
67+
"zod": "4.1.11"
6868
},
6969
"devDependencies": {
7070
"@eslint/eslintrc": "3.3.1",
71-
"@eslint/js": "9.35.0",
71+
"@eslint/js": "9.36.0",
7272
"@graphql-codegen/cli": "6.0.0",
73-
"@graphql-codegen/client-preset": "5.0.0",
73+
"@graphql-codegen/client-preset": "5.0.1",
7474
"@types/dagre": "0.7.53",
7575
"@types/js-yaml": "4.0.9",
76-
"@types/node": "22.18.3",
76+
"@types/node": "22.18.6",
7777
"@types/react": "19.1.13",
7878
"@types/react-dom": "19.1.9",
7979
"@types/react-syntax-highlighter": "15.5.13",
8080
"@ui5/webcomponents-cypress-commands": "2.14.1",
81-
"@vitejs/plugin-react": "5.0.2",
82-
"@vitest/eslint-plugin": "1.3.9",
81+
"@vitejs/plugin-react": "5.0.3",
82+
"@vitest/eslint-plugin": "1.3.12",
8383
"cypress": "15.2.0",
8484
"eslint-config-prettier": "10.1.8",
8585
"eslint-import-resolver-typescript": "4.4.4",
@@ -95,8 +95,8 @@
9595
"prettier": "3.6.2",
9696
"tsx": "4.20.5",
9797
"typescript": "5.9.2",
98-
"typescript-eslint": "8.43.0",
99-
"vite": "7.1.5",
98+
"typescript-eslint": "8.44.1",
99+
"vite": "7.1.7",
100100
"vitest": "3.2.4"
101101
}
102102
}

public/locales/en.json

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"signInButton": "Sign In"
77
},
88
"Entities": {
9-
"ManagedControlPlane": "Managed Control Plane",
9+
"ManagedControlPlane": "ManagedControlPlane",
1010
"Project": "Project",
1111
"Workspace": "Workspace",
1212
"Users": "Users",
@@ -104,11 +104,8 @@
104104
"subtitleMessage": "Sorry, we couldn’t find what you are looking for.<br />The link may be incorrect or the {{entityType}} might have been removed.",
105105
"navigateHome": "Back to Homepage"
106106
},
107-
"IntelligentBreadcrumbs": {
108-
"homeLabel": "Home",
109-
"projects": "Projects",
110-
"workspaces": "Workspaces",
111-
"mcps": "MCPs"
107+
"PathAwareBreadcrumbs": {
108+
"projectsLabel": "Projects"
112109
},
113110
"MCPContext": {
114111
"errorMessage": "An unknown error occurred"

src/Routes.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const Routes = {
2+
Home: '/',
3+
Project: '/mcp/projects/:projectName',
4+
Mcp: '/mcp/projects/:projectName/workspaces/:workspaceName/mcps/:controlPlaneName',
5+
} as const;
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { Button, FlexBox, FlexBoxAlignItems, Menu, MenuItem } from '@ui5/webcomponents-react';
2+
3+
import { useTranslation } from 'react-i18next';
4+
import { FeedbackButton } from './FeedbackButton.tsx';
5+
import { BetaButton } from './BetaButton.tsx';
6+
import { useRef, useState } from 'react';
7+
import { useAuthOnboarding } from '../../spaces/onboarding/auth/AuthContextOnboarding.tsx';
8+
import { SearchParamToggleVisibility } from '../Helper/FeatureToggleExistance.tsx';
9+
import { PathAwareBreadcrumbs } from './PathAwareBreadcrumbs/PathAwareBreadcrumbs.tsx';
10+
11+
export function BreadcrumbFeedbackHeader() {
12+
return (
13+
<FlexBox alignItems={FlexBoxAlignItems.Center}>
14+
<PathAwareBreadcrumbs />
15+
<BetaButton />
16+
<FeedbackButton />
17+
<SearchParamToggleVisibility
18+
shouldBeVisible={(params) => {
19+
if (params === undefined) return false;
20+
if (params.get('showHeaderBar') === null) return false;
21+
return params?.get('showHeaderBar') === 'false';
22+
}}
23+
>
24+
<LogoutMenu />
25+
</SearchParamToggleVisibility>
26+
</FlexBox>
27+
);
28+
}
29+
30+
function LogoutMenu() {
31+
const auth = useAuthOnboarding();
32+
const { t } = useTranslation();
33+
34+
const buttonRef = useRef(null);
35+
const [menuIsOpen, setMenuIsOpen] = useState(false);
36+
return (
37+
<>
38+
<Button
39+
ref={buttonRef}
40+
icon="menu2"
41+
onClick={() => {
42+
setMenuIsOpen(true);
43+
}}
44+
/>
45+
<Menu
46+
opener={buttonRef.current}
47+
open={menuIsOpen}
48+
onClose={() => {
49+
setMenuIsOpen(false);
50+
}}
51+
>
52+
<MenuItem
53+
icon="log"
54+
text={t('ShellBar.signOutButton')}
55+
onClick={async () => {
56+
setMenuIsOpen(false);
57+
await auth.logout();
58+
}}
59+
/>
60+
</Menu>
61+
</>
62+
);
63+
}

src/components/Core/IntelligentBreadcrumbs.tsx

Lines changed: 0 additions & 128 deletions
This file was deleted.

src/components/Core/LandscapeLabel.tsx

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { PathAwareBreadcrumbs } from './PathAwareBreadcrumbs';
2+
import { useNavigate, useParams } from 'react-router-dom';
3+
4+
describe('PathAwareBreadcrumbs', () => {
5+
let lastNavigatedPath = '';
6+
const fakeUseNavigate = (() => (path: string) => {
7+
lastNavigatedPath = path;
8+
}) as typeof useNavigate;
9+
const fakeUseParams = (() => ({
10+
projectName: 'my-project',
11+
workspaceName: 'my-workspace',
12+
controlPlaneName: 'my-control-plane',
13+
})) as typeof useParams;
14+
15+
beforeEach(() => {
16+
lastNavigatedPath = '';
17+
});
18+
19+
it('renders breadcrumbs for all path parameters', () => {
20+
cy.mount(<PathAwareBreadcrumbs useNavigate={fakeUseNavigate} useParams={fakeUseParams} />);
21+
22+
// Check that all breadcrumbs are rendered
23+
cy.get("[data-testid='breadcrumb-item']").should('have.length', 3);
24+
cy.get("[data-testid='breadcrumb-item']").eq(0).should('contain', '[LOCAL] Projects');
25+
cy.get("[data-testid='breadcrumb-item']").eq(1).should('contain', 'my-project');
26+
cy.get("[data-testid='breadcrumb-item']").eq(2).should('contain', 'my-workspace');
27+
});
28+
29+
it('navigates when clicking breadcrumbs for all path parameters', () => {
30+
cy.mount(<PathAwareBreadcrumbs useNavigate={fakeUseNavigate} useParams={fakeUseParams} />);
31+
32+
// Navigate to '/'
33+
cy.contains('[LOCAL] Projects').click();
34+
cy.wrap(null).then(() => {
35+
expect(lastNavigatedPath).to.equal('/');
36+
});
37+
38+
// Click on 'my-project' > Navigate to 'my-project'
39+
cy.contains('my-project').click();
40+
cy.wrap(null).then(() => {
41+
expect(lastNavigatedPath).to.equal('/mcp/projects/my-project');
42+
});
43+
44+
// Click on 'my-workspace' > Navigate to 'my-project' since workspaces don’t expose a direct path
45+
cy.contains('my-workspace').click();
46+
cy.wrap(null).then(() => {
47+
expect(lastNavigatedPath).to.equal('/mcp/projects/my-project');
48+
});
49+
});
50+
51+
it('renders only home breadcrumb when there are no path parameters', () => {
52+
const fakeUseParams = (() => ({})) as typeof useParams;
53+
54+
cy.mount(<PathAwareBreadcrumbs useNavigate={fakeUseNavigate} useParams={fakeUseParams} />);
55+
56+
cy.get("[data-testid='breadcrumb-item']").should('have.length', 1);
57+
});
58+
59+
it('handles partial route parameters', () => {
60+
const fakeUseParams = (() => ({
61+
projectName: 'my-project',
62+
// No workspaceName
63+
// No controlPlaneName
64+
})) as typeof useParams;
65+
66+
cy.mount(<PathAwareBreadcrumbs useNavigate={fakeUseNavigate} useParams={fakeUseParams} />);
67+
68+
// Should show 3 breadcrumbs
69+
cy.get("[data-testid='breadcrumb-item']").should('have.length', 2);
70+
71+
// Verify data-target attributes
72+
cy.get("[data-testid='breadcrumb-item']").eq(0).should('contain', '[LOCAL] Projects');
73+
cy.get("[data-testid='breadcrumb-item']").eq(1).should('contain', 'my-project');
74+
});
75+
});

0 commit comments

Comments
 (0)