diff --git a/x-pack/plugins/spaces/public/management/edit_space/manage_space_page.test.tsx b/x-pack/plugins/spaces/public/management/edit_space/manage_space_page.test.tsx index f169395688de1..ac60902920fa9 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/manage_space_page.test.tsx +++ b/x-pack/plugins/spaces/public/management/edit_space/manage_space_page.test.tsx @@ -98,6 +98,8 @@ describe('ManageSpacePage', () => { nameInput.simulate('change', { target: { value: 'New Space Name' } }); descriptionInput.simulate('change', { target: { value: 'some description' } }); + updateSpace(wrapper, false, 'oblt'); + const createButton = wrapper.find('button[data-test-subj="save-space-button"]'); createButton.simulate('click'); await Promise.resolve(); @@ -110,9 +112,78 @@ describe('ManageSpacePage', () => { color: '#AA6556', imageUrl: '', disabledFeatures: [], + solution: 'oblt', }); }); + it('validates the form (name, initials, solution view...)', async () => { + const spacesManager = spacesManagerMock.create(); + spacesManager.createSpace = jest.fn(spacesManager.createSpace); + spacesManager.getActiveSpace = jest.fn().mockResolvedValue(space); + + const wrapper = mountWithIntl( + + ); + + await waitFor(() => { + wrapper.update(); + expect(wrapper.find('input[name="name"]')).toHaveLength(1); + }); + + const createButton = wrapper.find('button[data-test-subj="save-space-button"]'); + createButton.simulate('click'); + await Promise.resolve(); + + { + const errors = wrapper.find('.euiFormErrorText').map((node) => node.text()); + expect(errors).toEqual([ + 'Enter a name.', + 'Enter a URL identifier.', + 'Enter initials.', + 'Select one solution.', + ]); + + expect(spacesManager.createSpace).not.toHaveBeenCalled(); + + const nameInput = wrapper.find('input[name="name"]'); + nameInput.simulate('change', { target: { value: 'New Space Name' } }); + } + + createButton.simulate('click'); + await Promise.resolve(); + + { + const errors = wrapper.find('.euiFormErrorText').map((node) => node.text()); + expect(errors).toEqual(['Select one solution.']); // requires solution view to be set + } + + updateSpace(wrapper, false, 'oblt'); + + createButton.simulate('click'); + await Promise.resolve(); + + { + const errors = wrapper.find('.euiFormErrorText').map((node) => node.text()); + expect(errors).toEqual([]); // no more errors + } + + expect(spacesManager.createSpace).toHaveBeenCalled(); + }); + it('shows solution view select when visible', async () => { const spacesManager = spacesManagerMock.create(); spacesManager.createSpace = jest.fn(spacesManager.createSpace); diff --git a/x-pack/plugins/spaces/public/management/edit_space/manage_space_page.tsx b/x-pack/plugins/spaces/public/management/edit_space/manage_space_page.tsx index cb81ae9304260..4f45b55fb1630 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/manage_space_page.tsx +++ b/x-pack/plugins/spaces/public/management/edit_space/manage_space_page.tsx @@ -206,6 +206,8 @@ export class ManageSpacePage extends Component { { const originalSpace: Space = this.state.originalSpace as Space; const space: Space = this.state.space as Space; const { haveDisabledFeaturesChanged, hasSolutionViewChanged } = this.state; - const result = this.validator.validateForSave(space); + const result = this.validator.validateForSave( + space, + this.editingExistingSpace(), + this.props.allowSolutionVisibility + ); if (result.isInvalid) { this.setState({ formError: result, diff --git a/x-pack/plugins/spaces/public/management/edit_space/solution_view/solution_view.tsx b/x-pack/plugins/spaces/public/management/edit_space/solution_view/solution_view.tsx index 608454a75600b..9d7ca7140956c 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/solution_view/solution_view.tsx +++ b/x-pack/plugins/spaces/public/management/edit_space/solution_view/solution_view.tsx @@ -24,6 +24,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { Space } from '../../../../common'; +import type { SpaceValidator } from '../../lib'; import { SectionPanel } from '../section_panel'; type SolutionView = Space['solution']; @@ -98,10 +99,18 @@ const getOptions = ({ size }: EuiThemeComputed): Array; onChange: (space: Partial) => void; + isEditing: boolean; + validator: SpaceValidator; sectionTitle?: string; } -export const SolutionView: FunctionComponent = ({ space, onChange, sectionTitle }) => { +export const SolutionView: FunctionComponent = ({ + space, + onChange, + validator, + isEditing, + sectionTitle, +}) => { const { euiTheme } = useEuiTheme(); return ( @@ -132,6 +141,7 @@ export const SolutionView: FunctionComponent = ({ space, onChange, sectio defaultMessage: 'Solution view', })} fullWidth + {...validator.validateSolutionView(space, isEditing)} > = ({ space, onChange, sectio onChange={(solution) => { onChange({ ...space, solution }); }} + placeholder={i18n.translate( + 'xpack.spaces.management.navigation.solutionViewDefaultValue', + { + defaultMessage: 'Classic (Default)', + } + )} + isInvalid={validator.validateSolutionView(space, isEditing).isInvalid} /> diff --git a/x-pack/plugins/spaces/public/management/lib/validate_space.ts b/x-pack/plugins/spaces/public/management/lib/validate_space.ts index a93d627f6e159..9a9ae0cbe98fd 100644 --- a/x-pack/plugins/spaces/public/management/lib/validate_space.ts +++ b/x-pack/plugins/spaces/public/management/lib/validate_space.ts @@ -169,11 +169,31 @@ export class SpaceValidator { return valid(); } + public validateSolutionView( + space: FormValues, + isEditing: boolean, + allowSolutionVisibility = true + ) { + if (!this.shouldValidate || isEditing || !allowSolutionVisibility) { + return valid(); + } + + if (!space.solution) { + return invalid( + i18n.translate('xpack.spaces.management.validateSpace.requiredSolutionViewErrorMessage', { + defaultMessage: 'Select one solution.', + }) + ); + } + + return valid(); + } + public validateEnabledFeatures(space: FormValues) { return valid(); } - public validateForSave(space: FormValues) { + public validateForSave(space: FormValues, isEditing: boolean, allowSolutionVisibility: boolean) { const { isInvalid: isNameInvalid } = this.validateSpaceName(space); const { isInvalid: isDescriptionInvalid } = this.validateSpaceDescription(space); const { isInvalid: isIdentifierInvalid } = this.validateURLIdentifier(space); @@ -181,6 +201,11 @@ export class SpaceValidator { const { isInvalid: isAvatarColorInvalid } = this.validateAvatarColor(space); const { isInvalid: isAvatarImageInvalid } = this.validateAvatarImage(space); const { isInvalid: areFeaturesInvalid } = this.validateEnabledFeatures(space); + const { isInvalid: isSolutionViewInvalid } = this.validateSolutionView( + space, + isEditing, + allowSolutionVisibility + ); if ( isNameInvalid || @@ -189,7 +214,8 @@ export class SpaceValidator { isAvatarInitialsInvalid || isAvatarColorInvalid || isAvatarImageInvalid || - areFeaturesInvalid + areFeaturesInvalid || + isSolutionViewInvalid ) { return invalid(); }