Skip to content

Commit 37140a5

Browse files
committed
fix
1 parent c88c362 commit 37140a5

File tree

14 files changed

+1036
-1135
lines changed

14 files changed

+1036
-1135
lines changed

package-lock.json

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

package.json

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,23 @@
3434
"@fastify/static": "8.2.0",
3535
"@fastify/vite": "8.2.0",
3636
"@hookform/resolvers": "5.2.1",
37-
"@sentry/node": "10.8.0",
38-
"@sentry/react": "10.8.0",
39-
"@sentry/vite-plugin": "4.2.0",
40-
"@ui5/webcomponents": "2.13.3",
41-
"@ui5/webcomponents-fiori": "2.13.3",
42-
"@ui5/webcomponents-icons": "2.13.3",
43-
"@ui5/webcomponents-react": "2.13.2",
44-
"@ui5/webcomponents-react-charts": "2.13.2",
37+
"@sentry/node": "10.10.0",
38+
"@sentry/react": "10.10.0",
39+
"@sentry/vite-plugin": "4.3.0",
40+
"@ui5/webcomponents": "2.14.0",
41+
"@ui5/webcomponents-fiori": "2.14.0",
42+
"@ui5/webcomponents-icons": "2.14.0",
43+
"@ui5/webcomponents-react": "2.14.0",
44+
"@ui5/webcomponents-react-charts": "2.14.0",
4545
"@xyflow/react": "12.8.4",
4646
"clsx": "2.1.1",
4747
"dagre": "0.8.5",
48-
"dotenv": "17.2.1",
49-
"fastify": "5.5.0",
48+
"dotenv": "17.2.2",
49+
"fastify": "5.6.0",
5050
"fastify-plugin": "5.0.1",
5151
"graphql": "16.11.0",
5252
"graphql-config": "5.1.5",
53-
"i18next": "25.4.2",
53+
"i18next": "25.5.2",
5454
"javascript-time-ago": "2.5.11",
5555
"js-yaml": "4.1.0",
5656
"react": "19.1.1",
@@ -67,18 +67,18 @@
6767
},
6868
"devDependencies": {
6969
"@eslint/eslintrc": "3.3.1",
70-
"@eslint/js": "9.34.0",
70+
"@eslint/js": "9.35.0",
7171
"@graphql-codegen/cli": "5.0.7",
7272
"@graphql-codegen/client-preset": "4.8.3",
7373
"@types/dagre": "0.7.53",
7474
"@types/js-yaml": "4.0.9",
75-
"@types/node": "22.18.0",
75+
"@types/node": "22.18.1",
7676
"@types/react": "19.1.12",
7777
"@types/react-dom": "19.1.9",
7878
"@types/react-syntax-highlighter": "15.5.13",
79-
"@ui5/webcomponents-cypress-commands": "2.13.2",
79+
"@ui5/webcomponents-cypress-commands": "2.14.0",
8080
"@vitejs/plugin-react": "5.0.2",
81-
"@vitest/eslint-plugin": "1.3.5",
81+
"@vitest/eslint-plugin": "1.3.9",
8282
"cypress": "15.1.0",
8383
"eslint-config-prettier": "10.1.8",
8484
"eslint-import-resolver-typescript": "4.4.4",
@@ -94,8 +94,8 @@
9494
"prettier": "3.6.2",
9595
"tsx": "4.20.5",
9696
"typescript": "5.9.2",
97-
"typescript-eslint": "8.41.0",
98-
"vite": "6.3.5",
97+
"typescript-eslint": "8.42.0",
98+
"vite": "7.1.5",
9999
"vitest": "3.2.4"
100100
}
101101
}

public/locales/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@
9393
"menuDownload": "Download",
9494
"menuCopy": "Copy to clipboard"
9595
},
96+
"ComponentsSelection": {
97+
"chooseVersion": "Please select version"
98+
},
9699
"IllustratedBanner": {
97100
"titleMessage": "No Managed Control Planes found",
98101
"subtitleMessage": "Get started by creating your first Managed Control Plane.",

src/components/ComponentsSelection/ComponentsSelection.tsx

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,19 @@ import { Infobox } from '../Ui/Infobox/Infobox.tsx';
2222
import { useTranslation } from 'react-i18next';
2323
import { ComponentsListItem } from '../../lib/api/types/crate/createManagedControlPlane.ts';
2424
import { getSelectedComponents } from './ComponentsSelectionContainer.tsx';
25+
import IllustratedError from '../Shared/IllustratedError.tsx';
2526

2627
export interface ComponentsSelectionProps {
2728
componentsList: ComponentsListItem[];
2829
setComponentsList: (components: ComponentsListItem[]) => void;
30+
templateDefaultsError?: string;
2931
}
3032

31-
export const ComponentsSelection: React.FC<ComponentsSelectionProps> = ({ componentsList, setComponentsList }) => {
33+
export const ComponentsSelection: React.FC<ComponentsSelectionProps> = ({
34+
componentsList,
35+
setComponentsList,
36+
templateDefaultsError,
37+
}) => {
3238
const [searchTerm, setSearchTerm] = useState('');
3339
const { t } = useTranslation();
3440

@@ -132,8 +138,19 @@ export const ComponentsSelection: React.FC<ComponentsSelectionProps> = ({ compon
132138
value={component.selectedVersion}
133139
disabled={!component.isSelected || providerDisabled}
134140
aria-label={`${component.name} version`}
141+
valueState={component.isSelected && !component.selectedVersion ? 'Negative' : 'None'}
142+
valueStateMessage={
143+
component.isSelected && !component.selectedVersion ? (
144+
<span>{t('ComponentsSelection.chooseVersion')}</span>
145+
) : undefined
146+
}
135147
onChange={handleVersionChange}
136148
>
149+
{!component.selectedVersion && (
150+
<Option key="__placeholder" data-version="" data-name={component.name} selected>
151+
{t('ComponentsSelection.chooseVersion')}
152+
</Option>
153+
)}
137154
{component.versions.map((version) => (
138155
<Option
139156
key={version}
@@ -155,7 +172,14 @@ export const ComponentsSelection: React.FC<ComponentsSelectionProps> = ({ compon
155172
</Infobox>
156173
)}
157174
</div>
175+
158176
<div data-layout-span="XL4 L4 M4 S4">
177+
{templateDefaultsError ? (
178+
<div style={{ marginBottom: 8 }}>
179+
<IllustratedError title={templateDefaultsError} compact />
180+
</div>
181+
) : null}
182+
159183
{selectedComponents.length > 0 ? (
160184
<List headerText={t('componentsSelection.selectedComponents')}>
161185
{selectedComponents.map((component) => (

src/components/ControlPlanes/ControlPlanesListMenu.tsx

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,27 @@ import '@ui5/webcomponents-icons/dist/copy';
55
import '@ui5/webcomponents-icons/dist/accept';
66

77
import { useTranslation } from 'react-i18next';
8+
import { ManagedControlPlaneTemplate } from '../../lib/api/types/templates/mcpTemplate.ts';
89

910
type ControlPlanesListMenuProps = {
1011
setDialogDeleteWsIsOpen: Dispatch<SetStateAction<boolean>>;
1112
setIsCreateManagedControlPlaneWizardOpen: Dispatch<SetStateAction<boolean>>;
13+
setInitialTemplateName: Dispatch<SetStateAction<string | undefined>>;
1214
};
1315

1416
export const ControlPlanesListMenu: FC<ControlPlanesListMenuProps> = ({
1517
setDialogDeleteWsIsOpen,
1618
setIsCreateManagedControlPlaneWizardOpen,
19+
setInitialTemplateName,
1720
}) => {
1821
const popoverRef = useRef<MenuDomRef>(null);
1922
const [open, setOpen] = useState(false);
2023

2124
const { t } = useTranslation();
2225

26+
// Here we will pass template list from OnboardingAPI
27+
const allTemplates: ManagedControlPlaneTemplate[] = [];
28+
2329
const handleOpenerClick = (e: Ui5CustomEvent<ButtonDomRef, ButtonClickEventDetail>) => {
2430
if (popoverRef.current && e.currentTarget) {
2531
popoverRef.current.opener = e.currentTarget as HTMLElement;
@@ -34,14 +40,20 @@ export const ControlPlanesListMenu: FC<ControlPlanesListMenuProps> = ({
3440
ref={popoverRef}
3541
open={open}
3642
onItemClick={(event) => {
37-
const action = (event.detail.item as HTMLElement).dataset.action;
43+
const item = event.detail.item as HTMLElement;
44+
const action = item.dataset.action;
3845
if (action === 'newManagedControlPlane') {
46+
setInitialTemplateName(undefined);
47+
setIsCreateManagedControlPlaneWizardOpen(true);
48+
}
49+
if (action === 'newManagedControlPlaneWithTemplate') {
50+
const tplName = item.dataset.templateName || undefined;
51+
setInitialTemplateName(tplName);
3952
setIsCreateManagedControlPlaneWizardOpen(true);
4053
}
4154
if (action === 'deleteWorkspace') {
4255
setDialogDeleteWsIsOpen(true);
4356
}
44-
4557
setOpen(false);
4658
}}
4759
>
@@ -51,6 +63,17 @@ export const ControlPlanesListMenu: FC<ControlPlanesListMenuProps> = ({
5163
data-action="newManagedControlPlane"
5264
icon="add"
5365
/>
66+
{allTemplates.map((tpl) => (
67+
<MenuItem
68+
key={`tpl-${tpl.metadata.name}`}
69+
text={tpl.metadata.name}
70+
title={tpl.metadata.descriptionText || ''}
71+
data-action="newManagedControlPlaneWithTemplate"
72+
data-template-name={tpl.metadata.name}
73+
icon="document-text"
74+
/>
75+
))}
76+
5477
<MenuItem
5578
key={'delete'}
5679
text={t('ControlPlaneListToolbar.deleteWorkspace')}

src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import '@ui5/webcomponents-icons/dist/delete';
55
import { CopyButton } from '../../Shared/CopyButton.tsx';
66
import { ControlPlaneCard } from '../ControlPlaneCard/ControlPlaneCard.tsx';
77
import { ListWorkspacesType, isWorkspaceReady } from '../../../lib/api/types/crate/listWorkspaces.ts';
8-
import { useState } from 'react';
8+
import { useMemo, useState } from 'react';
99
import { MembersAvatarView } from './MembersAvatarView.tsx';
1010
import { DeleteWorkspaceResource, DeleteWorkspaceType } from '../../../lib/api/types/crate/deleteWorkspace.ts';
1111
import { useApiResourceMutation, useApiResource } from '../../../lib/api/useApiResource.ts';
@@ -32,6 +32,7 @@ interface Props {
3232

3333
export function ControlPlaneListWorkspaceGridTile({ projectName, workspace }: Props) {
3434
const [isCreateManagedControlPlaneWizardOpen, setIsCreateManagedControlPlaneWizardOpen] = useState(false);
35+
const [initialTemplateName, setInitialTemplateName] = useState<string | undefined>(undefined);
3536
const workspaceName = workspace.metadata.name;
3637
const workspaceDisplayName = workspace.metadata.annotations?.[DISPLAY_NAME_ANNOTATION] || '';
3738
const showDisplayName = workspaceDisplayName.length > 0;
@@ -68,6 +69,24 @@ export function ControlPlaneListWorkspaceGridTile({ projectName, workspace }: Pr
6869
return null;
6970
}
7071

72+
const uniqueMembers = useMemo(() => {
73+
const seenKeys = new Set<string>();
74+
const fallbackNamespace = workspace.status?.namespace ?? '';
75+
76+
return (workspace.spec.members ?? []).filter((member: { name?: string; namespace?: string }) => {
77+
const memberNamespace = member?.namespace ?? fallbackNamespace;
78+
const memberName = String(member?.name ?? '')
79+
.trim()
80+
.toLowerCase();
81+
if (!memberName) return false;
82+
83+
const dedupeKey = `${memberNamespace}::${memberName}`;
84+
if (seenKeys.has(dedupeKey)) return false;
85+
seenKeys.add(dedupeKey);
86+
return true;
87+
});
88+
}, [workspace.spec.members, workspace.status?.namespace]);
89+
7190
return (
7291
<>
7392
<ObjectPageSection
@@ -98,7 +117,7 @@ export function ControlPlaneListWorkspaceGridTile({ projectName, workspace }: Pr
98117

99118
<CopyButton text={workspace.status?.namespace || '-'} style={{ justifyContent: 'start' }} />
100119

101-
<MembersAvatarView members={workspace.spec.members} project={projectName} workspace={workspaceName} />
120+
<MembersAvatarView members={uniqueMembers} project={projectName} workspace={workspaceName} />
102121
<FlexBox justifyContent={'SpaceBetween'} gap={10}>
103122
<YamlViewButtonWithLoader
104123
workspaceName={workspace.metadata.namespace}
@@ -108,6 +127,7 @@ export function ControlPlaneListWorkspaceGridTile({ projectName, workspace }: Pr
108127
<ControlPlanesListMenu
109128
setDialogDeleteWsIsOpen={setDialogDeleteWsIsOpen}
110129
setIsCreateManagedControlPlaneWizardOpen={setIsCreateManagedControlPlaneWizardOpen}
130+
setInitialTemplateName={setInitialTemplateName}
111131
/>
112132
</FlexBox>
113133
</div>
@@ -168,6 +188,7 @@ export function ControlPlaneListWorkspaceGridTile({ projectName, workspace }: Pr
168188
setIsOpen={setIsCreateManagedControlPlaneWizardOpen}
169189
projectName={projectNamespace}
170190
workspaceName={workspaceName}
191+
initialTemplateName={initialTemplateName}
171192
isEditMode={true}
172193
/>
173194
</>

src/components/Dialogs/CreateProjectWorkspaceDialog.module.css renamed to src/components/Dialogs/MetadataForm.module.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
.affixRow {
2+
display: flex;
3+
gap: 8px;
4+
align-items: center;
5+
}
6+
17
.input {
28
width: 100%;
39
margin-bottom: 2rem;

0 commit comments

Comments
 (0)