diff --git a/frontend/locales/en/strings.json b/frontend/locales/en/strings.json index 3f519ee8..9fe35c68 100644 --- a/frontend/locales/en/strings.json +++ b/frontend/locales/en/strings.json @@ -229,6 +229,9 @@ "actions": { "cancel": "Cancel", "create": "Create cluster", + "createFromWizard": "Use interface", + "createFromTemplate": "Upload a template", + "createFromCluster": "From another cluster", "edit": "Edit", "start": "Start fleet", "stop": "Stop fleet", diff --git a/frontend/src/old-pages/Clusters/CreateButtonDropdown/CreateButtonDropdown.tsx b/frontend/src/old-pages/Clusters/CreateButtonDropdown/CreateButtonDropdown.tsx new file mode 100644 index 00000000..c54e119d --- /dev/null +++ b/frontend/src/old-pages/Clusters/CreateButtonDropdown/CreateButtonDropdown.tsx @@ -0,0 +1,131 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance +// with the License. A copy of the License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "LICENSE.txt" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +// OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions and +// limitations under the License. + +import { + ButtonDropdown, + ButtonDropdownProps, +} from '@cloudscape-design/components' +import {CancelableEventHandler} from '@cloudscape-design/components/internal/events' +import React, {useCallback, useMemo} from 'react' +import {useTranslation} from 'react-i18next' +import {NavigateFunction, useNavigate} from 'react-router-dom' +import {GetConfiguration} from '../../../model' +import {setState} from '../../../store' +import loadTemplate from '../../Configure/util' +import {HiddenFileUpload} from '../../../components/HiddenFileUpload' +// @ts-expect-error TS(7016) FIXME: Could not find a declaration file for module 'js-y... Remove this comment to see the full error message +import jsyaml from 'js-yaml' +import {FromClusterModal} from '../FromClusterModal/FromClusterModal' + +const loadingPath = ['app', 'wizard', 'source', 'loading'] + +function copyFrom(sourceClusterName: any) { + setState(loadingPath, true) + GetConfiguration(sourceClusterName, (configuration: any) => { + loadTemplate(jsyaml.load(configuration), () => setState(loadingPath, false)) + }) +} + +interface Props { + openWizard: (navigate: NavigateFunction) => void +} + +export const CreateButtonDropdown: React.FC = ({openWizard}) => { + const {t} = useTranslation() + const [isFileDialogOpen, setIsFileDialogOpen] = React.useState(false) + const [isModalVisible, setIsModalVisible] = React.useState(false) + + const navigate = useNavigate() + + const onModalDismiss = useCallback(() => { + setIsModalVisible(false) + }, []) + + const onCreate = useCallback( + (name: string) => { + copyFrom(name) + openWizard(navigate) + }, + [navigate, openWizard], + ) + + const onFileSelectorDismiss = useCallback(() => { + setIsFileDialogOpen(false) + }, []) + + const onFileChange = useCallback( + (data: string) => { + setIsFileDialogOpen(false) + setState(loadingPath, true) + loadTemplate(jsyaml.load(data), () => setState(loadingPath, false)) + openWizard(navigate) + }, + [navigate, openWizard], + ) + + const onCreateClick: CancelableEventHandler = + React.useCallback( + ({detail}) => { + switch (detail.id) { + case 'wizard': + openWizard(navigate) + return + case 'template': + setIsFileDialogOpen(true) + return + case 'from-cluster': + setIsModalVisible(true) + return + } + }, + [navigate, openWizard], + ) + + const createDropdownItems: ButtonDropdownProps.Item[] = useMemo( + () => [ + { + id: 'wizard', + text: t('cluster.list.actions.createFromWizard'), + }, + { + id: 'template', + text: t('cluster.list.actions.createFromTemplate'), + }, + { + id: 'from-cluster', + text: t('cluster.list.actions.createFromCluster'), + }, + ], + [t], + ) + + return ( + <> + + {t('cluster.list.actions.create')} + + + + + ) +} diff --git a/frontend/src/old-pages/Clusters/CreateButtonDropdown/__tests__/CreateButtonDropdown.test.tsx b/frontend/src/old-pages/Clusters/CreateButtonDropdown/__tests__/CreateButtonDropdown.test.tsx new file mode 100644 index 00000000..a5be7fff --- /dev/null +++ b/frontend/src/old-pages/Clusters/CreateButtonDropdown/__tests__/CreateButtonDropdown.test.tsx @@ -0,0 +1,51 @@ +import wrapper from '@cloudscape-design/components/test-utils/dom' +import {Store} from '@reduxjs/toolkit' +import {render, RenderResult} from '@testing-library/react' +import i18n from 'i18next' +import {mock} from 'jest-mock-extended' +import {I18nextProvider, initReactI18next} from 'react-i18next' +import {Provider} from 'react-redux' +import {BrowserRouter} from 'react-router-dom' +import {CreateButtonDropdown} from '../CreateButtonDropdown' + +i18n.use(initReactI18next).init({ + resources: {}, + lng: 'en', +}) + +const mockStore = mock() + +const MockProviders = (props: any) => ( + + + {props.children} + + +) + +describe('given a dropdown button to create a cluster', () => { + let screen: RenderResult + let mockOpenWizard: jest.Mock + + beforeEach(() => { + mockOpenWizard = jest.fn() + + screen = render( + + + , + ) + }) + + describe('when user selects the option to create a cluster using the wizard', () => { + beforeEach(() => { + const buttonDropdown = wrapper(screen.container).findButtonDropdown()! + buttonDropdown.openDropdown() + buttonDropdown.findItemById('wizard')?.click() + }) + + it('should open the cluster creation wizard', () => { + expect(mockOpenWizard).toHaveBeenCalledTimes(1) + }) + }) +})