From 0a29cd08a6de8d0db015fbd1150ac1e0da8903e2 Mon Sep 17 00:00:00 2001
From: Thom Heymann
Date: Thu, 20 May 2021 17:07:45 +0100
Subject: [PATCH 01/18] Updated spaces management page
---
.../customize_space.test.tsx.snap | 133 ++++++++
.../customize_space_avatar.test.tsx.snap | 154 ++++++---
.../space_identifier.test.tsx.snap | 63 ----
.../customize_space/customize_space.test.tsx | 87 ++++++
.../customize_space/customize_space.tsx | 176 +++++------
.../customize_space_avatar.test.tsx | 20 +-
.../customize_space_avatar.tsx | 291 +++++++++++++-----
.../customize_space/space_identifier.test.tsx | 29 --
.../customize_space/space_identifier.tsx | 177 -----------
.../enabled_features.test.tsx.snap | 30 +-
.../enabled_features.test.tsx | 2 +-
.../enabled_features/enabled_features.tsx | 129 ++------
.../enabled_features/feature_table.scss | 2 +-
.../enabled_features/feature_table.tsx | 56 ++--
.../edit_space/manage_space_page.test.tsx | 6 +-
.../edit_space/manage_space_page.tsx | 60 ++--
.../__snapshots__/section_panel.test.tsx.snap | 2 +-
.../section_panel/section_panel.tsx | 2 +-
.../management/lib/validate_space.test.ts | 100 +++++-
.../public/management/lib/validate_space.ts | 85 ++++-
.../spaces_grid/spaces_grid_page.tsx | 2 +-
.../management/spaces_management_app.test.tsx | 2 +-
.../management/spaces_management_app.tsx | 1 +
23 files changed, 904 insertions(+), 705 deletions(-)
create mode 100644 x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/customize_space.test.tsx.snap
delete mode 100644 x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/space_identifier.test.tsx.snap
create mode 100644 x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space.test.tsx
delete mode 100644 x-pack/plugins/spaces/public/management/edit_space/customize_space/space_identifier.test.tsx
delete mode 100644 x-pack/plugins/spaces/public/management/edit_space/customize_space/space_identifier.tsx
diff --git a/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/customize_space.test.tsx.snap b/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/customize_space.test.tsx.snap
new file mode 100644
index 0000000000000..aaac18c052634
--- /dev/null
+++ b/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/customize_space.test.tsx.snap
@@ -0,0 +1,133 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+
+
+ }
+ isInvalid={true}
+ label={
+
+ }
+ labelType="label"
+ >
+
+
+
+
+
+
+
+
+ }
+ >
+
+
+
+`;
diff --git a/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/customize_space_avatar.test.tsx.snap b/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/customize_space_avatar.test.tsx.snap
index 058b9ecdd0f8f..8a07f830c915b 100644
--- a/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/customize_space_avatar.test.tsx.snap
+++ b/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/customize_space_avatar.test.tsx.snap
@@ -7,60 +7,130 @@ exports[`renders without crashing 1`] = `
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`;
diff --git a/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/space_identifier.test.tsx.snap b/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/space_identifier.test.tsx.snap
deleted file mode 100644
index f1b4b956eca88..0000000000000
--- a/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/space_identifier.test.tsx.snap
+++ /dev/null
@@ -1,63 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders without crashing 1`] = `
-
-
-
- /s/
-
- ,
- }
- }
- />
-
- }
- isInvalid={false}
- label={
-
-
-
-
-
-
- }
- labelType="label"
- >
-
-
-
-`;
diff --git a/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space.test.tsx b/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space.test.tsx
new file mode 100644
index 0000000000000..42195317e6731
--- /dev/null
+++ b/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space.test.tsx
@@ -0,0 +1,87 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React from 'react';
+
+import { mountWithIntl, shallowWithIntl } from '@kbn/test/jest';
+
+import { SpaceValidator } from '../../lib';
+import { CustomizeSpace } from './customize_space';
+
+const validator = new SpaceValidator({ shouldValidate: true });
+
+test('renders correctly', () => {
+ const wrapper = shallowWithIntl(
+
+ );
+ expect(wrapper).toMatchSnapshot();
+});
+
+test('updates identifier, initials and color when name is changed', () => {
+ const space = {
+ id: 'space-1',
+ name: 'Space 1',
+ initials: 'S1',
+ color: '#ABCDEF',
+ };
+ const changeHandler = jest.fn();
+
+ const wrapper = mountWithIntl(
+
+ );
+
+ wrapper.find('input[name="name"]').simulate('change', { target: { value: 'Space 2' } });
+
+ expect(changeHandler).toHaveBeenCalledWith({
+ ...space,
+ id: 'space-2',
+ name: 'Space 2',
+ initials: 'S2',
+ color: '#9170B8',
+ });
+});
+
+test('does not update custom identifier, initials or color name is changed', () => {
+ const space = {
+ id: 'space-1',
+ name: 'Space 1',
+ initials: 'S1',
+ color: '#ABCDEF',
+ customAvatarInitials: true,
+ customAvatarColor: true,
+ };
+ const changeHandler = jest.fn();
+
+ const wrapper = mountWithIntl(
+
+ );
+
+ wrapper.find('input[name="name"]').simulate('change', { target: { value: 'Space 2' } });
+
+ expect(changeHandler).toHaveBeenCalledWith({
+ ...space,
+ name: 'Space 2',
+ });
+});
diff --git a/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space.tsx b/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space.tsx
index 4bbad58b5d139..c59ec943f0d1c 100644
--- a/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space.tsx
+++ b/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space.tsx
@@ -5,42 +5,31 @@
* 2.0.
*/
-import type { EuiPopoverProps } from '@elastic/eui';
import {
EuiDescribedFormGroup,
EuiFieldText,
EuiFormRow,
- EuiLoadingSpinner,
- EuiPopover,
- EuiSpacer,
EuiTextArea,
EuiTitle,
} from '@elastic/eui';
import type { ChangeEvent } from 'react';
-import React, { Component, Fragment, lazy, Suspense } from 'react';
+import React, { Component } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
-import type { Space } from 'src/plugins/spaces_oss/common';
-import { isReservedSpace } from '../../../../common';
-import { getSpaceAvatarComponent } from '../../../space_avatar';
+import { getSpaceColor, getSpaceInitials } from '../../../space_avatar';
import type { SpaceValidator } from '../../lib';
import { toSpaceIdentifier } from '../../lib';
+import type { FormValues } from '../manage_space_page';
import { SectionPanel } from '../section_panel';
import { CustomizeSpaceAvatar } from './customize_space_avatar';
-import { SpaceIdentifier } from './space_identifier';
-
-// No need to wrap LazySpaceAvatar in an error boundary, because it is one of the first chunks loaded when opening Kibana.
-const LazySpaceAvatar = lazy(() =>
- getSpaceAvatarComponent().then((component) => ({ default: component }))
-);
interface Props {
validator: SpaceValidator;
- space: Partial;
+ space: FormValues;
editingExistingSpace: boolean;
- onChange: (space: Partial) => void;
+ onChange: (space: FormValues) => void;
}
interface State {
@@ -60,14 +49,10 @@ export class CustomizeSpace extends Component {
const panelTitle = i18n.translate(
'xpack.spaces.management.manageSpacePage.customizeSpaceTitle',
{
- defaultMessage: 'Customize your space',
+ defaultMessage: 'General',
}
);
- const extraPopoverProps: Partial = {
- initialFocus: 'input[name="spaceInitials"]',
- };
-
return (
{
}
- description={this.getPanelDescription()}
+ description={i18n.translate('xpack.spaces.management.manageSpacePage.nameFormRowLabel', {
+ defaultMessage: 'Give your space a name and description for easy identification.',
+ })}
fullWidth
>
{
-
-
- {this.props.space && isReservedSpace(this.props.space) ? null : (
-
-
-
- )}
-
{
name="description"
value={description}
onChange={this.onDescriptionChange}
+ isInvalid={validator.validateSpaceDescription(this.props.space).isInvalid}
fullWidth
rows={2}
/>
-
-
- }>
-
-
-
+ {editingExistingSpace ? null : (
+
+ }
+ helpText={
+
}
- closePopover={this.closePopover}
- {...extraPopoverProps}
- ownFocus={true}
- isOpen={this.state.customizingAvatar}
+ {...this.props.validator.validateURLIdentifier(this.props.space)}
+ fullWidth
>
-
-
-
-
-
+
+
+ )}
+
+
+
+
+
+
+
+ }
+ description={i18n.translate('xpack.spaces.management.manageSpacePage.avatarDescription', {
+ defaultMessage: 'Choose how you wish your space’s avatar to appear across Kibana.',
+ })}
+ fullWidth
+ >
+
);
}
- public togglePopover = () => {
- this.setState({
- customizingAvatar: !this.state.customizingAvatar,
- });
- };
-
- public closePopover = () => {
- this.setState({
- customizingAvatar: false,
- });
- };
-
- public getPanelDescription = () => {
- return this.props.editingExistingSpace ? (
-
-
-
- ) : (
-
-
-
- );
- };
-
public onNameChange = (e: ChangeEvent) => {
if (!this.props.space) {
return;
@@ -230,6 +187,12 @@ export class CustomizeSpace extends Component {
...this.props.space,
name: e.target.value,
id,
+ initials: this.props.space.customAvatarInitials
+ ? this.props.space.initials
+ : getSpaceInitials({ name: e.target.value }),
+ color: this.props.space.customAvatarColor
+ ? this.props.space.color
+ : getSpaceColor({ name: e.target.value }),
});
};
@@ -240,7 +203,8 @@ export class CustomizeSpace extends Component {
});
};
- public onSpaceIdentifierChange = (updatedIdentifier: string) => {
+ public onSpaceIdentifierChange = (e: ChangeEvent) => {
+ const updatedIdentifier = e.target.value;
const usingCustomIdentifier = updatedIdentifier !== toSpaceIdentifier(this.props.space.name);
this.setState({
@@ -252,7 +216,7 @@ export class CustomizeSpace extends Component {
});
};
- public onAvatarChange = (space: Partial) => {
+ public onAvatarChange = (space: FormValues) => {
this.props.onChange(space);
};
}
diff --git a/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space_avatar.test.tsx b/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space_avatar.test.tsx
index babd89f69c784..578da9b96611c 100644
--- a/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space_avatar.test.tsx
+++ b/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space_avatar.test.tsx
@@ -10,6 +10,7 @@ import React from 'react';
import { mountWithIntl, shallowWithIntl } from '@kbn/test/jest';
+import { SpaceValidator } from '../../lib';
import { CustomizeSpaceAvatar } from './customize_space_avatar';
const space = {
@@ -17,13 +18,19 @@ const space = {
name: '',
};
+const validator = new SpaceValidator({ shouldValidate: true });
+
test('renders without crashing', () => {
- const wrapper = shallowWithIntl();
+ const wrapper = shallowWithIntl(
+
+ );
expect(wrapper).toMatchSnapshot();
});
test('shows customization fields', () => {
- const wrapper = mountWithIntl();
+ const wrapper = mountWithIntl(
+
+ );
expect(wrapper.find(EuiLink)).toHaveLength(0);
expect(wrapper.find(EuiFieldText)).toHaveLength(2); // EuiColorPicker contains an EuiFieldText element
@@ -41,17 +48,14 @@ test('invokes onChange callback when avatar is customized', () => {
const changeHandler = jest.fn();
const wrapper = mountWithIntl(
-
+
);
- wrapper
- .find(EuiFieldText)
- .first()
- .find('input')
- .simulate('change', { target: { value: 'NV' } });
+ wrapper.find('input[name="spaceInitials"]').simulate('change', { target: { value: 'NV' } });
expect(changeHandler).toHaveBeenCalledWith({
...customizedSpace,
initials: 'NV',
+ customAvatarInitials: true,
});
});
diff --git a/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space_avatar.tsx b/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space_avatar.tsx
index 96cd094c14645..2ce78b5c30e2d 100644
--- a/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space_avatar.tsx
+++ b/x-pack/plugins/spaces/public/management/edit_space/customize_space/customize_space_avatar.tsx
@@ -6,28 +6,35 @@
*/
import {
- EuiButton,
+ EuiAvatar,
EuiColorPicker,
EuiFieldText,
EuiFilePicker,
+ EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
+ EuiIcon,
+ EuiKeyPadMenu,
+ EuiKeyPadMenuItem,
+ EuiLoadingSpinner,
EuiSpacer,
- isValidHex,
} from '@elastic/eui';
-import type { ChangeEvent } from 'react';
-import React, { Component } from 'react';
+import type { ChangeEvent, FunctionComponent } from 'react';
+import React, { Component, lazy, Suspense } from 'react';
import { i18n } from '@kbn/i18n';
-import type { Space } from 'src/plugins/spaces_oss/common';
+import { euiThemeVars } from '@kbn/ui-shared-deps/theme';
import { MAX_SPACE_INITIALS } from '../../../../common';
import { encode, imageTypes } from '../../../../common/lib/dataurl';
-import { getSpaceColor, getSpaceInitials } from '../../../space_avatar';
+import { getSpaceAvatarComponent, getSpaceInitials } from '../../../space_avatar';
+import type { SpaceValidator } from '../../lib';
+import type { FormValues } from '../manage_space_page';
interface Props {
- space: Partial;
- onChange: (space: Partial) => void;
+ space: FormValues;
+ onChange: (space: FormValues) => void;
+ validator: SpaceValidator;
}
interface State {
@@ -35,6 +42,11 @@ interface State {
pendingInitials?: string | null;
}
+// No need to wrap LazySpaceAvatar in an error boundary, because it is one of the first chunks loaded when opening Kibana.
+const LazySpaceAvatar = lazy(() =>
+ getSpaceAvatarComponent().then((component) => ({ default: component }))
+);
+
export class CustomizeSpaceAvatar extends Component {
private initialsRef: HTMLInputElement | null = null;
@@ -106,93 +118,192 @@ export class CustomizeSpaceAvatar extends Component {
public render() {
const { space } = this.props;
- const { initialsHasFocus, pendingInitials } = this.state;
-
- const spaceColor = getSpaceColor(space);
- const isInvalidSpaceColor = !isValidHex(spaceColor) && spaceColor !== '';
-
return (
);
}
- private removeImageUrl() {
- this.props.onChange({
- ...this.props.space,
- imageUrl: '',
- });
- }
-
- public filePickerOrImage() {
- if (!this.props.space.imageUrl) {
- return (
-
-
-
- );
- } else {
- return (
-
- this.removeImageUrl()} color="danger" iconType="trash">
- {i18n.translate('xpack.spaces.management.customizeSpaceAvatar.removeImage', {
- defaultMessage: 'Remove custom image',
- })}
-
-
- );
- }
- }
-
public initialsInputRef = (ref: HTMLInputElement) => {
if (ref) {
this.initialsRef = ref;
@@ -230,6 +341,7 @@ export class CustomizeSpaceAvatar extends Component {
this.props.onChange({
...this.props.space,
+ customAvatarInitials: true,
initials,
});
};
@@ -237,7 +349,24 @@ export class CustomizeSpaceAvatar extends Component {
public onColorChange = (color: string) => {
this.props.onChange({
...this.props.space,
+ customAvatarColor: true,
color,
});
};
}
+
+const InitialsIcon: FunctionComponent = () => (
+
+);
diff --git a/x-pack/plugins/spaces/public/management/edit_space/customize_space/space_identifier.test.tsx b/x-pack/plugins/spaces/public/management/edit_space/customize_space/space_identifier.test.tsx
deleted file mode 100644
index f28e17d0e1f03..0000000000000
--- a/x-pack/plugins/spaces/public/management/edit_space/customize_space/space_identifier.test.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-import React from 'react';
-
-import { shallowWithIntl } from '@kbn/test/jest';
-
-import { SpaceValidator } from '../../lib';
-import { SpaceIdentifier } from './space_identifier';
-
-test('renders without crashing', () => {
- const props = {
- space: {
- id: '',
- name: '',
- },
- editable: true,
- onChange: jest.fn(),
- validator: new SpaceValidator(),
- };
- const wrapper = shallowWithIntl(
-
- );
- expect(wrapper).toMatchSnapshot();
-});
diff --git a/x-pack/plugins/spaces/public/management/edit_space/customize_space/space_identifier.tsx b/x-pack/plugins/spaces/public/management/edit_space/customize_space/space_identifier.tsx
deleted file mode 100644
index bc863e4add2cc..0000000000000
--- a/x-pack/plugins/spaces/public/management/edit_space/customize_space/space_identifier.tsx
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-import { EuiFieldText, EuiFormRow, EuiLink } from '@elastic/eui';
-import type { ChangeEvent } from 'react';
-import React, { Component, Fragment } from 'react';
-
-import type { InjectedIntl } from '@kbn/i18n/react';
-import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
-import type { Space } from 'src/plugins/spaces_oss/common';
-
-import type { SpaceValidator } from '../../lib';
-import { toSpaceIdentifier } from '../../lib';
-
-interface Props {
- space: Partial;
- editable: boolean;
- validator: SpaceValidator;
- intl: InjectedIntl;
- onChange: (updatedIdentifier: string) => void;
-}
-
-interface State {
- editing: boolean;
-}
-
-class SpaceIdentifierUI extends Component {
- private textFieldRef: HTMLInputElement | null = null;
-
- constructor(props: Props) {
- super(props);
- this.state = {
- editing: false,
- };
- }
-
- public render() {
- const { intl } = this.props;
- const { id = '' } = this.props.space;
-
- return (
-
-
- (this.textFieldRef = ref)}
- fullWidth
- />
-
-
- );
- }
-
- public getLabel = () => {
- if (!this.props.editable) {
- return (
-
-
-
- );
- }
-
- const editLinkText = this.state.editing ? (
-
- ) : (
-
- );
-
- const editLinkLabel = this.state.editing
- ? this.props.intl.formatMessage({
- id: 'xpack.spaces.management.spaceIdentifier.resetSpaceNameLinkLabel',
- defaultMessage: 'Reset the URL identifier',
- })
- : this.props.intl.formatMessage({
- id: 'xpack.spaces.management.spaceIdentifier.customizeSpaceNameLinkLabel',
- defaultMessage: 'Customize the URL identifier',
- });
-
- return (
-
-
-
- {editLinkText}
-
-
- );
- };
-
- public getHelpText = (
- identifier: string = this.props.intl.formatMessage({
- id: 'xpack.spaces.management.spaceIdentifier.emptySpaceIdentifierText',
- defaultMessage: 'awesome-space',
- })
- ) => {
- return (
-
- /s/{identifier},
- }}
- />
-
- );
- };
-
- public onEditClick = () => {
- const currentlyEditing = this.state.editing;
- if (currentlyEditing) {
- // "Reset" clicked. Create space identifier based on the space name.
- const resetIdentifier = toSpaceIdentifier(this.props.space.name);
-
- this.setState({
- editing: false,
- });
- this.props.onChange(resetIdentifier);
- } else {
- this.setState(
- {
- editing: true,
- },
- () => {
- if (this.textFieldRef) {
- this.textFieldRef.focus();
- }
- }
- );
- }
- };
-
- public onChange = (e: ChangeEvent) => {
- if (!this.state.editing) {
- return;
- }
- this.props.onChange(e.target.value);
- };
-}
-
-export const SpaceIdentifier = injectI18n(SpaceIdentifierUI);
diff --git a/x-pack/plugins/spaces/public/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap b/x-pack/plugins/spaces/public/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap
index c22a25ef60c31..eacaca2d6bc3f 100644
--- a/x-pack/plugins/spaces/public/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap
+++ b/x-pack/plugins/spaces/public/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap
@@ -4,33 +4,7 @@ exports[`EnabledFeatures renders as expected 1`] = `
-
-
-
-
-
-
-
-
- }
+ title="Features"
>
@@ -54,7 +28,7 @@ exports[`EnabledFeatures renders as expected 1`] = `
>
diff --git a/x-pack/plugins/spaces/public/management/edit_space/enabled_features/enabled_features.test.tsx b/x-pack/plugins/spaces/public/management/edit_space/enabled_features/enabled_features.test.tsx
index 7f1ea57a6b89c..3802a56f168cd 100644
--- a/x-pack/plugins/spaces/public/management/edit_space/enabled_features/enabled_features.test.tsx
+++ b/x-pack/plugins/spaces/public/management/edit_space/enabled_features/enabled_features.test.tsx
@@ -36,7 +36,7 @@ describe('EnabledFeatures', () => {
it(`renders as expected`, () => {
expect(
- shallowWithIntl(
+ shallowWithIntl(
{
- public render() {
- const description = i18n.translate(
+export const EnabledFeatures: FunctionComponent = (props) => (
+
-
-
-
-
-
-
-
-
- {this.getDescription()}
-
-
-
-
-
-
- );
- }
-
- private getPanelTitle = () => {
- const featureCount = this.props.features.length;
- const enabledCount = getEnabledFeatures(this.props.features, this.props.space).length;
-
- let details: null | ReactNode = null;
-
- if (enabledCount === featureCount) {
- details = (
-
-
-
-
-
- );
- } else if (enabledCount === 0) {
- details = (
-
-
+ )}
+ data-test-subj="enabled-features-panel"
+ >
+
+
+
+
-
-
- );
- } else {
- details = (
-
-
-
-
-
- );
- }
-
- return (
-
- {' '}
- {details}
-
- );
- };
-
- private getDescription = () => {
- return (
-
+
+
+
-
- );
- };
-}
+
+
+
+
+
+
+);
diff --git a/x-pack/plugins/spaces/public/management/edit_space/enabled_features/feature_table.scss b/x-pack/plugins/spaces/public/management/edit_space/enabled_features/feature_table.scss
index 35b9dc1d45661..20828c4b832d4 100644
--- a/x-pack/plugins/spaces/public/management/edit_space/enabled_features/feature_table.scss
+++ b/x-pack/plugins/spaces/public/management/edit_space/enabled_features/feature_table.scss
@@ -1,4 +1,4 @@
.spcFeatureTableAccordionContent {
// Align accordion content with the feature category logo in the accordion's buttonContent
- padding-left: $euiSizeXL;
+ padding-left: $euiSizeL;
}
diff --git a/x-pack/plugins/spaces/public/management/edit_space/enabled_features/feature_table.tsx b/x-pack/plugins/spaces/public/management/edit_space/enabled_features/feature_table.tsx
index 2c9eaf4563d05..5fb00700683f3 100644
--- a/x-pack/plugins/spaces/public/management/edit_space/enabled_features/feature_table.tsx
+++ b/x-pack/plugins/spaces/public/management/edit_space/enabled_features/feature_table.tsx
@@ -10,13 +10,13 @@ import './feature_table.scss';
import type { EuiCheckboxProps } from '@elastic/eui';
import {
EuiAccordion,
+ EuiButtonEmpty,
EuiCallOut,
EuiCheckbox,
EuiFlexGroup,
EuiFlexItem,
EuiHorizontalRule,
EuiIcon,
- EuiLink,
EuiSpacer,
EuiText,
EuiTitle,
@@ -88,9 +88,9 @@ export class FeatureTable extends Component {
const buttonContent = (
{
if (!canExpandCategory) {
const isChecked = enabledCount > 0;
@@ -110,22 +110,22 @@ export class FeatureTable extends Component {
) : null}
-
- {category.label}
+
+ {category.label}
);
const label: string = i18n.translate('xpack.spaces.management.featureAccordionSwitchLabel', {
- defaultMessage: '{enabledCount} / {featureCount} features visible',
+ defaultMessage: '{enabledCount}/{featureCount} features visible',
values: {
enabledCount,
featureCount,
},
});
const extraAction = (
-
+
{label}
);
@@ -143,13 +143,13 @@ export class FeatureTable extends Component {
extraAction={canExpandCategory ? extraAction : undefined}
>
-
+
{helpText && (
<>
{helpText}
-
+
>
)}
{featuresInCategory.map((feature) => {
@@ -188,30 +188,34 @@ export class FeatureTable extends Component
{
const controls = [];
if (enabledCount < featureCount) {
controls.push(
- this.showAll()} data-test-subj="showAllFeaturesLink">
-
- {i18n.translate('xpack.spaces.management.selectAllFeaturesLink', {
- defaultMessage: 'Select all',
- })}
-
-
+ this.showAll()}
+ size="xs"
+ data-test-subj="showAllFeaturesLink"
+ >
+ {i18n.translate('xpack.spaces.management.selectAllFeaturesLink', {
+ defaultMessage: 'Show all',
+ })}
+
);
}
if (enabledCount > 0) {
controls.push(
- this.hideAll()} data-test-subj="hideAllFeaturesLink">
-
- {i18n.translate('xpack.spaces.management.deselectAllFeaturesLink', {
- defaultMessage: 'Deselect all',
- })}
-
-
+ this.hideAll()}
+ size="xs"
+ data-test-subj="hideAllFeaturesLink"
+ >
+ {i18n.translate('xpack.spaces.management.deselectAllFeaturesLink', {
+ defaultMessage: 'Hide all',
+ })}
+
);
}
return (
-
+
@@ -227,10 +231,10 @@ export class FeatureTable extends Component {
))}
-
+
{accordions.flatMap((a, idx) => [
a.element,
- ,
+ ,
])}
);
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 79daeba2c8ec3..c6f7169df245a 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,8 +98,9 @@ describe('ManageSpacePage', () => {
id: 'new-space-name',
name: 'New Space Name',
description: 'some description',
- color: undefined,
- initials: undefined,
+ initials: 'NS',
+ color: '#AA6556',
+ imageUrl: '',
disabledFeatures: [],
});
});
@@ -163,6 +164,7 @@ describe('ManageSpacePage', () => {
description: 'some description',
color: '#aabbcc',
initials: 'AB',
+ imageUrl: '',
disabledFeatures: ['feature-1'],
});
});
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 d00ee0bb26a3e..f6a2667f1d84e 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
@@ -13,7 +13,6 @@ import {
EuiLoadingSpinner,
EuiPageContentBody,
EuiSpacer,
- EuiText,
EuiTitle,
} from '@elastic/eui';
import _ from 'lodash';
@@ -31,6 +30,7 @@ import type { Space } from 'src/plugins/spaces_oss/common';
import type { FeaturesPluginStart, KibanaFeature } from '../../../../features/public';
import { isReservedSpace } from '../../../common';
+import { getSpaceColor, getSpaceInitials } from '../../space_avatar';
import type { SpacesManager } from '../../spaces_manager';
import { UnauthorizedPrompt } from '../components';
import { toSpaceIdentifier } from '../lib';
@@ -41,6 +41,13 @@ import { DeleteSpacesButton } from './delete_spaces_button';
import { EnabledFeatures } from './enabled_features';
import { ReservedSpaceBadge } from './reserved_space_badge';
+export interface FormValues extends Partial {
+ customIdentifier?: boolean;
+ avatarType?: 'initials' | 'image';
+ customAvatarInitials?: boolean;
+ customAvatarColor?: boolean;
+}
+
interface Props {
getFeatures: FeaturesPluginStart['getFeatures'];
notifications: NotificationsStart;
@@ -53,7 +60,7 @@ interface Props {
}
interface State {
- space: Partial;
+ space: FormValues;
features: KibanaFeature[];
originalSpace?: Partial;
showAlteringActiveSpaceDialog: boolean;
@@ -75,7 +82,9 @@ export class ManageSpacePage extends Component {
isLoading: true,
showAlteringActiveSpaceDialog: false,
saveInProgress: false,
- space: {},
+ space: {
+ color: getSpaceColor({}),
+ },
features: [],
};
}
@@ -121,7 +130,7 @@ export class ManageSpacePage extends Component {
public getLoadingIndicator = () => (
-
{' '}
+
Loading...
@@ -139,15 +148,6 @@ export class ManageSpacePage extends Component
{
{this.getFormHeading()}
-
-
-
-
-
-
{
- {this.getTitle()}
+ {this.getTitle()}
@@ -197,12 +197,17 @@ export class ManageSpacePage extends Component {
public getTitle = () => {
if (this.editingExistingSpace()) {
- return `Edit space`;
+ return (
+
+ );
}
return (
);
};
@@ -271,7 +276,7 @@ export class ManageSpacePage extends Component {
return null;
};
- public onSpaceChange = (updatedSpace: Partial) => {
+ public onSpaceChange = (updatedSpace: FormValues) => {
this.setState({
space: updatedSpace,
});
@@ -280,7 +285,9 @@ export class ManageSpacePage extends Component {
public saveSpace = () => {
this.validator.enableValidation();
- const result = this.validator.validateForSave(this.state.space as Space);
+ const originalSpace: Space = this.state.originalSpace as Space;
+ const space: Space = this.state.space as Space;
+ const result = this.validator.validateForSave(space);
if (result.isInvalid) {
this.setState({
formError: result,
@@ -292,9 +299,6 @@ export class ManageSpacePage extends Component {
if (this.editingExistingSpace()) {
const { spacesManager } = this.props;
- const originalSpace: Space = this.state.originalSpace as Space;
- const space: Space = this.state.space as Space;
-
spacesManager.getActiveSpace().then((activeSpace) => {
const editingActiveSpace = activeSpace.id === originalSpace.id;
@@ -330,7 +334,14 @@ export class ManageSpacePage extends Component {
}
this.setState({
- space,
+ space: {
+ ...space,
+ avatarType: space.imageUrl ? 'image' : 'initials',
+ initials: space.initials || getSpaceInitials(space),
+ customIdentifier: false,
+ customAvatarInitials: getSpaceInitials({ name: space.name }) !== space.initials,
+ customAvatarColor: getSpaceColor({ name: space.name }) !== space.color,
+ },
features,
originalSpace: space,
isLoading: false,
@@ -362,16 +373,17 @@ export class ManageSpacePage extends Component {
color,
disabledFeatures = [],
imageUrl,
+ avatarType,
} = this.state.space;
const params = {
name,
id,
description,
- initials,
+ initials: avatarType !== 'image' ? initials : '',
color,
disabledFeatures,
- imageUrl,
+ imageUrl: avatarType === 'image' ? imageUrl : '',
};
let action;
diff --git a/x-pack/plugins/spaces/public/management/edit_space/section_panel/__snapshots__/section_panel.test.tsx.snap b/x-pack/plugins/spaces/public/management/edit_space/section_panel/__snapshots__/section_panel.test.tsx.snap
index b9d054d6309d0..addca6ed67778 100644
--- a/x-pack/plugins/spaces/public/management/edit_space/section_panel/__snapshots__/section_panel.test.tsx.snap
+++ b/x-pack/plugins/spaces/public/management/edit_space/section_panel/__snapshots__/section_panel.test.tsx.snap
@@ -11,7 +11,7 @@ exports[`it renders without blowing up 1`] = `
grow={false}
>