From 4a5002a31c369024c2fa2e4ac9673a33efaaeba8 Mon Sep 17 00:00:00 2001 From: Agata Kucharska Date: Wed, 24 Jul 2024 15:47:31 +0200 Subject: [PATCH 1/5] Edit modules --- public/i18n/en.yaml | 1 + .../KymaModules/KymaModulesCreate.js | 203 +++++++++++++++++- .../KymaModules/KymaModulesCreate.scss | 18 ++ src/components/KymaModules/ModulesCard.js | 1 + .../components/CollapsibleSection.js | 18 +- 5 files changed, 232 insertions(+), 9 deletions(-) diff --git a/public/i18n/en.yaml b/public/i18n/en.yaml index 96c06fd087..886d2bf367 100644 --- a/public/i18n/en.yaml +++ b/public/i18n/en.yaml @@ -952,6 +952,7 @@ kyma-modules: module-added: Module added module-uninstall: Module deleted module-documentation: Documentation + modules-channel: Modules Channel learn-more: Learn more add-module: Add Modules modify: Modify diff --git a/src/components/KymaModules/KymaModulesCreate.js b/src/components/KymaModules/KymaModulesCreate.js index 8a2b1a9fdc..f6014c07fb 100644 --- a/src/components/KymaModules/KymaModulesCreate.js +++ b/src/components/KymaModules/KymaModulesCreate.js @@ -1,6 +1,9 @@ import { cloneDeep } from 'lodash'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { useGet } from 'shared/hooks/BackendAPI/useGet'; +import { MessageStrip, Option, Select, Text } from '@ui5/webcomponents-react'; +import { spacing } from '@ui5/webcomponents-react-base'; import { ResourceForm } from 'shared/ResourceForm'; import './KymaModulesCreate.scss'; @@ -11,6 +14,171 @@ export default function KymaModulesCreate({ resource, ...props }) { const [initialResource] = useState(resource); const [initialUnchangedResource] = useState(resource); + const resourceName = kymaResource?.metadata.name; + const modulesResourceUrl = `/apis/operator.kyma-project.io/v1beta2/moduletemplates`; + + const { data: modules } = useGet(modulesResourceUrl, { + pollingInterval: 3000, + skip: !resourceName, + }); + + const [selectedModules] = useState(initialResource?.spec?.modules ?? []); + + const setChannel = (module, channel, index) => { + if ( + selectedModules.find( + selectedModule => selectedModule.name === module.name, + ) + ) { + if (channel === 'predefined') { + delete selectedModules[index].channel; + } else selectedModules[index].channel = channel; + } else { + selectedModules.push({ + name: module.name, + }); + if (channel !== 'predefined') + selectedModules[selectedModules.length - 1].channel = channel; + } + + setKymaResource({ + ...kymaResource, + spec: { + ...kymaResource.spec, + modules: selectedModules, + }, + }); + }; + const installedModules = modules?.items.filter(module => { + const name = + module.metadata?.labels['operator.kyma-project.io/module-name']; + return ( + selectedModules?.findIndex(kymaResourceModule => { + return kymaResourceModule.name === name; + }) !== -1 + ); + }); + + const modulesEditData = (installedModules || []).reduce((acc, module) => { + const name = + module.metadata?.labels['operator.kyma-project.io/module-name']; + const existingModule = acc.find(item => item.name === name); + + if (!existingModule) { + acc.push({ + name: name, + channels: [ + { + channel: module.spec.channel, + version: module.spec.descriptor.component.version, + isBeta: + module.metadata.labels['operator.kyma-project.io/beta'] === + 'true', + }, + ], + docsUrl: + module.metadata.annotations['operator.kyma-project.io/doc-url'], + }); + } else { + existingModule.channels?.push({ + channel: module.spec.channel, + version: module.spec.descriptor.component.version, + isBeta: + module.metadata.labels['operator.kyma-project.io/beta'] === 'true', + }); + } + return acc; + }, []); + + const findStatus = moduleName => { + return kymaResource?.status?.modules?.find( + module => moduleName === module.name, + ); + }; + + const findSpec = moduleName => { + return kymaResource?.spec.modules?.find( + module => moduleName === module.name, + ); + }; + + const checkIfSelectedModuleIsBeta = moduleName => { + return selectedModules.some(({ name, channel }) => { + if (moduleName && name !== moduleName) { + return false; + } + const moduleData = modulesEditData?.find(module => module.name === name); + return moduleData + ? moduleData.channels.some( + ({ channel: ch, isBeta }) => ch === channel && isBeta, + ) + : false; + }); + }; + const renderCards = () => { + const cards = []; + modulesEditData?.forEach((module, i) => { + const index = selectedModules?.findIndex(selectedModule => { + return selectedModule.name === module?.name; + }); + + const card = ( + <> + {module.name} + + + ); + cards.push(card); + }); + + return ( +
+ {cards} +
+ ); + }; + return ( + disableDefaultFields + > + + {modulesEditData?.length !== 0 ? ( + <> + {checkIfSelectedModuleIsBeta() ? ( + + {t('kyma-modules.beta-alert')} + + ) : null} + {renderCards()} + + ) : ( + + {t('extensibility.widgets.modules.no-modules')} + + )} + + ); } diff --git a/src/components/KymaModules/KymaModulesCreate.scss b/src/components/KymaModules/KymaModulesCreate.scss index 3103671bea..325caea21b 100644 --- a/src/components/KymaModules/KymaModulesCreate.scss +++ b/src/components/KymaModules/KymaModulesCreate.scss @@ -16,5 +16,23 @@ .yaml-form { height: calc(100vh - 20rem); } + + .gridbox-editModule { + display: grid; + gap: 16px; + } + + .channel-select { + width: 100%; + } + + .collapsible-margins { + padding: 0; + padding-left: 0; + padding-right: 0; + margin-top: 1rem; + margin-left: -1rem; + margin-right: -1rem; + } } } diff --git a/src/components/KymaModules/ModulesCard.js b/src/components/KymaModules/ModulesCard.js index 08411eb1aa..1ae7618a65 100644 --- a/src/components/KymaModules/ModulesCard.js +++ b/src/components/KymaModules/ModulesCard.js @@ -9,6 +9,7 @@ import { Text, Title, } from '@ui5/webcomponents-react'; +import '@ui5/webcomponents/dist/features/InputElementsFormSupport.js'; import { ExternalLink } from 'shared/components/ExternalLink/ExternalLink'; import { useTranslation } from 'react-i18next'; import { spacing } from '@ui5/webcomponents-react-base'; diff --git a/src/shared/ResourceForm/components/CollapsibleSection.js b/src/shared/ResourceForm/components/CollapsibleSection.js index 4874aa7bdd..d4c5bd0b52 100644 --- a/src/shared/ResourceForm/components/CollapsibleSection.js +++ b/src/shared/ResourceForm/components/CollapsibleSection.js @@ -10,6 +10,7 @@ export function CollapsibleSection({ defaultOpen = undefined, canChangeState = true, title, + defaultTitleType = false, actions, children, resource, @@ -68,13 +69,16 @@ export function CollapsibleSection({ onClick={toggle} aria-label={`expand ${title}`} > - + {!defaultTitleType && ( + <Title + tooltipContent={tooltipContent} + title={title} + disabled={disabled} + canChangeState={canChangeState} + required={required} + /> + )} + {defaultTitleType && title} {actions && ( <> <ToolbarSpacer /> From 0f24c277d4bbf108cfdb63b58ab67ffb6d62c7fc Mon Sep 17 00:00:00 2001 From: Agata Kucharska <agata.kucharska@sap.com> Date: Thu, 25 Jul 2024 08:16:06 +0200 Subject: [PATCH 2/5] Adjust styles --- src/components/KymaModules/KymaModulesCreate.js | 4 ++-- src/components/KymaModules/KymaModulesCreate.scss | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/KymaModules/KymaModulesCreate.js b/src/components/KymaModules/KymaModulesCreate.js index f6014c07fb..09e97c2365 100644 --- a/src/components/KymaModules/KymaModulesCreate.js +++ b/src/components/KymaModules/KymaModulesCreate.js @@ -2,7 +2,7 @@ import { cloneDeep } from 'lodash'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useGet } from 'shared/hooks/BackendAPI/useGet'; -import { MessageStrip, Option, Select, Text } from '@ui5/webcomponents-react'; +import { Label, MessageStrip, Option, Select } from '@ui5/webcomponents-react'; import { spacing } from '@ui5/webcomponents-react-base'; import { ResourceForm } from 'shared/ResourceForm'; @@ -124,7 +124,7 @@ export default function KymaModulesCreate({ resource, ...props }) { const card = ( <> - <Text>{module.name}</Text> + <Label>{module.name}</Label> <Select onChange={event => { setChannel(module, event.detail.selectedOption.value, index); diff --git a/src/components/KymaModules/KymaModulesCreate.scss b/src/components/KymaModules/KymaModulesCreate.scss index 325caea21b..64346ec7ca 100644 --- a/src/components/KymaModules/KymaModulesCreate.scss +++ b/src/components/KymaModules/KymaModulesCreate.scss @@ -19,7 +19,7 @@ .gridbox-editModule { display: grid; - gap: 16px; + gap: 0.5rem; } .channel-select { From 2a082aa60b92d79291e7f3a0cce458c802c1b7a6 Mon Sep 17 00:00:00 2001 From: Agata Kucharska <agata.kucharska@sap.com> Date: Thu, 25 Jul 2024 14:16:19 +0200 Subject: [PATCH 3/5] Show in 2 columns --- public/i18n/en.yaml | 1 + .../KymaModules/KymaModulesCreate.js | 34 +++++++++++-------- .../KymaModules/KymaModulesCreate.scss | 4 +-- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/public/i18n/en.yaml b/public/i18n/en.yaml index 886d2bf367..0467720b9e 100644 --- a/public/i18n/en.yaml +++ b/public/i18n/en.yaml @@ -793,6 +793,7 @@ extensibility: error: The table widget configuration is incorrect. Path value must be an array type. modules: no-modules: No modules available + no-modules-installed: No modules installed documentation: DOCUMENTATION module-channel-label: Module channel overwrite module-channel-placeholder: Uses Default Kyma Channel diff --git a/src/components/KymaModules/KymaModulesCreate.js b/src/components/KymaModules/KymaModulesCreate.js index 09e97c2365..d4aecf0f06 100644 --- a/src/components/KymaModules/KymaModulesCreate.js +++ b/src/components/KymaModules/KymaModulesCreate.js @@ -2,7 +2,13 @@ import { cloneDeep } from 'lodash'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useGet } from 'shared/hooks/BackendAPI/useGet'; -import { Label, MessageStrip, Option, Select } from '@ui5/webcomponents-react'; +import { + FlexBox, + Label, + MessageStrip, + Option, + Select, +} from '@ui5/webcomponents-react'; import { spacing } from '@ui5/webcomponents-react-base'; import { ResourceForm } from 'shared/ResourceForm'; @@ -115,15 +121,19 @@ export default function KymaModulesCreate({ resource, ...props }) { : false; }); }; - const renderCards = () => { - const cards = []; + const renderModules = () => { + const modulesList = []; modulesEditData?.forEach((module, i) => { const index = selectedModules?.findIndex(selectedModule => { return selectedModule.name === module?.name; }); - const card = ( - <> + const mod = ( + <FlexBox + direction="Column" + style={{ gap: '0.5rem' }} + key={module?.name} + > <Label>{module.name}</Label> <Select onChange={event => { @@ -167,16 +177,12 @@ export default function KymaModulesCreate({ resource, ...props }) { </Option> ))} </Select> - </> + </FlexBox> ); - cards.push(card); + modulesList.push(mod); }); - return ( - <div className="gridbox-editModule" style={spacing.sapUiSmallMarginTop}> - {cards} - </div> - ); + return <div className="gridbox-editModule">{modulesList}</div>; }; return ( @@ -210,7 +216,7 @@ export default function KymaModulesCreate({ resource, ...props }) { {t('kyma-modules.beta-alert')} </MessageStrip> ) : null} - {renderCards()} + {renderModules()} </> ) : ( <MessageStrip @@ -218,7 +224,7 @@ export default function KymaModulesCreate({ resource, ...props }) { hideCloseButton style={spacing.sapUiSmallMarginTop} > - {t('extensibility.widgets.modules.no-modules')} + {t('extensibility.widgets.modules.no-modules-installed')} </MessageStrip> )} </ResourceForm.CollapsibleSection> diff --git a/src/components/KymaModules/KymaModulesCreate.scss b/src/components/KymaModules/KymaModulesCreate.scss index 64346ec7ca..61690ba05e 100644 --- a/src/components/KymaModules/KymaModulesCreate.scss +++ b/src/components/KymaModules/KymaModulesCreate.scss @@ -19,7 +19,8 @@ .gridbox-editModule { display: grid; - gap: 0.5rem; + grid-template-columns: 3fr 3fr; + gap: 0.5rem 1rem; } .channel-select { @@ -30,7 +31,6 @@ padding: 0; padding-left: 0; padding-right: 0; - margin-top: 1rem; margin-left: -1rem; margin-right: -1rem; } From 22b2cf8635da73c2ef109a93f2fb3f4b88ca4f9a Mon Sep 17 00:00:00 2001 From: Agata Kucharska <agata.kucharska@sap.com> Date: Fri, 26 Jul 2024 15:51:39 +0200 Subject: [PATCH 4/5] Show confirmation on first save when channels changed --- public/i18n/en.yaml | 3 + .../KymaModules/KymaModulesCreate.js | 236 ++++++++++++++---- .../ResourceForm/components/ResourceForm.js | 2 + src/shared/ResourceForm/useCreateResource.js | 16 +- 4 files changed, 208 insertions(+), 49 deletions(-) diff --git a/public/i18n/en.yaml b/public/i18n/en.yaml index 0467720b9e..62a71962be 100644 --- a/public/i18n/en.yaml +++ b/public/i18n/en.yaml @@ -972,6 +972,9 @@ kyma-modules: channel-overridden: Overridden beta: Beta beta-alert: "CAUTION: The Service Level Agreements (SLAs) and Support obligations do not apply to Beta modules and functionalities. If Beta modules or functionalities directly or indirectly affect other modules, the Service Level Agreements and Support for these modules are limited to priority levels P3 (Medium) or P4 (Low). Thus, Beta releases are not intended for use in customer production environments." + change: Change + change-release-channel: Change Release Channel + change-release-channel-warning: The module's version in the fast channel is usually higher than the version in the regular channel. As downgrades are not supported, switching the channel back to regular will not affect the module's version <0>until the channel version is the same or higher.</0> To use the lower version, you must delete the module and re-add it from the <0>regular</0> channel. legal: copyright: Copyright legal-disclosure: Legal Disclosure diff --git a/src/components/KymaModules/KymaModulesCreate.js b/src/components/KymaModules/KymaModulesCreate.js index d4aecf0f06..1adddbe5b9 100644 --- a/src/components/KymaModules/KymaModulesCreate.js +++ b/src/components/KymaModules/KymaModulesCreate.js @@ -1,10 +1,24 @@ +import { createPortal } from 'react-dom'; import { cloneDeep } from 'lodash'; import { useState } from 'react'; -import { useTranslation } from 'react-i18next'; +import { createPatch } from 'rfc6902'; +import { useRecoilState } from 'recoil'; +import { useTranslation, Trans } from 'react-i18next'; +import { useUrl } from 'hooks/useUrl'; + +import { useNotification } from 'shared/contexts/NotificationContext'; import { useGet } from 'shared/hooks/BackendAPI/useGet'; +import { useUpdate } from 'shared/hooks/BackendAPI/useMutation'; +import { useSingleGet } from 'shared/hooks/BackendAPI/useGet'; +import { HttpError } from 'shared/hooks/BackendAPI/config'; +import { columnLayoutState } from 'state/columnLayoutAtom'; +import { ForceUpdateModalContent } from 'shared/ResourceForm/ForceUpdateModalContent'; + import { + Button, FlexBox, Label, + MessageBox, MessageStrip, Option, Select, @@ -18,7 +32,7 @@ export default function KymaModulesCreate({ resource, ...props }) { const { t } = useTranslation(); const [kymaResource, setKymaResource] = useState(cloneDeep(resource)); const [initialResource] = useState(resource); - const [initialUnchangedResource] = useState(resource); + const [initialUnchangedResource] = useState(cloneDeep(resource)); const resourceName = kymaResource?.metadata.name; const modulesResourceUrl = `/apis/operator.kyma-project.io/v1beta2/moduletemplates`; @@ -28,7 +42,18 @@ export default function KymaModulesCreate({ resource, ...props }) { skip: !resourceName, }); + const [layoutColumn, setLayoutColumn] = useRecoilState(columnLayoutState); + const notification = useNotification(); + const { scopedUrl } = useUrl(); + + const getRequest = useSingleGet(); + const patchRequest = useUpdate(); const [selectedModules] = useState(initialResource?.spec?.modules ?? []); + const [isEdited, setIsEdited] = useState(false); + const [showMessageBox, setShowMessageBox] = useState({ + isOpen: false, + hide: false, + }); const setChannel = (module, channel, index) => { if ( @@ -54,6 +79,7 @@ export default function KymaModulesCreate({ resource, ...props }) { modules: selectedModules, }, }); + setIsEdited(true); }; const installedModules = modules?.items.filter(module => { const name = @@ -121,6 +147,7 @@ export default function KymaModulesCreate({ resource, ...props }) { : false; }); }; + const renderModules = () => { const modulesList = []; modulesEditData?.forEach((module, i) => { @@ -185,49 +212,170 @@ export default function KymaModulesCreate({ resource, ...props }) { return <div className="gridbox-editModule">{modulesList}</div>; }; + const showError = error => { + console.error(error); + notification.notifyError({ + content: t('common.create-form.messages.patch-failure', { + resourceType: t('kyma-modules.kyma'), + error: error.message, + }), + }); + }; + + const onSuccess = () => { + notification.notifySuccess({ + content: t('common.create-form.messages.patch-success', { + resourceType: t('kyma-modules.kyma'), + }), + }); + setLayoutColumn({ + ...layoutColumn, + layout: 'OneColumn', + showCreate: null, + endColumn: { + resourceName: kymaResource.metadata.name, + resourceType: kymaResource.kind, + namespaceId: kymaResource.metadata.namespace, + }, + }); + window.history.pushState( + window.history.state, + '', + `${scopedUrl(`kymas/${encodeURIComponent(kymaResource.metadata.name)}`)}`, + ); + }; + const handleCreate = async () => { + try { + const diff = createPatch(initialUnchangedResource, kymaResource); + await patchRequest(props.resourceUrl, diff); + + onSuccess(); + } catch (e) { + const isConflict = e instanceof HttpError && e.code === 409; + if (isConflict) { + const response = await getRequest(props.resourceUrl); + const updatedResource = await response.json(); + + const makeForceUpdateFn = closeModal => { + return async () => { + kymaResource.metadata.resourceVersion = + initialUnchangedResource?.metadata.resourceVersion; + try { + await patchRequest( + props.resourceUrl, + createPatch(initialUnchangedResource, kymaResource), + ); + closeModal(); + onSuccess(); + } catch (e) { + showError(e); + } + }; + }; + + notification.notifyError({ + content: ( + <ForceUpdateModalContent + error={e} + singularName={t('kyma-modules.kyma')} + initialResource={updatedResource} + modifiedResource={kymaResource} + /> + ), + actions: (closeModal, defaultCloseButton) => [ + <Button onClick={makeForceUpdateFn(closeModal)}> + {t('common.create-form.force-update')} + </Button>, + defaultCloseButton(closeModal), + ], + wider: true, + }); + } else { + showError(e); + return false; + } + } + }; + return ( - <ResourceForm - {...props} - className="kyma-modules-create" - pluralKind="kymas" - singularName={t('kyma-modules.kyma')} - resource={kymaResource} - initialResource={initialResource} - initialUnchangedResource={initialUnchangedResource} - setResource={setKymaResource} - createUrl={props.resourceUrl} - disableDefaultFields - > - <ResourceForm.CollapsibleSection - defaultOpen - defaultTitleType - className="collapsible-margins" - title={t('kyma-modules.modules-channel')} + <> + {createPortal( + <MessageBox + type="Warning" + open={showMessageBox.isOpen} + onClose={() => { + setShowMessageBox({ isOpen: false, hide: true }); + }} + titleText={t('kyma-modules.change-release-channel')} + actions={[ + <Button + design="Emphasized" + key="discard" + onClick={() => handleCreate()} + > + {t('kyma-modules.change')} + </Button>, + <Button design="Transparent" key="cancel">{`${t( + 'common.buttons.cancel', + )}`}</Button>, + ]} + > + <Trans i18nKey="kyma-modules.change-release-channel-warning"> + <span style={{ fontWeight: 'bold' }} /> + </Trans> + </MessageBox>, + document.body, + )} + <ResourceForm + {...props} + className="kyma-modules-create" + pluralKind="kymas" + singularName={t('kyma-modules.kyma')} + resource={kymaResource} + initialResource={initialResource} + initialUnchangedResource={initialUnchangedResource} + setResource={setKymaResource} + createUrl={props.resourceUrl} + disableDefaultFields + skipCreateFn={() => { + if (isEdited && !showMessageBox.hide) { + setShowMessageBox({ ...showMessageBox, isOpen: true, hide: true }); + return true; + } + return false; + }} > - {modulesEditData?.length !== 0 ? ( - <> - {checkIfSelectedModuleIsBeta() ? ( - <MessageStrip - key={'beta'} - design="Warning" - hideCloseButton - style={spacing.sapUiTinyMarginTop} - > - {t('kyma-modules.beta-alert')} - </MessageStrip> - ) : null} - {renderModules()} - </> - ) : ( - <MessageStrip - design="Warning" - hideCloseButton - style={spacing.sapUiSmallMarginTop} - > - {t('extensibility.widgets.modules.no-modules-installed')} - </MessageStrip> - )} - </ResourceForm.CollapsibleSection> - </ResourceForm> + <ResourceForm.CollapsibleSection + defaultOpen + defaultTitleType + className="collapsible-margins" + title={t('kyma-modules.modules-channel')} + > + {modulesEditData?.length !== 0 ? ( + <> + {checkIfSelectedModuleIsBeta() ? ( + <MessageStrip + key={'beta'} + design="Warning" + hideCloseButton + style={spacing.sapUiTinyMarginTop} + > + {t('kyma-modules.beta-alert')} + </MessageStrip> + ) : null} + {renderModules()} + </> + ) : ( + <MessageStrip + design="Warning" + hideCloseButton + style={spacing.sapUiSmallMarginTop} + > + {t('extensibility.widgets.modules.no-modules-installed')} + </MessageStrip> + )} + </ResourceForm.CollapsibleSection> + </ResourceForm> + </> ); } diff --git a/src/shared/ResourceForm/components/ResourceForm.js b/src/shared/ResourceForm/components/ResourceForm.js index 6801bbc233..f6fa38bd32 100644 --- a/src/shared/ResourceForm/components/ResourceForm.js +++ b/src/shared/ResourceForm/components/ResourceForm.js @@ -47,6 +47,7 @@ export function ResourceForm({ onPresetSelected, renderEditor, onSubmit, + skipCreateFn, afterCreatedFn, afterCreatedCustomMessage, className, @@ -124,6 +125,7 @@ export function ResourceForm({ resource, initialUnchangedResource, createUrl, + skipCreateFn, afterCreatedFn, urlPath, layoutNumber, diff --git a/src/shared/ResourceForm/useCreateResource.js b/src/shared/ResourceForm/useCreateResource.js index 00544e5622..1e584415d6 100644 --- a/src/shared/ResourceForm/useCreateResource.js +++ b/src/shared/ResourceForm/useCreateResource.js @@ -21,6 +21,7 @@ export function useCreateResource({ resource, initialUnchangedResource, createUrl, + skipCreateFn, afterCreatedFn, urlPath, layoutNumber, @@ -130,11 +131,7 @@ export function useCreateResource({ }); }; - return async e => { - if (e) { - e.preventDefault(); - } - + const handleCreate = async () => { try { if (isEdit) { const diff = createPatch(initialUnchangedResource, resource); @@ -190,4 +187,13 @@ export function useCreateResource({ } } }; + + return async e => { + if (e) { + e.preventDefault(); + } + if (skipCreateFn && skipCreateFn()) { + return null; + } else handleCreate(); + }; } From 3115148e10fb3c80a94ab2c5f8249c8b915b50b8 Mon Sep 17 00:00:00 2001 From: Oliwia Gowor <oliwiagowor@gmail.com> Date: Tue, 30 Jul 2024 08:42:06 +0200 Subject: [PATCH 5/5] fix discard msg & loading --- .../KymaModules/KymaModulesCreate.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/components/KymaModules/KymaModulesCreate.js b/src/components/KymaModules/KymaModulesCreate.js index 1adddbe5b9..bad466a16c 100644 --- a/src/components/KymaModules/KymaModulesCreate.js +++ b/src/components/KymaModules/KymaModulesCreate.js @@ -27,6 +27,7 @@ import { spacing } from '@ui5/webcomponents-react-base'; import { ResourceForm } from 'shared/ResourceForm'; import './KymaModulesCreate.scss'; +import { Spinner } from 'shared/components/Spinner/Spinner'; export default function KymaModulesCreate({ resource, ...props }) { const { t } = useTranslation(); @@ -37,7 +38,7 @@ export default function KymaModulesCreate({ resource, ...props }) { const resourceName = kymaResource?.metadata.name; const modulesResourceUrl = `/apis/operator.kyma-project.io/v1beta2/moduletemplates`; - const { data: modules } = useGet(modulesResourceUrl, { + const { data: modules, loading } = useGet(modulesResourceUrl, { pollingInterval: 3000, skip: !resourceName, }); @@ -48,13 +49,23 @@ export default function KymaModulesCreate({ resource, ...props }) { const getRequest = useSingleGet(); const patchRequest = useUpdate(); - const [selectedModules] = useState(initialResource?.spec?.modules ?? []); + const [selectedModules] = useState( + cloneDeep(initialResource?.spec?.modules) ?? [], + ); const [isEdited, setIsEdited] = useState(false); const [showMessageBox, setShowMessageBox] = useState({ isOpen: false, hide: false, }); + if (loading) { + return ( + <div style={{ height: 'calc(100vh - 14rem)' }}> + <Spinner /> + </div> + ); + } + const setChannel = (module, channel, index) => { if ( selectedModules.find( @@ -161,7 +172,7 @@ export default function KymaModulesCreate({ resource, ...props }) { style={{ gap: '0.5rem' }} key={module?.name} > - <Label>{module.name}</Label> + <Label>{`${module.name}:`}</Label> <Select onChange={event => { setChannel(module, event.detail.selectedOption.value, index); @@ -310,7 +321,7 @@ export default function KymaModulesCreate({ resource, ...props }) { actions={[ <Button design="Emphasized" - key="discard" + key="change" onClick={() => handleCreate()} > {t('kyma-modules.change')}