Expose hasOnlyDefaultSpace from spaces contract (#166174)

Resolves https://github.com/elastic/kibana/issues/165965

## Summary

Exposes `hasOnlyDefaultSpace` from spaces contract. 

If anyone has a better suggestion for the name I'd be happy to change
it.

---------

Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com>
This commit is contained in:
Thom Heymann 2023-09-14 13:38:37 +01:00 committed by GitHub
parent 0538e65a8b
commit 1316738857
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 116 additions and 3 deletions

View file

@ -9,11 +9,12 @@ import React from 'react';
import { LegacyUrlConflictCallOut } from './legacy_url_conflict_callout';
import { render, screen } from '@testing-library/react';
import type { Rule } from '../../../rule_management/logic';
import type { SpacesApi } from '@kbn/spaces-plugin/public';
const mockRedirectLegacyUrl = jest.fn();
const mockGetLegacyUrlConflict = jest.fn();
const mockSpacesApi = {
const mockSpacesApi: SpacesApi = {
getActiveSpace$: jest.fn(),
getActiveSpace: jest.fn(),
ui: {
@ -29,6 +30,7 @@ const mockSpacesApi = {
redirectLegacyUrl: mockRedirectLegacyUrl,
useSpaces: jest.fn(),
},
hasOnlyDefaultSpace: false,
};
describe('<LegacyUrlConflictCallOut />', () => {

View file

@ -10,11 +10,12 @@ import { renderHook, cleanup } from '@testing-library/react-hooks';
import type { UseLegacyUrlRedirectParams } from './use_redirect_legacy_url';
import { useLegacyUrlRedirect } from './use_redirect_legacy_url';
import type { Rule } from '../../../rule_management/logic';
import type { SpacesApi } from '@kbn/spaces-plugin/public';
const mockRedirectLegacyUrl = jest.fn();
const mockGetLegacyUrlConflict = jest.fn();
const mockSpacesApi = {
const mockSpacesApi: SpacesApi = {
getActiveSpace$: jest.fn(),
getActiveSpace: jest.fn(),
ui: {
@ -30,6 +31,7 @@ const mockSpacesApi = {
redirectLegacyUrl: mockRedirectLegacyUrl,
useSpaces: jest.fn(),
},
hasOnlyDefaultSpace: false,
};
describe('useLegacyUrlRedirect', () => {

View file

@ -15,6 +15,7 @@ const createApiMock = (): jest.Mocked<SpacesApi> => ({
getActiveSpace$: jest.fn().mockReturnValue(of()),
getActiveSpace: jest.fn(),
ui: createApiUiMock(),
hasOnlyDefaultSpace: false,
});
type SpacesApiUiMock = Omit<jest.Mocked<SpacesApiUi>, 'components'> & {

View file

@ -149,4 +149,28 @@ describe('Spaces plugin', () => {
expect(coreStart.chrome.navControls.registerLeft).not.toHaveBeenCalled();
});
});
it('determines hasOnlyDefaultSpace correctly when maxSpaces=1', () => {
const coreSetup = coreMock.createSetup();
const coreStart = coreMock.createStart();
const plugin = new SpacesPlugin(coreMock.createPluginInitializerContext({ maxSpaces: 1 }));
const spacesSetup = plugin.setup(coreSetup, {});
const spacesStart = plugin.start(coreStart);
expect(spacesSetup.hasOnlyDefaultSpace).toBe(true);
expect(spacesStart.hasOnlyDefaultSpace).toBe(true);
});
it('determines hasOnlyDefaultSpace correctly when maxSpaces=1000', () => {
const coreSetup = coreMock.createSetup();
const coreStart = coreMock.createStart();
const plugin = new SpacesPlugin(coreMock.createPluginInitializerContext({ maxSpaces: 1000 }));
const spacesSetup = plugin.setup(coreSetup, {});
const spacesStart = plugin.start(coreStart);
expect(spacesSetup.hasOnlyDefaultSpace).toBe(false);
expect(spacesStart.hasOnlyDefaultSpace).toBe(false);
});
});

View file

@ -53,6 +53,8 @@ export class SpacesPlugin implements Plugin<SpacesPluginSetup, SpacesPluginStart
}
public setup(core: CoreSetup<PluginsStart, SpacesPluginStart>, plugins: PluginsSetup) {
const hasOnlyDefaultSpace = this.config.maxSpaces === 1;
this.spacesManager = new SpacesManager(core.http);
this.spacesApi = {
ui: getUiApi({
@ -61,6 +63,7 @@ export class SpacesPlugin implements Plugin<SpacesPluginSetup, SpacesPluginStart
}),
getActiveSpace$: () => this.spacesManager.onActiveSpaceChange$,
getActiveSpace: () => this.spacesManager.getActiveSpace(),
hasOnlyDefaultSpace,
};
if (!this.isServerless) {
@ -85,7 +88,7 @@ export class SpacesPlugin implements Plugin<SpacesPluginSetup, SpacesPluginStart
});
}
return {};
return { hasOnlyDefaultSpace };
}
public start(core: CoreStart) {

View file

@ -49,6 +49,13 @@ export interface SpacesApi {
*/
getActiveSpace(): Promise<Space>;
/**
* Determines whether Kibana supports multiple spaces or only the default space.
*
* When `xpack.spaces.maxSpaces` is set to 1 Kibana only supports the default space and any spaces related UI can safely be hidden.
*/
hasOnlyDefaultSpace: boolean;
/**
* UI components and services to add spaces capabilities to an application.
*/

View file

@ -5,6 +5,8 @@
* 2.0.
*/
import { of } from 'rxjs';
import { spacesClientServiceMock } from './spaces_client/spaces_client_service.mock';
import { spacesServiceMock } from './spaces_service/spaces_service.mock';
@ -12,12 +14,14 @@ function createSetupMock() {
return {
spacesService: spacesServiceMock.createSetupContract(),
spacesClient: spacesClientServiceMock.createSetup(),
hasOnlyDefaultSpace$: of(false),
};
}
function createStartMock() {
return {
spacesService: spacesServiceMock.createStartContract(),
hasOnlyDefaultSpace$: of(false),
};
}

View file

@ -5,6 +5,8 @@
* 2.0.
*/
import { lastValueFrom } from 'rxjs';
import type { CoreSetup } from '@kbn/core/server';
import { coreMock } from '@kbn/core/server/mocks';
import { featuresPluginMock } from '@kbn/features-plugin/server/mocks';
@ -26,6 +28,12 @@ describe('Spaces plugin', () => {
const spacesSetup = plugin.setup(core, { features, licensing });
expect(spacesSetup).toMatchInlineSnapshot(`
Object {
"hasOnlyDefaultSpace$": Observable {
"operator": [Function],
"source": Observable {
"_subscribe": [Function],
},
},
"spacesClient": Object {
"registerClientWrapper": [Function],
"setClientRepositoryFactory": [Function],
@ -85,6 +93,12 @@ describe('Spaces plugin', () => {
const spacesStart = plugin.start(coreStart);
expect(spacesStart).toMatchInlineSnapshot(`
Object {
"hasOnlyDefaultSpace$": Observable {
"operator": [Function],
"source": Observable {
"_subscribe": [Function],
},
},
"spacesService": Object {
"createSpacesClient": [Function],
"getActiveSpace": [Function],
@ -97,4 +111,40 @@ describe('Spaces plugin', () => {
`);
});
});
it('determines hasOnlyDefaultSpace$ correctly when maxSpaces=1', async () => {
const initializerContext = coreMock.createPluginInitializerContext({ maxSpaces: 1 });
const core = coreMock.createSetup() as CoreSetup<PluginsStart>;
const features = featuresPluginMock.createSetup();
const licensing = licensingMock.createSetup();
const usageCollection = usageCollectionPluginMock.createSetupContract();
const plugin = new SpacesPlugin(initializerContext);
const spacesSetup = plugin.setup(core, { features, licensing, usageCollection });
const coreStart = coreMock.createStart();
const spacesStart = plugin.start(coreStart);
await expect(lastValueFrom(spacesSetup.hasOnlyDefaultSpace$)).resolves.toEqual(true);
await expect(lastValueFrom(spacesStart.hasOnlyDefaultSpace$)).resolves.toEqual(true);
});
it('determines hasOnlyDefaultSpace$ correctly when maxSpaces=1000', async () => {
const initializerContext = coreMock.createPluginInitializerContext({ maxSpaces: 1000 });
const core = coreMock.createSetup() as CoreSetup<PluginsStart>;
const features = featuresPluginMock.createSetup();
const licensing = licensingMock.createSetup();
const usageCollection = usageCollectionPluginMock.createSetupContract();
const plugin = new SpacesPlugin(initializerContext);
const spacesSetup = plugin.setup(core, { features, licensing, usageCollection });
const coreStart = coreMock.createStart();
const spacesStart = plugin.start(coreStart);
await expect(lastValueFrom(spacesSetup.hasOnlyDefaultSpace$)).resolves.toEqual(false);
await expect(lastValueFrom(spacesStart.hasOnlyDefaultSpace$)).resolves.toEqual(false);
});
});

View file

@ -6,6 +6,7 @@
*/
import type { Observable } from 'rxjs';
import { map } from 'rxjs';
import type {
CoreSetup,
@ -76,6 +77,13 @@ export interface SpacesPluginSetup {
*/
registerClientWrapper: (wrapper: SpacesClientWrapper) => void;
};
/**
* Determines whether Kibana supports multiple spaces or only the default space.
*
* When `xpack.spaces.maxSpaces` is set to 1 Kibana only supports the default space and any spaces related UI can safely be hidden.
*/
hasOnlyDefaultSpace$: Observable<boolean>;
}
/**
@ -84,6 +92,13 @@ export interface SpacesPluginSetup {
export interface SpacesPluginStart {
/** Service for interacting with spaces. */
spacesService: SpacesServiceStart;
/**
* Determines whether Kibana supports multiple spaces or only the default space.
*
* When `xpack.spaces.maxSpaces` is set to 1 Kibana only supports the default space and any spaces related UI can safely be hidden.
*/
hasOnlyDefaultSpace$: Observable<boolean>;
}
export class SpacesPlugin
@ -99,12 +114,15 @@ export class SpacesPlugin
private readonly spacesService: SpacesService;
private readonly hasOnlyDefaultSpace$: Observable<boolean>;
private spacesServiceStart?: SpacesServiceStart;
private defaultSpaceService?: DefaultSpaceService;
constructor(private readonly initializerContext: PluginInitializerContext) {
this.config$ = initializerContext.config.create<ConfigType>();
this.hasOnlyDefaultSpace$ = this.config$.pipe(map(({ maxSpaces }) => maxSpaces === 1));
this.log = initializerContext.logger.get();
this.spacesService = new SpacesService();
this.spacesClientService = new SpacesClientService((message) => this.log.debug(message));
@ -195,6 +213,7 @@ export class SpacesPlugin
return {
spacesClient: spacesClientSetup,
spacesService: spacesServiceSetup,
hasOnlyDefaultSpace$: this.hasOnlyDefaultSpace$,
};
}
@ -208,6 +227,7 @@ export class SpacesPlugin
return {
spacesService: this.spacesServiceStart,
hasOnlyDefaultSpace$: this.hasOnlyDefaultSpace$,
};
}