From 0908cf650c4442f740731fe6df13c1d605a0a45d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Goral?= Date: Tue, 1 Jul 2025 13:45:27 +0200 Subject: [PATCH 01/18] Update ComponentsSelection.tsx --- src/components/ComponentsSelection/ComponentsSelection.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/ComponentsSelection/ComponentsSelection.tsx b/src/components/ComponentsSelection/ComponentsSelection.tsx index 1abf0d67..3a02d39f 100644 --- a/src/components/ComponentsSelection/ComponentsSelection.tsx +++ b/src/components/ComponentsSelection/ComponentsSelection.tsx @@ -68,7 +68,7 @@ export const ComponentsSelection: React.FC = ({ }; const filteredComponents = components.filter(({ name }) => - name.includes(searchTerm), + name.toLowerCase().includes(searchTerm.toLowerCase()), ); const selectedComponents = components.filter( (component) => component.isSelected, @@ -115,6 +115,7 @@ export const ComponentsSelection: React.FC = ({ )} {component.versions.map((version) => ( From a6fc80c1508df01cd79b8f40e9155af9fbf94bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Goral?= Date: Tue, 1 Jul 2025 13:48:13 +0200 Subject: [PATCH 03/18] Update CreateManagedControlPlaneWizardContainer.tsx --- .../Wizards/CreateManagedControlPlaneWizardContainer.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx index f1c17d89..9f78540f 100644 --- a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx +++ b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx @@ -237,6 +237,7 @@ export const CreateManagedControlPlaneWizardContainer: FC< return ( selectedStep === 'metadata' || selectedStep === 'members' || + selectedStep === 'componentSelection' || !isValid ); From 044613ba6a0fe97a8eaff66a498ecaa5a9876b44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Goral?= Date: Tue, 1 Jul 2025 14:25:38 +0200 Subject: [PATCH 04/18] Update ComponentsSelectionContainer.tsx --- .../ComponentsSelection/ComponentsSelectionContainer.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx b/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx index d489578e..a3ed48a6 100644 --- a/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx +++ b/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx @@ -9,11 +9,6 @@ import useApiResource from '../../lib/api/useApiResource.ts'; import Loading from '../Shared/Loading.tsx'; import { ComponentSelectionItem } from '../../lib/api/types/crate/createManagedControlPlane.ts'; -export interface ComponentItem { - name: string; - versions: string[]; -} - export interface ComponentsSelectionProps { selectedComponents: ComponentSelectionItem[]; setSelectedComponents: React.Dispatch< From 5efefdeca691436ae11b154a04b16efe346159f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Goral?= Date: Wed, 2 Jul 2025 13:33:49 +0200 Subject: [PATCH 05/18] refactor --- .../ComponentsSelection.tsx | 12 ++++----- .../ComponentsSelectionContainer.tsx | 4 +-- .../CreateWorkspaceDialogContainer.tsx | 2 ++ src/components/Dialogs/MetadataForm.tsx | 1 - ...eateManagedControlPlaneWizardContainer.tsx | 26 ++++++++++--------- 5 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/components/ComponentsSelection/ComponentsSelection.tsx b/src/components/ComponentsSelection/ComponentsSelection.tsx index 8663f537..89f45cb2 100644 --- a/src/components/ComponentsSelection/ComponentsSelection.tsx +++ b/src/components/ComponentsSelection/ComponentsSelection.tsx @@ -24,9 +24,7 @@ import { ComponentSelectionItem } from '../../lib/api/types/crate/createManagedC export interface ComponentsSelectionProps { components: ComponentSelectionItem[]; - setSelectedComponents: React.Dispatch< - React.SetStateAction - >; + setSelectedComponents: (components: ComponentSelectionItem[]) => void; } export const ComponentsSelection: React.FC = ({ @@ -39,8 +37,8 @@ export const ComponentsSelection: React.FC = ({ e: Ui5CustomEvent, ) => { const id = e.target?.id; - setSelectedComponents((prev) => - prev.map((component) => + setSelectedComponents( + components.map((component) => component.name === id ? { ...component, isSelected: !component.isSelected } : component, @@ -58,8 +56,8 @@ export const ComponentsSelection: React.FC = ({ const selectedOption = e.detail.selectedOption as HTMLElement; const name = selectedOption.dataset.name; const version = selectedOption.dataset.version; - setSelectedComponents((prev) => - prev.map((component) => + setSelectedComponents( + components.map((component) => component.name === name ? { ...component, selectedVersion: version || '' } : component, diff --git a/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx b/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx index a3ed48a6..0c18433c 100644 --- a/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx +++ b/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx @@ -11,9 +11,7 @@ import { ComponentSelectionItem } from '../../lib/api/types/crate/createManagedC export interface ComponentsSelectionProps { selectedComponents: ComponentSelectionItem[]; - setSelectedComponents: React.Dispatch< - React.SetStateAction - >; + setSelectedComponents: (components: ComponentSelectionItem[]) => void; } export const ComponentsSelectionContainer: React.FC< ComponentsSelectionProps diff --git a/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx b/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx index 267ead65..4c69bc1e 100644 --- a/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx +++ b/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx @@ -23,12 +23,14 @@ import { useTranslation } from 'react-i18next'; import { zodResolver } from '@hookform/resolvers/zod'; import { useForm } from 'react-hook-form'; import { validationSchemaProjectWorkspace } from '../../lib/api/validations/schemas.ts'; +import { ComponentSelectionItem } from '../../lib/api/types/crate/createManagedControlPlane.ts'; export type CreateDialogProps = { name: string; displayName?: string; chargingTarget?: string; members: Member[]; + selectedComponents?: ComponentSelectionItem[]; }; export function CreateWorkspaceDialogContainer({ diff --git a/src/components/Dialogs/MetadataForm.tsx b/src/components/Dialogs/MetadataForm.tsx index a69f088c..136bcf7d 100644 --- a/src/components/Dialogs/MetadataForm.tsx +++ b/src/components/Dialogs/MetadataForm.tsx @@ -14,7 +14,6 @@ export interface MetadataFormProps { export function MetadataForm({ register, errors, - sideFormContent, }: MetadataFormProps) { const { t } = useTranslation(); diff --git a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx index 9f78540f..5e7ff159 100644 --- a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx +++ b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx @@ -40,13 +40,7 @@ import { MetadataForm } from '../Dialogs/MetadataForm.tsx'; import { IllustratedBanner } from '../Ui/IllustratedBanner/IllustratedBanner.tsx'; import { ComponentsSelectionContainer } from '../ComponentsSelection/ComponentsSelectionContainer.tsx'; import { idpPrefix } from '../../utils/idpPrefix.ts'; - -export type CreateDialogProps = { - name: string; - displayName?: string; - chargingTarget?: string; - members: Member[]; -}; +import { CreateDialogProps } from '../Dialogs/CreateWorkspaceDialogContainer.tsx'; type CreateManagedControlPlaneWizardContainerProps = { isOpen: boolean; @@ -78,9 +72,9 @@ export const CreateManagedControlPlaneWizardContainer: FC< const errorDialogRef = useRef(null); const [selectedStep, setSelectedStep] = useState('metadata'); - const [selectedComponents, setSelectedComponents] = useState< - ComponentSelectionItem[] - >([]); + // const [selectedComponents, setSelectedComponents] = useState< + // ComponentSelectionItem[] + // >([]); const { register, handleSubmit, @@ -97,6 +91,7 @@ export const CreateManagedControlPlaneWizardContainer: FC< displayName: '', chargingTarget: '', members: [], + selectedComponents: [], }, mode: 'onChange', }); @@ -138,7 +133,7 @@ export const CreateManagedControlPlaneWizardContainer: FC< const { trigger } = useApiResourceMutation( CreateManagedControlPlaneResource(projectName, workspaceName), ); - + const selectedComponents = watch('selectedComponents'); const handleCreateManagedControlPlane = useCallback( async ({ name, @@ -220,6 +215,13 @@ export const CreateManagedControlPlaneWizardContainer: FC< [setValue], ); + const setSelectedComponents = useCallback( + (components: ComponentSelectionItem[]) => { + setValue('selectedComponents', components, { shouldValidate: false }); + }, + [setValue], + ); + const isStepDisabled = useCallback( (step: WizardStepType) => { switch (step) { @@ -325,7 +327,7 @@ export const CreateManagedControlPlaneWizardContainer: FC< disabled={isStepDisabled('componentSelection')} > From bcd1be0b6767c2ac672c7ff6e2417a55312ee291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Goral?= Date: Wed, 2 Jul 2025 14:34:53 +0200 Subject: [PATCH 06/18] Update ComponentsSelection.tsx --- .../ComponentsSelection.tsx | 91 +++++++++++-------- 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/src/components/ComponentsSelection/ComponentsSelection.tsx b/src/components/ComponentsSelection/ComponentsSelection.tsx index 89f45cb2..afb899ed 100644 --- a/src/components/ComponentsSelection/ComponentsSelection.tsx +++ b/src/components/ComponentsSelection/ComponentsSelection.tsx @@ -69,7 +69,13 @@ export const ComponentsSelection: React.FC = ({ name.toLowerCase().includes(searchTerm.toLowerCase()), ); const selectedComponents = components.filter( - (component) => component.isSelected, + (component) => + component.isSelected && + !( + component.name?.includes('provider') && + components?.find(({ name }) => name === 'crossplane')?.isSelected === + false + ), ); return ( @@ -86,50 +92,57 @@ export const ComponentsSelection: React.FC = ({
- {filteredComponents.map((component) => ( - - + {filteredComponents.map((component) => { + const isProviderDisabled = + component.name?.includes('provider') && + components?.find(({ name }) => name === 'crossplane') + ?.isSelected === false; + return ( - {/*This button will be implemented later*/} - {component.documentationUrl && ( - - )} - + {/*This button will be implemented later*/} + {component.documentationUrl && ( + + )} + + - - ))} + ); + })}
{selectedComponents.length > 0 ? ( From b82b38762a9bc0f477f1efd88ccb24361dc05965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Goral?= Date: Wed, 2 Jul 2025 15:00:15 +0200 Subject: [PATCH 07/18] fixes --- .../ComponentsSelection.tsx | 11 ++-------- ...eateManagedControlPlaneWizardContainer.tsx | 21 +++++++++++++++---- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/components/ComponentsSelection/ComponentsSelection.tsx b/src/components/ComponentsSelection/ComponentsSelection.tsx index afb899ed..b242e531 100644 --- a/src/components/ComponentsSelection/ComponentsSelection.tsx +++ b/src/components/ComponentsSelection/ComponentsSelection.tsx @@ -21,6 +21,7 @@ import styles from './ComponentsSelection.module.css'; import { Infobox } from '../Ui/Infobox/Infobox.tsx'; import { useTranslation } from 'react-i18next'; import { ComponentSelectionItem } from '../../lib/api/types/crate/createManagedControlPlane.ts'; +import { filterSelectedComponents } from '../Wizards/CreateManagedControlPlaneWizardContainer.tsx'; export interface ComponentsSelectionProps { components: ComponentSelectionItem[]; @@ -68,15 +69,7 @@ export const ComponentsSelection: React.FC = ({ const filteredComponents = components.filter(({ name }) => name.toLowerCase().includes(searchTerm.toLowerCase()), ); - const selectedComponents = components.filter( - (component) => - component.isSelected && - !( - component.name?.includes('provider') && - components?.find(({ name }) => name === 'crossplane')?.isSelected === - false - ), - ); + const selectedComponents = filterSelectedComponents(components); return (
diff --git a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx index 5e7ff159..3031d89e 100644 --- a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx +++ b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx @@ -64,6 +64,19 @@ const wizardStepOrder: WizardStepType[] = [ 'success', ]; +export const filterSelectedComponents = ( + components: ComponentSelectionItem[], +) => + components.filter( + (component) => + component.isSelected && + !( + component.name?.includes('provider') && + components?.find(({ name }) => name === 'crossplane')?.isSelected === + false + ), + ); + export const CreateManagedControlPlaneWizardContainer: FC< CreateManagedControlPlaneWizardContainerProps > = ({ isOpen, setIsOpen, projectName = '', workspaceName = '' }) => { @@ -371,15 +384,15 @@ export const CreateManagedControlPlaneWizardContainer: FC<
- {selectedComponents - .filter(({ isSelected }) => isSelected) - .map((component) => ( + {filterSelectedComponents(selectedComponents ?? []).map( + (component) => ( - ))} + ), + )}
From 67cf5d4fecc1ddeed9280796b0d11943bd75a094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Goral?= Date: Wed, 2 Jul 2025 15:16:53 +0200 Subject: [PATCH 08/18] Update CreateManagedControlPlaneWizardContainer.tsx --- .../Wizards/CreateManagedControlPlaneWizardContainer.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx index 3031d89e..11e89c13 100644 --- a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx +++ b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx @@ -85,9 +85,7 @@ export const CreateManagedControlPlaneWizardContainer: FC< const errorDialogRef = useRef(null); const [selectedStep, setSelectedStep] = useState('metadata'); - // const [selectedComponents, setSelectedComponents] = useState< - // ComponentSelectionItem[] - // >([]); + const { register, handleSubmit, @@ -405,7 +403,9 @@ export const CreateManagedControlPlaneWizardContainer: FC< displayName: getValues('displayName'), chargingTarget: getValues('chargingTarget'), members: getValues('members'), - selectedComponents: selectedComponents, + selectedComponents: filterSelectedComponents( + selectedComponents ?? [], + ), }, idpPrefix, ), From 80baed502cce49b082ef7198cf75194ad4f326ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Goral?= Date: Thu, 3 Jul 2025 10:52:23 +0200 Subject: [PATCH 09/18] Update createManagedControlPlane.ts --- .../types/crate/createManagedControlPlane.ts | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/lib/api/types/crate/createManagedControlPlane.ts b/src/lib/api/types/crate/createManagedControlPlane.ts index 88c245bb..a12e17d1 100644 --- a/src/lib/api/types/crate/createManagedControlPlane.ts +++ b/src/lib/api/types/crate/createManagedControlPlane.ts @@ -24,6 +24,11 @@ interface Subject { kind: 'User' | 'Group' | 'ServiceAccount'; name: string; } + +interface Provider { + name: string; + version: string; +} interface Spec { authentication: { enableSystemIdentityProvider: boolean; @@ -38,7 +43,8 @@ interface Components { | { version: string; } - | { type: 'GardenerDedicated' }; + | { type: 'GardenerDedicated' } + | { version: string; providers: Provider[] }; } export interface CreateManagedControlPlaneType { @@ -66,11 +72,26 @@ export const CreateManagedControlPlane = ( ): CreateManagedControlPlaneType => { const componentsObject: Components = optional?.selectedComponents - ?.filter((component) => component.isSelected) + ?.filter( + (component) => + component.isSelected && + !component.name.includes('provider') && + !component.name.includes('crossplane'), + ) .reduce((acc, item) => { acc[item.name] = { version: item.selectedVersion }; return acc; }, {} as Components) ?? {}; + const crossplane: Components = optional?.selectedComponents?.find( + ({ name }) => name === 'crossplane', + ); + const providers: Provider[] = optional?.selectedComponents + ?.filter(({ name, isSelected }) => name.includes('provider') && isSelected) + .map(({ name, selectedVersion }) => ({ + name: name, + version: selectedVersion, + })); + const providersObject = return { apiVersion: 'core.openmcp.cloud/v1alpha1', @@ -90,6 +111,7 @@ export const CreateManagedControlPlane = ( components: { ...componentsObject, apiServer: { type: 'GardenerDedicated' }, + // ...{crossplane ? { crossplane: { version: '', providers: [] } } : {}}, }, authorization: { roleBindings: From 0e9aced0ea259d26a5e58ea6cb4daf629fc9de33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Goral?= Date: Fri, 4 Jul 2025 15:13:40 +0200 Subject: [PATCH 10/18] Update createManagedControlPlane.ts --- .../types/crate/createManagedControlPlane.ts | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/lib/api/types/crate/createManagedControlPlane.ts b/src/lib/api/types/crate/createManagedControlPlane.ts index a12e17d1..5da8380c 100644 --- a/src/lib/api/types/crate/createManagedControlPlane.ts +++ b/src/lib/api/types/crate/createManagedControlPlane.ts @@ -82,16 +82,25 @@ export const CreateManagedControlPlane = ( acc[item.name] = { version: item.selectedVersion }; return acc; }, {} as Components) ?? {}; - const crossplane: Components = optional?.selectedComponents?.find( - ({ name }) => name === 'crossplane', + const crossplane = optional?.selectedComponents?.find( + ({ name, isSelected }) => name === 'crossplane' && isSelected, ); - const providers: Provider[] = optional?.selectedComponents - ?.filter(({ name, isSelected }) => name.includes('provider') && isSelected) - .map(({ name, selectedVersion }) => ({ - name: name, - version: selectedVersion, - })); - const providersObject = + + const providers: Provider[] = + optional?.selectedComponents + ?.filter( + ({ name, isSelected }) => name.includes('provider') && isSelected, + ) + .map(({ name, selectedVersion }) => ({ + name: name, + version: selectedVersion, + })) ?? []; + const providersObject = { + crossplane: { + version: crossplane?.selectedVersion ?? '', + providers: providers, + }, + }; return { apiVersion: 'core.openmcp.cloud/v1alpha1', @@ -111,7 +120,7 @@ export const CreateManagedControlPlane = ( components: { ...componentsObject, apiServer: { type: 'GardenerDedicated' }, - // ...{crossplane ? { crossplane: { version: '', providers: [] } } : {}}, + ...(crossplane ? providersObject : {}), }, authorization: { roleBindings: From 548e5f831bf8e6bad55c5c53e14f60e8247b8c64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Goral?= Date: Mon, 7 Jul 2025 10:30:22 +0200 Subject: [PATCH 11/18] refactor --- .../ComponentsSelectionContainer.tsx | 10 +++++----- .../api/types/crate/createManagedControlPlane.ts | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx b/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx index 0c18433c..1202bc83 100644 --- a/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx +++ b/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx @@ -17,21 +17,21 @@ export const ComponentsSelectionContainer: React.FC< ComponentsSelectionProps > = ({ setSelectedComponents, selectedComponents }) => { const { - data: allManagedComponents, + data: availableManagedComponentsListData, error, isLoading, } = useApiResource(ListManagedComponents()); const [isReady, setIsReady] = useState(false); useEffect(() => { if ( - allManagedComponents?.items.length === 0 || - !allManagedComponents?.items || + availableManagedComponentsListData?.items.length === 0 || + !availableManagedComponentsListData?.items || isReady ) return; setSelectedComponents( - allManagedComponents?.items?.map((item) => { + availableManagedComponentsListData?.items?.map((item) => { const versions = sortVersions(item.status.versions); return { name: item.metadata.name, @@ -43,7 +43,7 @@ export const ComponentsSelectionContainer: React.FC< }) ?? [], ); setIsReady(true); - }, [allManagedComponents, isReady, setSelectedComponents]); + }, [availableManagedComponentsListData, isReady, setSelectedComponents]); if (isLoading) { return ; } diff --git a/src/lib/api/types/crate/createManagedControlPlane.ts b/src/lib/api/types/crate/createManagedControlPlane.ts index 5da8380c..2f063e16 100644 --- a/src/lib/api/types/crate/createManagedControlPlane.ts +++ b/src/lib/api/types/crate/createManagedControlPlane.ts @@ -70,7 +70,7 @@ export const CreateManagedControlPlane = ( }, idpPrefix?: string, ): CreateManagedControlPlaneType => { - const componentsObject: Components = + const selectedComponentsListObject: Components = optional?.selectedComponents ?.filter( (component) => @@ -82,11 +82,11 @@ export const CreateManagedControlPlane = ( acc[item.name] = { version: item.selectedVersion }; return acc; }, {} as Components) ?? {}; - const crossplane = optional?.selectedComponents?.find( + const crossplaneComponent = optional?.selectedComponents?.find( ({ name, isSelected }) => name === 'crossplane' && isSelected, ); - const providers: Provider[] = + const providersListObject: Provider[] = optional?.selectedComponents ?.filter( ({ name, isSelected }) => name.includes('provider') && isSelected, @@ -95,10 +95,10 @@ export const CreateManagedControlPlane = ( name: name, version: selectedVersion, })) ?? []; - const providersObject = { + const crossplaneWithProvidersListObject = { crossplane: { - version: crossplane?.selectedVersion ?? '', - providers: providers, + version: crossplaneComponent?.selectedVersion ?? '', + providers: providersListObject, }, }; @@ -118,9 +118,9 @@ export const CreateManagedControlPlane = ( spec: { authentication: { enableSystemIdentityProvider: true }, components: { - ...componentsObject, + ...selectedComponentsListObject, apiServer: { type: 'GardenerDedicated' }, - ...(crossplane ? providersObject : {}), + ...(crossplaneComponent ? crossplaneWithProvidersListObject : {}), }, authorization: { roleBindings: From 962e103405d7f8c342272e4a3ba23ec088d5afe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Goral?= Date: Mon, 7 Jul 2025 12:09:20 +0200 Subject: [PATCH 12/18] fixes --- .../ComponentsSelection.tsx | 2 +- .../ComponentsSelectionContainer.tsx | 14 ++++++++++++++ ...reateManagedControlPlaneWizardContainer.tsx | 18 ++++-------------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/components/ComponentsSelection/ComponentsSelection.tsx b/src/components/ComponentsSelection/ComponentsSelection.tsx index b242e531..8c912d46 100644 --- a/src/components/ComponentsSelection/ComponentsSelection.tsx +++ b/src/components/ComponentsSelection/ComponentsSelection.tsx @@ -21,7 +21,7 @@ import styles from './ComponentsSelection.module.css'; import { Infobox } from '../Ui/Infobox/Infobox.tsx'; import { useTranslation } from 'react-i18next'; import { ComponentSelectionItem } from '../../lib/api/types/crate/createManagedControlPlane.ts'; -import { filterSelectedComponents } from '../Wizards/CreateManagedControlPlaneWizardContainer.tsx'; +import { filterSelectedComponents } from './ComponentsSelectionContainer.tsx'; export interface ComponentsSelectionProps { components: ComponentSelectionItem[]; diff --git a/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx b/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx index 1202bc83..b7115c39 100644 --- a/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx +++ b/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx @@ -13,6 +13,20 @@ export interface ComponentsSelectionProps { selectedComponents: ComponentSelectionItem[]; setSelectedComponents: (components: ComponentSelectionItem[]) => void; } + +export const filterSelectedComponents = ( + components: ComponentSelectionItem[], +) => + components.filter( + (component) => + component.isSelected && + !( + component.name?.includes('provider') && + components?.find(({ name }) => name === 'crossplane')?.isSelected === + false + ), + ); + export const ComponentsSelectionContainer: React.FC< ComponentsSelectionProps > = ({ setSelectedComponents, selectedComponents }) => { diff --git a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx index 5eeab258..001e46d2 100644 --- a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx +++ b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx @@ -38,7 +38,10 @@ import { EditMembers } from '../Members/EditMembers.tsx'; import { useTranslation } from 'react-i18next'; import { MetadataForm } from '../Dialogs/MetadataForm.tsx'; import { IllustratedBanner } from '../Ui/IllustratedBanner/IllustratedBanner.tsx'; -import { ComponentsSelectionContainer } from '../ComponentsSelection/ComponentsSelectionContainer.tsx'; +import { + ComponentsSelectionContainer, + filterSelectedComponents, +} from '../ComponentsSelection/ComponentsSelectionContainer.tsx'; import { idpPrefix } from '../../utils/idpPrefix.ts'; import { CreateDialogProps } from '../Dialogs/CreateWorkspaceDialogContainer.tsx'; @@ -64,19 +67,6 @@ const wizardStepOrder: WizardStepType[] = [ 'success', ]; -export const filterSelectedComponents = ( - components: ComponentSelectionItem[], -) => - components.filter( - (component) => - component.isSelected && - !( - component.name?.includes('provider') && - components?.find(({ name }) => name === 'crossplane')?.isSelected === - false - ), - ); - export const CreateManagedControlPlaneWizardContainer: FC< CreateManagedControlPlaneWizardContainerProps > = ({ isOpen, setIsOpen, projectName = '', workspaceName = '' }) => { From 7030b83571c111efee00410837d4d395627ac000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Goral?= Date: Mon, 7 Jul 2025 12:15:39 +0200 Subject: [PATCH 13/18] Update CreateManagedControlPlaneWizardContainer.tsx --- .../Wizards/CreateManagedControlPlaneWizardContainer.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx index 770bcd3a..7901661c 100644 --- a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx +++ b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx @@ -45,13 +45,6 @@ import { import { CreateDialogProps } from '../Dialogs/CreateWorkspaceDialogContainer.tsx'; import { idpPrefix } from '../../utils/idpPrefix.ts'; -export type CreateDialogProps = { - name: string; - displayName?: string; - chargingTarget?: string; - chargingTargetType?: string; - members: Member[]; -}; type CreateManagedControlPlaneWizardContainerProps = { isOpen: boolean; From 8d76211713b71dc0f1b9738034cbb4d534cd8972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Goral?= Date: Mon, 7 Jul 2025 13:36:26 +0200 Subject: [PATCH 14/18] refactor --- .../ComponentsSelection/ComponentsSelection.tsx | 8 ++++---- .../ComponentsSelection/ComponentsSelectionContainer.tsx | 5 ++--- .../Wizards/CreateManagedControlPlaneWizardContainer.tsx | 6 +++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/components/ComponentsSelection/ComponentsSelection.tsx b/src/components/ComponentsSelection/ComponentsSelection.tsx index 8c912d46..5b97de3a 100644 --- a/src/components/ComponentsSelection/ComponentsSelection.tsx +++ b/src/components/ComponentsSelection/ComponentsSelection.tsx @@ -21,7 +21,7 @@ import styles from './ComponentsSelection.module.css'; import { Infobox } from '../Ui/Infobox/Infobox.tsx'; import { useTranslation } from 'react-i18next'; import { ComponentSelectionItem } from '../../lib/api/types/crate/createManagedControlPlane.ts'; -import { filterSelectedComponents } from './ComponentsSelectionContainer.tsx'; +import { getSelectedComponents } from './ComponentsSelectionContainer.tsx'; export interface ComponentsSelectionProps { components: ComponentSelectionItem[]; @@ -66,10 +66,10 @@ export const ComponentsSelection: React.FC = ({ ); }; - const filteredComponents = components.filter(({ name }) => + const searchResults = components.filter(({ name }) => name.toLowerCase().includes(searchTerm.toLowerCase()), ); - const selectedComponents = filterSelectedComponents(components); + const selectedComponents = getSelectedComponents(components); return (
@@ -85,7 +85,7 @@ export const ComponentsSelection: React.FC = ({
- {filteredComponents.map((component) => { + {searchResults.map((component) => { const isProviderDisabled = component.name?.includes('provider') && components?.find(({ name }) => name === 'crossplane') diff --git a/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx b/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx index b7115c39..c3e4dbb6 100644 --- a/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx +++ b/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx @@ -14,9 +14,8 @@ export interface ComponentsSelectionProps { setSelectedComponents: (components: ComponentSelectionItem[]) => void; } -export const filterSelectedComponents = ( - components: ComponentSelectionItem[], -) => +// get selected components and when Crossplane is selected then also providers +export const getSelectedComponents = (components: ComponentSelectionItem[]) => components.filter( (component) => component.isSelected && diff --git a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx index 7901661c..f2951079 100644 --- a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx +++ b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx @@ -40,7 +40,7 @@ import { MetadataForm } from '../Dialogs/MetadataForm.tsx'; import { IllustratedBanner } from '../Ui/IllustratedBanner/IllustratedBanner.tsx'; import { ComponentsSelectionContainer, - filterSelectedComponents, + getSelectedComponents, } from '../ComponentsSelection/ComponentsSelectionContainer.tsx'; import { CreateDialogProps } from '../Dialogs/CreateWorkspaceDialogContainer.tsx'; @@ -379,7 +379,7 @@ export const CreateManagedControlPlaneWizardContainer: FC<
- {filterSelectedComponents(selectedComponents ?? []).map( + {getSelectedComponents(selectedComponents ?? []).map( (component) => ( Date: Mon, 7 Jul 2025 16:42:22 +0200 Subject: [PATCH 15/18] refactor --- public/locales/en.json | 3 ++- .../ComponentsSelection.tsx | 24 +++++++++---------- .../ComponentsSelectionContainer.tsx | 24 ++++++++++--------- .../CreateWorkspaceDialogContainer.tsx | 4 ++-- ...eateManagedControlPlaneWizardContainer.tsx | 20 ++++++++-------- .../types/crate/createManagedControlPlane.ts | 4 ++-- 6 files changed, 41 insertions(+), 38 deletions(-) diff --git a/public/locales/en.json b/public/locales/en.json index f1a83b47..4192371f 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -308,6 +308,7 @@ "componentsSelection": { "selectComponents": "Select Components", "selectedComponents": "Selected Components", - "pleaseSelectComponents": "Choose the components you want to add to your Managed Control Plane." + "pleaseSelectComponents": "Choose the components you want to add to your Managed Control Plane.", + "cannotLoad": "Cannot load components list" } } diff --git a/src/components/ComponentsSelection/ComponentsSelection.tsx b/src/components/ComponentsSelection/ComponentsSelection.tsx index 5b97de3a..bb0f72a2 100644 --- a/src/components/ComponentsSelection/ComponentsSelection.tsx +++ b/src/components/ComponentsSelection/ComponentsSelection.tsx @@ -20,17 +20,17 @@ import { import styles from './ComponentsSelection.module.css'; import { Infobox } from '../Ui/Infobox/Infobox.tsx'; import { useTranslation } from 'react-i18next'; -import { ComponentSelectionItem } from '../../lib/api/types/crate/createManagedControlPlane.ts'; +import { ComponentsListItem } from '../../lib/api/types/crate/createManagedControlPlane.ts'; import { getSelectedComponents } from './ComponentsSelectionContainer.tsx'; export interface ComponentsSelectionProps { - components: ComponentSelectionItem[]; - setSelectedComponents: (components: ComponentSelectionItem[]) => void; + componentsList: ComponentsListItem[]; + setComponentsList: (components: ComponentsListItem[]) => void; } export const ComponentsSelection: React.FC = ({ - components, - setSelectedComponents, + componentsList, + setComponentsList, }) => { const [searchTerm, setSearchTerm] = useState(''); const { t } = useTranslation(); @@ -38,8 +38,8 @@ export const ComponentsSelection: React.FC = ({ e: Ui5CustomEvent, ) => { const id = e.target?.id; - setSelectedComponents( - components.map((component) => + setComponentsList( + componentsList.map((component) => component.name === id ? { ...component, isSelected: !component.isSelected } : component, @@ -57,8 +57,8 @@ export const ComponentsSelection: React.FC = ({ const selectedOption = e.detail.selectedOption as HTMLElement; const name = selectedOption.dataset.name; const version = selectedOption.dataset.version; - setSelectedComponents( - components.map((component) => + setComponentsList( + componentsList.map((component) => component.name === name ? { ...component, selectedVersion: version || '' } : component, @@ -66,10 +66,10 @@ export const ComponentsSelection: React.FC = ({ ); }; - const searchResults = components.filter(({ name }) => + const searchResults = componentsList.filter(({ name }) => name.toLowerCase().includes(searchTerm.toLowerCase()), ); - const selectedComponents = getSelectedComponents(components); + const selectedComponents = getSelectedComponents(componentsList); return (
@@ -88,7 +88,7 @@ export const ComponentsSelection: React.FC = ({ {searchResults.map((component) => { const isProviderDisabled = component.name?.includes('provider') && - components?.find(({ name }) => name === 'crossplane') + componentsList?.find(({ name }) => name === 'crossplane') ?.isSelected === false; return ( void; + componentsList: ComponentsListItem[]; + setComponentsList: (components: ComponentsListItem[]) => void; } // get selected components and when Crossplane is selected then also providers -export const getSelectedComponents = (components: ComponentSelectionItem[]) => +export const getSelectedComponents = (components: ComponentsListItem[]) => components.filter( (component) => component.isSelected && @@ -28,13 +29,14 @@ export const getSelectedComponents = (components: ComponentSelectionItem[]) => export const ComponentsSelectionContainer: React.FC< ComponentsSelectionProps -> = ({ setSelectedComponents, selectedComponents }) => { +> = ({ setComponentsList, componentsList }) => { const { data: availableManagedComponentsListData, error, isLoading, } = useApiResource(ListManagedComponents()); const [isReady, setIsReady] = useState(false); + const { t } = useTranslation(); useEffect(() => { if ( availableManagedComponentsListData?.items.length === 0 || @@ -43,7 +45,7 @@ export const ComponentsSelectionContainer: React.FC< ) return; - setSelectedComponents( + setComponentsList( availableManagedComponentsListData?.items?.map((item) => { const versions = sortVersions(item.status.versions); return { @@ -56,20 +58,20 @@ export const ComponentsSelectionContainer: React.FC< }) ?? [], ); setIsReady(true); - }, [availableManagedComponentsListData, isReady, setSelectedComponents]); + }, [availableManagedComponentsListData, isReady, setComponentsList]); if (isLoading) { return ; } if (error) return ; return ( <> - {selectedComponents.length > 0 ? ( + {componentsList.length > 0 ? ( ) : ( - + )} ); diff --git a/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx b/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx index 54d4028d..d4c36ca6 100644 --- a/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx +++ b/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx @@ -23,7 +23,7 @@ import { useTranslation } from 'react-i18next'; import { zodResolver } from '@hookform/resolvers/zod'; import { useForm } from 'react-hook-form'; import { validationSchemaProjectWorkspace } from '../../lib/api/validations/schemas.ts'; -import { ComponentSelectionItem } from '../../lib/api/types/crate/createManagedControlPlane.ts'; +import { ComponentsListItem } from '../../lib/api/types/crate/createManagedControlPlane.ts'; export type CreateDialogProps = { name: string; @@ -31,7 +31,7 @@ export type CreateDialogProps = { chargingTarget?: string; chargingTargetType?: string; members: Member[]; - selectedComponents?: ComponentSelectionItem[]; + selectedComponents?: ComponentsListItem[]; }; export function CreateWorkspaceDialogContainer({ diff --git a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx index f2951079..88adb12a 100644 --- a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx +++ b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx @@ -27,7 +27,7 @@ import YamlViewer from '../Yaml/YamlViewer.tsx'; import { stringify } from 'yaml'; import { APIError } from '../../lib/api/error.ts'; import { - ComponentSelectionItem, + ComponentsListItem, CreateManagedControlPlane, CreateManagedControlPlaneResource, CreateManagedControlPlaneType, @@ -137,7 +137,7 @@ export const CreateManagedControlPlaneWizardContainer: FC< const { trigger } = useApiResourceMutation( CreateManagedControlPlaneResource(projectName, workspaceName), ); - const selectedComponents = watch('selectedComponents'); + const componentsList = watch('selectedComponents'); const handleCreateManagedControlPlane = useCallback( async ({ name, @@ -154,7 +154,7 @@ export const CreateManagedControlPlaneWizardContainer: FC< displayName, chargingTarget, members, - selectedComponents, + selectedComponents: componentsList, }, idpPrefix, ), @@ -172,7 +172,7 @@ export const CreateManagedControlPlaneWizardContainer: FC< return false; } }, - [trigger, projectName, workspaceName, selectedComponents], + [trigger, projectName, workspaceName, componentsList], ); const handleStepChange = useCallback( @@ -219,8 +219,8 @@ export const CreateManagedControlPlaneWizardContainer: FC< [setValue], ); - const setSelectedComponents = useCallback( - (components: ComponentSelectionItem[]) => { + const setComponentsList = useCallback( + (components: ComponentsListItem[]) => { setValue('selectedComponents', components, { shouldValidate: false }); }, [setValue], @@ -335,8 +335,8 @@ export const CreateManagedControlPlaneWizardContainer: FC< disabled={isStepDisabled('componentSelection')} >
- {getSelectedComponents(selectedComponents ?? []).map( + {getSelectedComponents(componentsList ?? []).map( (component) => ( ; export type Labels = Record; -export interface ComponentSelectionItem { +export interface ComponentsListItem { name: string; versions: string[]; isSelected: boolean; @@ -68,7 +68,7 @@ export const CreateManagedControlPlane = ( chargingTarget?: string; chargingTargetType?: string; members?: Member[]; - selectedComponents?: ComponentSelectionItem[]; + selectedComponents?: ComponentsListItem[]; }, idpPrefix?: string, ): CreateManagedControlPlaneType => { From 30eec39a586ecd9aaefc1b7bc86800ba98a6d44c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Goral?= Date: Mon, 7 Jul 2025 16:51:07 +0200 Subject: [PATCH 16/18] refactor --- .../ComponentsSelection.tsx | 188 +++++++++++------- .../ComponentsSelectionContainer.tsx | 79 +++++--- ...eateManagedControlPlaneWizardContainer.tsx | 13 +- 3 files changed, 165 insertions(+), 115 deletions(-) diff --git a/src/components/ComponentsSelection/ComponentsSelection.tsx b/src/components/ComponentsSelection/ComponentsSelection.tsx index bb0f72a2..99cb29b6 100644 --- a/src/components/ComponentsSelection/ComponentsSelection.tsx +++ b/src/components/ComponentsSelection/ComponentsSelection.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useMemo, useCallback } from 'react'; import { CheckBox, Select, @@ -34,42 +34,65 @@ export const ComponentsSelection: React.FC = ({ }) => { const [searchTerm, setSearchTerm] = useState(''); const { t } = useTranslation(); - const handleSelectionChange = ( - e: Ui5CustomEvent, - ) => { - const id = e.target?.id; - setComponentsList( - componentsList.map((component) => - component.name === id - ? { ...component, isSelected: !component.isSelected } - : component, - ), + + const selectedComponents = useMemo( + () => getSelectedComponents(componentsList), + [componentsList], + ); + + const searchResults = useMemo(() => { + const lowerSearch = searchTerm.toLowerCase(); + return componentsList.filter(({ name }) => + name.toLowerCase().includes(lowerSearch), ); - }; + }, [componentsList, searchTerm]); - const handleSearch = (e: Ui5CustomEvent) => { + const handleSelectionChange = useCallback( + (e: Ui5CustomEvent) => { + const id = e.target?.id; + if (!id) return; + setComponentsList( + componentsList.map((component) => + component.name === id + ? { ...component, isSelected: !component.isSelected } + : component, + ), + ); + }, + [componentsList, setComponentsList], + ); + + const handleSearch = useCallback((e: Ui5CustomEvent) => { setSearchTerm(e.target.value.trim()); - }; + }, []); - const handleVersionChange = ( - e: Ui5CustomEvent, - ) => { - const selectedOption = e.detail.selectedOption as HTMLElement; - const name = selectedOption.dataset.name; - const version = selectedOption.dataset.version; - setComponentsList( - componentsList.map((component) => - component.name === name - ? { ...component, selectedVersion: version || '' } - : component, - ), - ); - }; + const handleVersionChange = useCallback( + (e: Ui5CustomEvent) => { + const selectedOption = e.detail.selectedOption as HTMLElement; + const name = selectedOption.dataset.name; + const version = selectedOption.dataset.version; + if (!name) return; + setComponentsList( + componentsList.map((component) => + component.name === name + ? { ...component, selectedVersion: version || '' } + : component, + ), + ); + }, + [componentsList, setComponentsList], + ); - const searchResults = componentsList.filter(({ name }) => - name.toLowerCase().includes(searchTerm.toLowerCase()), + const isProviderDisabled = useCallback( + (component: ComponentsListItem) => { + if (!component.name?.includes('provider')) return false; + const crossplane = componentsList.find( + ({ name }) => name === 'crossplane', + ); + return crossplane?.isSelected === false; + }, + [componentsList], ); - const selectedComponents = getSelectedComponents(componentsList); return (
@@ -80,62 +103,75 @@ export const ComponentsSelection: React.FC = ({ id="search" showClearIcon icon={} + value={searchTerm} + aria-label={t('common.search')} onInput={handleSearch} />
- {searchResults.map((component) => { - const isProviderDisabled = - component.name?.includes('provider') && - componentsList?.find(({ name }) => name === 'crossplane') - ?.isSelected === false; - return ( - - + {searchResults.length > 0 ? ( + searchResults.map((component) => { + const providerDisabled = isProviderDisabled(component); + return ( - {/*This button will be implemented later*/} - {component.documentationUrl && ( - - )} - + {t('common.documentation')} + + )} + + - - ); - })} + ); + }) + ) : ( + + {t('componentsSelection.pleaseSelectComponents')} + + )}
{selectedComponents.length > 0 ? ( @@ -149,7 +185,7 @@ export const ComponentsSelection: React.FC = ({ ))} ) : ( - + {t('componentsSelection.pleaseSelectComponents')} )} diff --git a/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx b/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx index ab1b3a2e..1e0e4fbf 100644 --- a/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx +++ b/src/components/ComponentsSelection/ComponentsSelectionContainer.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useRef } from 'react'; import { ComponentsSelection } from './ComponentsSelection.tsx'; import IllustratedError from '../Shared/IllustratedError.tsx'; @@ -15,17 +15,22 @@ export interface ComponentsSelectionProps { setComponentsList: (components: ComponentsListItem[]) => void; } -// get selected components and when Crossplane is selected then also providers -export const getSelectedComponents = (components: ComponentsListItem[]) => - components.filter( - (component) => - component.isSelected && - !( - component.name?.includes('provider') && - components?.find(({ name }) => name === 'crossplane')?.isSelected === - false - ), +/** + * Returns the selected components. If Crossplane is not selected, + * provider components are excluded. + */ +export const getSelectedComponents = (components: ComponentsListItem[]) => { + const isCrossplaneSelected = components.some( + ({ name, isSelected }) => name === 'crossplane' && isSelected, ); + return components.filter((component) => { + if (!component.isSelected) return false; + if (component.name?.includes('provider') && !isCrossplaneSelected) { + return false; + } + return true; + }); +}; export const ComponentsSelectionContainer: React.FC< ComponentsSelectionProps @@ -35,44 +40,52 @@ export const ComponentsSelectionContainer: React.FC< error, isLoading, } = useApiResource(ListManagedComponents()); - const [isReady, setIsReady] = useState(false); const { t } = useTranslation(); + const initialized = useRef(false); + useEffect(() => { if ( - availableManagedComponentsListData?.items.length === 0 || + initialized.current || !availableManagedComponentsListData?.items || - isReady - ) + availableManagedComponentsListData.items.length === 0 + ) { return; + } - setComponentsList( - availableManagedComponentsListData?.items?.map((item) => { + const newComponentsList = availableManagedComponentsListData.items.map( + (item) => { const versions = sortVersions(item.status.versions); return { name: item.metadata.name, - versions: versions, - selectedVersion: versions[0], + versions, + selectedVersion: versions[0] ?? '', isSelected: false, documentationUrl: '', }; - }) ?? [], + }, ); - setIsReady(true); - }, [availableManagedComponentsListData, isReady, setComponentsList]); + + setComponentsList(newComponentsList); + initialized.current = true; + }, [availableManagedComponentsListData, setComponentsList]); + if (isLoading) { return ; } - if (error) return ; + + if (error) { + return ; + } + + // Defensive: If the API returned no items, show error + if (!componentsList || componentsList.length === 0) { + return ; + } + return ( - <> - {componentsList.length > 0 ? ( - - ) : ( - - )} - + ); }; diff --git a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx index 88adb12a..d6b0d76e 100644 --- a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx +++ b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx @@ -33,7 +33,6 @@ import { CreateManagedControlPlaneType, } from '../../lib/api/types/crate/createManagedControlPlane.ts'; import { ErrorDialog, ErrorDialogHandle } from '../Shared/ErrorMessageBox.tsx'; - import { EditMembers } from '../Members/EditMembers.tsx'; import { useTranslation } from 'react-i18next'; import { MetadataForm } from '../Dialogs/MetadataForm.tsx'; @@ -43,7 +42,6 @@ import { getSelectedComponents, } from '../ComponentsSelection/ComponentsSelectionContainer.tsx'; import { CreateDialogProps } from '../Dialogs/CreateWorkspaceDialogContainer.tsx'; - import { idpPrefix } from '../../utils/idpPrefix.ts'; type CreateManagedControlPlaneWizardContainerProps = { @@ -138,6 +136,7 @@ export const CreateManagedControlPlaneWizardContainer: FC< CreateManagedControlPlaneResource(projectName, workspaceName), ); const componentsList = watch('selectedComponents'); + const handleCreateManagedControlPlane = useCallback( async ({ name, @@ -263,7 +262,9 @@ export const CreateManagedControlPlaneWizardContainer: FC< } }, [selectedStep]); - return isOpen ? ( + if (!isOpen) return null; + + return ( - ) : null; + ); }; From a0e593ffd08f237d9df75367d35e7540811f7ed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Goral?= Date: Tue, 8 Jul 2025 11:29:25 +0200 Subject: [PATCH 17/18] refactor --- .../Dialogs/CreateWorkspaceDialogContainer.tsx | 2 +- .../CreateManagedControlPlaneWizardContainer.tsx | 12 +++++------- src/lib/api/types/crate/createManagedControlPlane.ts | 8 ++++---- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx b/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx index d4c36ca6..3b794a92 100644 --- a/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx +++ b/src/components/Dialogs/CreateWorkspaceDialogContainer.tsx @@ -31,7 +31,7 @@ export type CreateDialogProps = { chargingTarget?: string; chargingTargetType?: string; members: Member[]; - selectedComponents?: ComponentsListItem[]; + componentsList?: ComponentsListItem[]; }; export function CreateWorkspaceDialogContainer({ diff --git a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx index d6b0d76e..cba547df 100644 --- a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx +++ b/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx @@ -92,7 +92,7 @@ export const CreateManagedControlPlaneWizardContainer: FC< chargingTarget: '', chargingTargetType: '', members: [], - selectedComponents: [], + componentsList: [], }, mode: 'onChange', }); @@ -135,7 +135,7 @@ export const CreateManagedControlPlaneWizardContainer: FC< const { trigger } = useApiResourceMutation( CreateManagedControlPlaneResource(projectName, workspaceName), ); - const componentsList = watch('selectedComponents'); + const componentsList = watch('componentsList'); const handleCreateManagedControlPlane = useCallback( async ({ @@ -153,7 +153,7 @@ export const CreateManagedControlPlaneWizardContainer: FC< displayName, chargingTarget, members, - selectedComponents: componentsList, + componentsList, }, idpPrefix, ), @@ -220,7 +220,7 @@ export const CreateManagedControlPlaneWizardContainer: FC< const setComponentsList = useCallback( (components: ComponentsListItem[]) => { - setValue('selectedComponents', components, { shouldValidate: false }); + setValue('componentsList', components, { shouldValidate: false }); }, [setValue], ); @@ -401,9 +401,7 @@ export const CreateManagedControlPlaneWizardContainer: FC< displayName: getValues('displayName'), chargingTarget: getValues('chargingTarget'), members: getValues('members'), - selectedComponents: getSelectedComponents( - componentsList ?? [], - ), + componentsList: componentsList ?? [], }, idpPrefix, ), diff --git a/src/lib/api/types/crate/createManagedControlPlane.ts b/src/lib/api/types/crate/createManagedControlPlane.ts index 4aeff6cd..7720edf8 100644 --- a/src/lib/api/types/crate/createManagedControlPlane.ts +++ b/src/lib/api/types/crate/createManagedControlPlane.ts @@ -68,12 +68,12 @@ export const CreateManagedControlPlane = ( chargingTarget?: string; chargingTargetType?: string; members?: Member[]; - selectedComponents?: ComponentsListItem[]; + componentsList?: ComponentsListItem[]; }, idpPrefix?: string, ): CreateManagedControlPlaneType => { const selectedComponentsListObject: Components = - optional?.selectedComponents + optional?.componentsList ?.filter( (component) => component.isSelected && @@ -84,12 +84,12 @@ export const CreateManagedControlPlane = ( acc[item.name] = { version: item.selectedVersion }; return acc; }, {} as Components) ?? {}; - const crossplaneComponent = optional?.selectedComponents?.find( + const crossplaneComponent = optional?.componentsList?.find( ({ name, isSelected }) => name === 'crossplane' && isSelected, ); const providersListObject: Provider[] = - optional?.selectedComponents + optional?.componentsList ?.filter( ({ name, isSelected }) => name.includes('provider') && isSelected, ) From 1ed654fd38b185d73f0306da884a69f7f8f5841d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Goral?= Date: Tue, 8 Jul 2025 13:19:14 +0200 Subject: [PATCH 18/18] refactor --- .../ControlPlaneListWorkspaceGridTile.tsx | 2 +- ...eateManagedControlPlaneWizardContainer.tsx | 116 +++++------------- .../SummarizeStep.tsx | 93 ++++++++++++++ 3 files changed, 123 insertions(+), 88 deletions(-) rename src/components/Wizards/{ => CreateManagedControlPlane}/CreateManagedControlPlaneWizardContainer.tsx (72%) create mode 100644 src/components/Wizards/CreateManagedControlPlane/SummarizeStep.tsx diff --git a/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx b/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx index 47b9a283..bd014ac9 100644 --- a/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx +++ b/src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx @@ -39,7 +39,7 @@ import { useLink } from '../../../lib/shared/useLink.ts'; import IllustrationMessageType from '@ui5/webcomponents-fiori/dist/types/IllustrationMessageType.js'; import styles from './WorkspacesList.module.css'; import { ControlPlanesListMenu } from '../ControlPlanesListMenu.tsx'; -import { CreateManagedControlPlaneWizardContainer } from '../../Wizards/CreateManagedControlPlaneWizardContainer.tsx'; +import { CreateManagedControlPlaneWizardContainer } from '../../Wizards/CreateManagedControlPlane/CreateManagedControlPlaneWizardContainer.tsx'; interface Props { projectName: string; diff --git a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx b/src/components/Wizards/CreateManagedControlPlane/CreateManagedControlPlaneWizardContainer.tsx similarity index 72% rename from src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx rename to src/components/Wizards/CreateManagedControlPlane/CreateManagedControlPlaneWizardContainer.tsx index cba547df..ebef018e 100644 --- a/src/components/Wizards/CreateManagedControlPlaneWizardContainer.tsx +++ b/src/components/Wizards/CreateManagedControlPlane/CreateManagedControlPlaneWizardContainer.tsx @@ -1,48 +1,47 @@ import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { useApiResourceMutation } from '../../lib/api/useApiResource'; + import IllustrationMessageType from '@ui5/webcomponents-fiori/dist/types/IllustrationMessageType.js'; -import { useAuthOnboarding } from '../../spaces/onboarding/auth/AuthContextOnboarding.tsx'; -import { Member, MemberRoles } from '../../lib/api/types/shared/members.ts'; + import type { WizardStepChangeEventDetail } from '@ui5/webcomponents-fiori/dist/Wizard.js'; import { zodResolver } from '@hookform/resolvers/zod'; import { useForm } from 'react-hook-form'; -import { validationSchemaCreateManagedControlPlane } from '../../lib/api/validations/schemas.ts'; -import { OnCreatePayload } from '../Dialogs/CreateProjectWorkspaceDialog.tsx'; + import { Bar, Button, Dialog, Form, FormGroup, - Grid, - List, - ListItemStandard, - Title, Ui5CustomEvent, Wizard, WizardDomRef, WizardStep, } from '@ui5/webcomponents-react'; -import YamlViewer from '../Yaml/YamlViewer.tsx'; -import { stringify } from 'yaml'; -import { APIError } from '../../lib/api/error.ts'; + +import { SummarizeStep } from './SummarizeStep.tsx'; +import { useTranslation } from 'react-i18next'; +import { useAuthOnboarding } from '../../../spaces/onboarding/auth/AuthContextOnboarding.tsx'; +import { + ErrorDialog, + ErrorDialogHandle, +} from '../../Shared/ErrorMessageBox.tsx'; +import { CreateDialogProps } from '../../Dialogs/CreateWorkspaceDialogContainer.tsx'; +import { validationSchemaCreateManagedControlPlane } from '../../../lib/api/validations/schemas.ts'; +import { Member, MemberRoles } from '../../../lib/api/types/shared/members.ts'; +import { useApiResourceMutation } from '../../../lib/api/useApiResource.ts'; import { ComponentsListItem, CreateManagedControlPlane, CreateManagedControlPlaneResource, CreateManagedControlPlaneType, -} from '../../lib/api/types/crate/createManagedControlPlane.ts'; -import { ErrorDialog, ErrorDialogHandle } from '../Shared/ErrorMessageBox.tsx'; -import { EditMembers } from '../Members/EditMembers.tsx'; -import { useTranslation } from 'react-i18next'; -import { MetadataForm } from '../Dialogs/MetadataForm.tsx'; -import { IllustratedBanner } from '../Ui/IllustratedBanner/IllustratedBanner.tsx'; -import { - ComponentsSelectionContainer, - getSelectedComponents, -} from '../ComponentsSelection/ComponentsSelectionContainer.tsx'; -import { CreateDialogProps } from '../Dialogs/CreateWorkspaceDialogContainer.tsx'; -import { idpPrefix } from '../../utils/idpPrefix.ts'; +} from '../../../lib/api/types/crate/createManagedControlPlane.ts'; +import { OnCreatePayload } from '../../Dialogs/CreateProjectWorkspaceDialog.tsx'; +import { idpPrefix } from '../../../utils/idpPrefix.ts'; +import { APIError } from '../../../lib/api/error.ts'; +import { MetadataForm } from '../../Dialogs/MetadataForm.tsx'; +import { EditMembers } from '../../Members/EditMembers.tsx'; +import { ComponentsSelectionContainer } from '../../ComponentsSelection/ComponentsSelectionContainer.tsx'; +import { IllustratedBanner } from '../../Ui/IllustratedBanner/IllustratedBanner.tsx'; type CreateManagedControlPlaneWizardContainerProps = { isOpen: boolean; @@ -347,69 +346,12 @@ export const CreateManagedControlPlaneWizardContainer: FC< selected={selectedStep === 'summarize'} data-step="summarize" > - {t('common.summarize')} - -
- - - - - - -
- - {getValues('members').map((member) => ( - - ))} - -
- - {getSelectedComponents(componentsList ?? []).map( - (component) => ( - - ), - )} - -
-
- -
-
+ ; + projectName: string; + workspaceName: string; + componentsList?: ComponentsListItem[]; +} + +export const SummarizeStep: React.FC = ({ + getValues, + projectName, + workspaceName, + componentsList, +}) => { + const { t } = useTranslation(); + return ( + <> + {t('common.summarize')} + +
+ + + + + + +
+ + {getValues('members').map((member) => ( + + ))} + +
+ + {getSelectedComponents(componentsList ?? []).map((component) => ( + + ))} + +
+
+ +
+
+ + ); +};