Skip to content

Commit

Permalink
add switch to space icon on space list table
Browse files Browse the repository at this point in the history
  • Loading branch information
eokoneyo committed Jun 13, 2024
1 parent 83f5dad commit dd25dd2
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 30 deletions.
6 changes: 5 additions & 1 deletion x-pack/plugins/spaces/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ export {
ENTER_SPACE_PATH,
DEFAULT_SPACE_ID,
} from './constants';
export { addSpaceIdToPath, getSpaceIdFromPath } from './lib/spaces_url_parser';
export {
addSpaceIdToPath,
getSpaceIdFromPath,
getSpaceNavigationURL,
} from './lib/spaces_url_parser';
export type {
Space,
GetAllSpacesOptions,
Expand Down
19 changes: 18 additions & 1 deletion x-pack/plugins/spaces/common/lib/spaces_url_parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { DEFAULT_SPACE_ID } from '../constants';
import { DEFAULT_SPACE_ID, ENTER_SPACE_PATH } from '../constants';

const spaceContextRegex = /^\/s\/([a-z0-9_\-]+)/;

Expand Down Expand Up @@ -75,6 +75,23 @@ export function addSpaceIdToPath(
return `${normalizedBasePath}${requestedPath}` || '/';
}

/**
* Builds URL that will navigate a user to the space for the spaceId provided
*/
export function getSpaceNavigationURL({
serverBasePath,
spaceId,
}: {
serverBasePath: string;
spaceId: string;
}) {
return addSpaceIdToPath(
serverBasePath,
spaceId,
`${ENTER_SPACE_PATH}?next=/app/management/kibana/spaces/view/${spaceId}`
);
}

function stripServerBasePath(requestBasePath: string, serverBasePath: string) {
if (serverBasePath && serverBasePath !== '/' && requestBasePath.startsWith(serverBasePath)) {
return requestBasePath.substr(serverBasePath.length);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import {
type EuiBasicTableColumn,
EuiButton,
EuiButtonIcon,
EuiCallOut,
Expand All @@ -30,7 +31,7 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { reactRouterNavigate } from '@kbn/kibana-react-plugin/public';

import type { Space } from '../../../common';
import { getSpaceNavigationURL, type Space } from '../../../common';
import { isReservedSpace } from '../../../common';
import { DEFAULT_SPACE_ID } from '../../../common/constants';
import { getSpacesFeatureDescription } from '../../constants';
Expand All @@ -47,6 +48,7 @@ const LazySpaceAvatar = lazy(() =>
interface Props {
spacesManager: SpacesManager;
notifications: NotificationsStart;
serverBasePath: string;
getFeatures: FeaturesPluginStart['getFeatures'];
capabilities: Capabilities;
history: ScopedHistory;
Expand All @@ -56,6 +58,7 @@ interface Props {

interface State {
spaces: Space[];
activeSpace: Space | null;
features: KibanaFeature[];
loading: boolean;
showConfirmDeleteModal: boolean;
Expand All @@ -67,6 +70,7 @@ export class SpacesGridPage extends Component<Props, State> {
super(props);
this.state = {
spaces: [],
activeSpace: null,
features: [],
loading: true,
showConfirmDeleteModal: false,
Expand Down Expand Up @@ -133,7 +137,7 @@ export class SpacesGridPage extends Component<Props, State> {
rowProps={(item) => ({
'data-test-subj': `spacesListTableRow-${item.id}`,
})}
columns={this.getColumnConfig()}
columns={this.getColumnConfig({ serverBasePath: this.props.serverBasePath })}
pagination={true}
sorting={true}
search={{
Expand Down Expand Up @@ -216,12 +220,18 @@ export class SpacesGridPage extends Component<Props, State> {
});

const getSpaces = spacesManager.getSpaces();
const getActiveSpace = spacesManager.getActiveSpace();

try {
const [spaces, features] = await Promise.all([getSpaces, getFeatures()]);
const [spaces, activeSpace, features] = await Promise.all([
getSpaces,
getActiveSpace,
getFeatures(),
]);
this.setState({
loading: false,
spaces,
activeSpace,
features,
});
} catch (error) {
Expand All @@ -236,17 +246,23 @@ export class SpacesGridPage extends Component<Props, State> {
}
};

public getColumnConfig() {
public getColumnConfig({
serverBasePath,
}: {
serverBasePath: string;
}): Array<EuiBasicTableColumn<Space>> {
return [
{
field: 'initials',
name: '',
width: '50px',
render: (_value: string, record: Space) => {
render: (_value: string, rowRecord) => {
return (
<Suspense fallback={<EuiLoadingSpinner />}>
<EuiLink {...reactRouterNavigate(this.props.history, this.getViewSpacePath(record))}>
<LazySpaceAvatar space={record} size="s" />
<EuiLink
{...reactRouterNavigate(this.props.history, this.getViewSpacePath(rowRecord))}
>
<LazySpaceAvatar space={rowRecord} size="s" />
</EuiLink>
</Suspense>
);
Expand All @@ -258,10 +274,10 @@ export class SpacesGridPage extends Component<Props, State> {
defaultMessage: 'Space',
}),
sortable: true,
render: (value: string, record: Space) => (
render: (value: string, rowRecord) => (
<EuiLink
{...reactRouterNavigate(this.props.history, this.getViewSpacePath(record))}
data-test-subj={`${record.id}-hyperlink`}
{...reactRouterNavigate(this.props.history, this.getViewSpacePath(rowRecord))}
data-test-subj={`${rowRecord.id}-hyperlink`}
>
{value}
</EuiLink>
Expand All @@ -282,8 +298,8 @@ export class SpacesGridPage extends Component<Props, State> {
sortable: (space: Space) => {
return getEnabledFeatures(this.state.features, space).length;
},
render: (_disabledFeatures: string[], record: Space) => {
const enabledFeatureCount = getEnabledFeatures(this.state.features, record).length;
render: (_disabledFeatures: string[], rowRecord) => {
const enabledFeatureCount = getEnabledFeatures(this.state.features, rowRecord).length;
if (enabledFeatureCount === this.state.features.length) {
return (
<FormattedMessage
Expand Down Expand Up @@ -333,37 +349,57 @@ export class SpacesGridPage extends Component<Props, State> {
}),
actions: [
{
render: (record: Space) => (
isPrimary: true,
available: (rowRecord) => this.state.activeSpace?.name !== rowRecord.name,
render: (rowRecord: Space) => {
return (
<EuiButtonIcon
href={getSpaceNavigationURL({ serverBasePath, spaceId: rowRecord.id })}
iconType="merge"
data-test-subj={`${rowRecord.name}-switchSpace`}
aria-label={i18n.translate(
'xpack.spaces.management.spacesGridPage.switchSpaceActionName',
{
defaultMessage: 'Switch to {spaceName} space',
values: { spaceName: rowRecord.name },
}
)}
/>
);
},
},
{
render: (rowRecord: Space) => (
<EuiButtonIcon
data-test-subj={`${record.name}-editSpace`}
data-test-subj={`${rowRecord.name}-editSpace`}
aria-label={i18n.translate(
'xpack.spaces.management.spacesGridPage.editSpaceActionName',
{
defaultMessage: `Edit {spaceName}.`,
values: { spaceName: record.name },
values: { spaceName: rowRecord.name },
}
)}
color={'primary'}
iconType={'pencil'}
{...reactRouterNavigate(this.props.history, this.getEditSpacePath(record))}
{...reactRouterNavigate(this.props.history, this.getEditSpacePath(rowRecord))}
/>
),
},
{
available: (record: Space) => !isReservedSpace(record),
render: (record: Space) => (
available: (rowRecord: Space) => !isReservedSpace(rowRecord),
render: (rowRecord: Space) => (
<EuiButtonIcon
data-test-subj={`${record.name}-deleteSpace`}
data-test-subj={`${rowRecord.name}-deleteSpace`}
aria-label={i18n.translate(
'xpack.spaces.management.spacesGridPage.deleteActionName',
{
defaultMessage: `Delete {spaceName}.`,
values: { spaceName: record.name },
values: { spaceName: rowRecord.name },
}
)}
color={'danger'}
iconType={'trash'}
onClick={() => this.onDeleteSpaceClick(record)}
onClick={() => this.onDeleteSpaceClick(rowRecord)}
/>
),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export const spacesManagementApp = Object.freeze({
getFeatures={features.getFeatures}
notifications={notifications}
spacesManager={spacesManager}
serverBasePath={http.basePath.serverBasePath}
history={history}
getUrlForApp={application.getUrlForApp}
maxSpaces={config.maxSpaces}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import type { Role } from '@kbn/security-plugin-types-common';
import { TAB_ID_CONTENT, TAB_ID_FEATURES, TAB_ID_ROLES } from './constants';
import { useTabs } from './hooks/use_tabs';
import { ViewSpaceContextProvider } from './hooks/view_space_context_provider';
import { addSpaceIdToPath, ENTER_SPACE_PATH, type Space } from '../../../common';
import { getSpaceNavigationURL, type Space } from '../../../common';
import { getSpaceAvatarComponent } from '../../space_avatar';
import type { SpacesManager } from '../../spaces_manager';

Expand Down Expand Up @@ -187,19 +187,18 @@ export const ViewSpacePage: FC<PageProps> = (props) => {
}

const { serverBasePath } = props;
const urlToSelectedSpace = addSpaceIdToPath(
serverBasePath,
space.id,
`${ENTER_SPACE_PATH}?next=/app/management/kibana/spaces/view/${space.id}`
);

if (userActiveSpace?.id === space.id) {
return null;
}

// use href to force full page reload (needed in order to change spaces)
return (
<EuiButton iconType="merge" href={urlToSelectedSpace} data-test-subj="spaceSwitcherButton">
<EuiButton
iconType="merge"
href={getSpaceNavigationURL({ serverBasePath, spaceId: space.id })}
data-test-subj="spaceSwitcherButton"
>
<FormattedMessage
id="xpack.spaces.management.spaceDetails.space.switchToSpaceButton.label"
defaultMessage="Switch to this space"
Expand Down

0 comments on commit dd25dd2

Please sign in to comment.