Skip to content

Commit

Permalink
[Spaces] Replace Space Selector modal with a less intrusive popover (#…
Browse files Browse the repository at this point in the history
…19497)

This replaces the existing Modal with a smaller Popover which is less intrusive. The popover also features a search bar for finding the desired Space when there are 8 or more Spaces to choose from.

### Details
When there are less than 8 spaces available, the selector will render a simple list of spaces.

When there are >= 8 spaces available, the selector will also render a search bar to let users search for their space.


### Prerequisites 
- [x] Merge #18862 into `spaces-phase-1`

### Known Issues
- elastic/eui#1043 (fixed in `v3.2.0`)
- elastic/eui#1052 (fixed in `v3.2.1`)
- Missing typdefs (not a blocker to merge): elastic/eui#1120
  • Loading branch information
legrego authored Aug 16, 2018
1 parent 649974a commit 69fe9a7
Show file tree
Hide file tree
Showing 25 changed files with 638 additions and 293 deletions.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,4 @@
export { isReservedSpace } from './is_reserved_space';
export { MAX_SPACE_INITIALS } from './constants';

export {
getSpaceInitials,
getSpaceColor,
} from './space_attributes';
export { getSpaceInitials, getSpaceColor } from './space_attributes';
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
*/

import { get } from 'lodash';
import { Space } from './model/space';

/**
* Returns whether the given Space is reserved or not.
*
* @param space the space
* @returns boolean
*/
export function isReservedSpace(space) {
export function isReservedSpace(space: Space): boolean {
return get(space, '_reserved', false);
}
14 changes: 14 additions & 0 deletions x-pack/plugins/spaces/common/model/space.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export interface Space {
id: string;
name: string;
description?: string;
color?: string;
initials?: string;
_reserved?: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

import { VISUALIZATION_COLORS } from '@elastic/eui';
import { MAX_SPACE_INITIALS } from './constants';
import { Space } from './model/space';

// code point for lowercase "a"
const FALLBACK_CODE_POINT = 97;

/**
* Determines the color for the provided space.
Expand All @@ -14,17 +18,16 @@ import { MAX_SPACE_INITIALS } from './constants';
*
* @param {Space} space
*/
export function getSpaceColor(space = {}) {
const {
color,
name = '',
} = space;
export function getSpaceColor(space: Partial<Space> = {}) {
const { color, name = '' } = space;

if (color) {
return color;
}

return VISUALIZATION_COLORS[name.codePointAt(0) % VISUALIZATION_COLORS.length];
const firstCodePoint = name.codePointAt(0) || FALLBACK_CODE_POINT;

return VISUALIZATION_COLORS[firstCodePoint % VISUALIZATION_COLORS.length];
}

/**
Expand All @@ -34,17 +37,14 @@ export function getSpaceColor(space = {}) {
*
* @param {Space} space
*/
export function getSpaceInitials(space = {}) {
const {
initials,
name = ''
} = space;
export function getSpaceInitials(space: Partial<Space> = {}) {
const { initials, name = '' } = space;

if (initials) {
return initials;
}

const words = name.split(" ");
const words = name.split(' ');

const numInitials = Math.min(MAX_SPACE_INITIALS, words.length);

Expand Down
9 changes: 9 additions & 0 deletions x-pack/plugins/spaces/public/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import chrome from 'ui/chrome';

export const MANAGE_SPACES_URL = chrome.addBasePath(`/app/kibana#/management/spaces/list`);
66 changes: 0 additions & 66 deletions x-pack/plugins/spaces/public/lib/spaces_manager.js

This file was deleted.

67 changes: 67 additions & 0 deletions x-pack/plugins/spaces/public/lib/spaces_manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { toastNotifications } from 'ui/notify';

import { IHttpResponse } from 'angular';
import { EventEmitter } from 'events';
import { Space } from '../../common/model/space';

export class SpacesManager extends EventEmitter {
private httpAgent: any;
private baseUrl: any;

constructor(httpAgent: any, chrome: any) {
super();
this.httpAgent = httpAgent;
this.baseUrl = chrome.addBasePath(`/api/spaces/v1`);
}

public async getSpaces(): Promise<Space[]> {
return await this.httpAgent
.get(`${this.baseUrl}/spaces`)
.then((response: IHttpResponse<Space[]>) => response.data);
}

public async getSpace(id: string): Promise<Space> {
return await this.httpAgent.get(`${this.baseUrl}/space/${id}`);
}

public async createSpace(space: Space) {
return await this.httpAgent.post(`${this.baseUrl}/space`, space);
}

public async updateSpace(space: Space) {
return await this.httpAgent.put(`${this.baseUrl}/space/${space.id}?overwrite=true`, space);
}

public async deleteSpace(space: Space) {
return await this.httpAgent.delete(`${this.baseUrl}/space/${space.id}`);
}

public async changeSelectedSpace(space: Space) {
return await this.httpAgent
.post(`${this.baseUrl}/space/${space.id}/select`)
.then((response: IHttpResponse<any>) => {
if (response.data && response.data.location) {
window.location = response.data.location;
} else {
this._displayError();
}
})
.catch(() => this._displayError());
}

public async requestRefresh() {
this.emit('request_refresh');
}

public _displayError() {
toastNotifications.addDanger({
title: 'Unable to change your Space',
text: 'please try again later',
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
*/

export { SpaceAvatar } from './space_avatar';
export { SpaceCards } from './space_cards';
export { SpaceCards } from './space_cards';
export { ManageSpacesButton } from './manage_spaces_button';
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { EuiButton } from '@elastic/eui';
import React, { Component } from 'react';
import { MANAGE_SPACES_URL } from '../../lib/constants';

interface Props {
isDisabled?: boolean;
size?: 's' | 'l';
style?: CSSProperties;
}

export class ManageSpacesButton extends Component<Props, {}> {
public render() {
return (
<EuiButton
size={this.props.size || 's'}
className="manage-spaces-button"
isDisabled={this.props.isDisabled}
onClick={this.navigateToManageSpaces}
style={this.props.style}
>
Manage Spaces
</EuiButton>
);
}

private navigateToManageSpaces = () => {
window.location.replace(MANAGE_SPACES_URL);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,29 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { EuiAvatar } from '@elastic/eui';
import React from 'react';
import PropTypes from 'prop-types';
import {
EuiAvatar
} from '@elastic/eui';
import { MAX_SPACE_INITIALS, getSpaceInitials, getSpaceColor } from '../../../common';
import { getSpaceColor, getSpaceInitials, MAX_SPACE_INITIALS } from '../../../common';
import { Space } from '../../../common/model/space';

interface Props {
space: Space;
size?: string;
className?: string;
}

export const SpaceAvatar = (props: Props) => {
const { space, size, ...rest } = props;

export const SpaceAvatar = ({ space, size, ...rest }) => {
return (
<EuiAvatar
type="space"
name={space.name || ''}
size={size || "m"}
size={size || 'm'}
initialsLength={MAX_SPACE_INITIALS}
initials={getSpaceInitials(space)}
color={getSpaceColor(space)}
{...rest}
/>
);
};

SpaceAvatar.propTypes = {
space: PropTypes.object.isRequired,
size: PropTypes.string,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`NavControlPopover renders without crashing 1`] = `""`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`SpacesDescription renders without crashing 1`] = `
<EuiContextMenuPanel
className="spacesDescription"
hasFocus={true}
items={Array []}
title="Spaces"
>
<EuiText
className="spacesDescription__text"
grow={true}
>
<p>
Use Spaces within Kibana to organize your Dashboards, Visualizations, and other saved objects.
</p>
</EuiText>
<div
className="spacesDescription__manageButtonWrapper"
key="manageSpacesButton"
>
<ManageSpacesButton
size="s"
style={
Object {
"width": "100%",
}
}
/>
</div>
</EuiContextMenuPanel>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.spacesDescription {
max-width: 300px;
}

.spacesDescription__text,
.spacesDescription__manageButtonWrapper {
padding: 12px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { shallow } from 'enzyme';
import React from 'react';
import { SpacesDescription } from './spaces_description';

describe('SpacesDescription', () => {
it('renders without crashing', () => {
expect(shallow(<SpacesDescription />)).toMatchSnapshot();
});
});
Loading

0 comments on commit 69fe9a7

Please sign in to comment.