Skip to content

Commit

Permalink
[Spaces] Enhancement in create space UI (#191586)
Browse files Browse the repository at this point in the history
  • Loading branch information
sebelga authored Aug 29, 2024
1 parent a156e67 commit 3a57478
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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(
<ManageSpacePage
spacesManager={spacesManager as unknown as SpacesManager}
getFeatures={featuresStart.getFeatures}
notifications={notificationServiceMock.createStartContract()}
history={history}
capabilities={{
navLinks: {},
management: {},
catalogue: {},
spaces: { manage: true },
}}
eventTracker={eventTracker}
allowFeatureVisibility
allowSolutionVisibility
/>
);

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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ export class ManageSpacePage extends Component<Props, State> {
<SolutionView
space={this.state.space}
onChange={this.onSolutionViewChange}
validator={this.validator}
isEditing={this.editingExistingSpace()}
sectionTitle={i18n.translate(
'xpack.spaces.management.manageSpacePage.navigationTitle',
{ defaultMessage: 'Navigation' }
Expand Down Expand Up @@ -373,7 +375,11 @@ export class ManageSpacePage extends Component<Props, State> {
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'];
Expand Down Expand Up @@ -98,10 +99,18 @@ const getOptions = ({ size }: EuiThemeComputed): Array<EuiSuperSelectOption<Solu
interface Props {
space: Partial<Space>;
onChange: (space: Partial<Space>) => void;
isEditing: boolean;
validator: SpaceValidator;
sectionTitle?: string;
}

export const SolutionView: FunctionComponent<Props> = ({ space, onChange, sectionTitle }) => {
export const SolutionView: FunctionComponent<Props> = ({
space,
onChange,
validator,
isEditing,
sectionTitle,
}) => {
const { euiTheme } = useEuiTheme();

return (
Expand Down Expand Up @@ -132,6 +141,7 @@ export const SolutionView: FunctionComponent<Props> = ({ space, onChange, sectio
defaultMessage: 'Solution view',
})}
fullWidth
{...validator.validateSolutionView(space, isEditing)}
>
<EuiSuperSelect
options={getOptions(euiTheme)}
Expand All @@ -140,6 +150,13 @@ export const SolutionView: FunctionComponent<Props> = ({ 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}
/>
</EuiFormRow>
</EuiFlexItem>
Expand Down
30 changes: 28 additions & 2 deletions x-pack/plugins/spaces/public/management/lib/validate_space.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,18 +169,43 @@ 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);
const { isInvalid: isAvatarInitialsInvalid } = this.validateAvatarInitials(space);
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 ||
Expand All @@ -189,7 +214,8 @@ export class SpaceValidator {
isAvatarInitialsInvalid ||
isAvatarColorInvalid ||
isAvatarImageInvalid ||
areFeaturesInvalid
areFeaturesInvalid ||
isSolutionViewInvalid
) {
return invalid();
}
Expand Down

0 comments on commit 3a57478

Please sign in to comment.