mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
parent
46a224a96e
commit
000102877c
22 changed files with 425 additions and 90 deletions
|
@ -1,17 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [FlyoutRef](./kibana-plugin-public.flyoutref.md) > [close](./kibana-plugin-public.flyoutref.close.md)
|
||||
|
||||
## FlyoutRef.close() method
|
||||
|
||||
Closes the referenced flyout if it's still open which in turn will resolve the `onClose` Promise. If the flyout had already been closed this method does nothing.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
close(): Promise<void>;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`Promise<void>`
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [FlyoutRef](./kibana-plugin-public.flyoutref.md)
|
||||
|
||||
## FlyoutRef class
|
||||
|
||||
A FlyoutRef is a reference to an opened flyout panel. It offers methods to close the flyout panel again. If you open a flyout panel you should make sure you call `close()` when it should be closed. Since a flyout could also be closed by a user or from another flyout being opened, you must bind to the `onClose` Promise on the FlyoutRef instance. The Promise will resolve whenever the flyout was closed at which point you should discard the FlyoutRef.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare class FlyoutRef
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Modifiers | Type | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| [onClose](./kibana-plugin-public.flyoutref.onclose.md) | | <code>Promise<void></code> | An Promise that will resolve once this flyout is closed.<!-- -->Flyouts can close from user interaction, calling <code>close()</code> on the flyout reference or another call to <code>openFlyout()</code> replacing your flyout. |
|
||||
|
||||
## Methods
|
||||
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [close()](./kibana-plugin-public.flyoutref.close.md) | | Closes the referenced flyout if it's still open which in turn will resolve the <code>onClose</code> Promise. If the flyout had already been closed this method does nothing. |
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [FlyoutRef](./kibana-plugin-public.flyoutref.md) > [onClose](./kibana-plugin-public.flyoutref.onclose.md)
|
||||
|
||||
## FlyoutRef.onClose property
|
||||
|
||||
An Promise that will resolve once this flyout is closed.
|
||||
|
||||
Flyouts can close from user interaction, calling `close()` on the flyout reference or another call to `openFlyout()` replacing your flyout.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
readonly onClose: Promise<void>;
|
||||
```
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
| Class | Description |
|
||||
| --- | --- |
|
||||
| [FlyoutRef](./kibana-plugin-public.flyoutref.md) | A FlyoutRef is a reference to an opened flyout panel. It offers methods to close the flyout panel again. If you open a flyout panel you should make sure you call <code>close()</code> when it should be closed. Since a flyout could also be closed by a user or from another flyout being opened, you must bind to the <code>onClose</code> Promise on the FlyoutRef instance. The Promise will resolve whenever the flyout was closed at which point you should discard the FlyoutRef. |
|
||||
| [ToastsApi](./kibana-plugin-public.toastsapi.md) | |
|
||||
| [UiSettingsClient](./kibana-plugin-public.uisettingsclient.md) | |
|
||||
|
||||
|
@ -30,6 +29,7 @@
|
|||
| [InjectedMetadataSetup](./kibana-plugin-public.injectedmetadatasetup.md) | Provides access to the metadata injected by the server into the page |
|
||||
| [LegacyNavLink](./kibana-plugin-public.legacynavlink.md) | |
|
||||
| [NotificationsSetup](./kibana-plugin-public.notificationssetup.md) | |
|
||||
| [OverlayRef](./kibana-plugin-public.overlayref.md) | |
|
||||
| [OverlayStart](./kibana-plugin-public.overlaystart.md) | |
|
||||
| [Plugin](./kibana-plugin-public.plugin.md) | The interface that should be returned by a <code>PluginInitializer</code>. |
|
||||
| [PluginInitializerContext](./kibana-plugin-public.plugininitializercontext.md) | The available core services passed to a <code>PluginInitializer</code> |
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [OverlayRef](./kibana-plugin-public.overlayref.md) > [close](./kibana-plugin-public.overlayref.close.md)
|
||||
|
||||
## OverlayRef.close() method
|
||||
|
||||
Closes the referenced overlay if it's still open which in turn will resolve the `onClose` Promise. If the overlay had already been closed this method does nothing.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
close(): Promise<void>;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`Promise<void>`
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [OverlayRef](./kibana-plugin-public.overlayref.md)
|
||||
|
||||
## OverlayRef interface
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface OverlayRef
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [onClose](./kibana-plugin-public.overlayref.onclose.md) | <code>Promise<void></code> | A Promise that will resolve once this overlay is closed.<!-- -->Overlays can close from user interaction, calling <code>close()</code> on the overlay reference or another overlay replacing yours via <code>openModal</code> or <code>openFlyout</code>. |
|
||||
|
||||
## Methods
|
||||
|
||||
| Method | Description |
|
||||
| --- | --- |
|
||||
| [close()](./kibana-plugin-public.overlayref.close.md) | Closes the referenced overlay if it's still open which in turn will resolve the <code>onClose</code> Promise. If the overlay had already been closed this method does nothing. |
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [OverlayRef](./kibana-plugin-public.overlayref.md) > [onClose](./kibana-plugin-public.overlayref.onclose.md)
|
||||
|
||||
## OverlayRef.onClose property
|
||||
|
||||
A Promise that will resolve once this overlay is closed.
|
||||
|
||||
Overlays can close from user interaction, calling `close()` on the overlay reference or another overlay replacing yours via `openModal` or `openFlyout`<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
onClose: Promise<void>;
|
||||
```
|
|
@ -15,5 +15,6 @@ export interface OverlayStart
|
|||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [openFlyout](./kibana-plugin-public.overlaystart.openflyout.md) | <code>(flyoutChildren: React.ReactNode, flyoutProps?: {`<p/>` closeButtonAriaLabel?: string;`<p/>` 'data-test-subj'?: string;`<p/>` }) => FlyoutRef</code> | |
|
||||
| [openFlyout](./kibana-plugin-public.overlaystart.openflyout.md) | <code>(flyoutChildren: React.ReactNode, flyoutProps?: {`<p/>` closeButtonAriaLabel?: string;`<p/>` 'data-test-subj'?: string;`<p/>` }) => OverlayRef</code> | |
|
||||
| [openModal](./kibana-plugin-public.overlaystart.openmodal.md) | <code>(modalChildren: React.ReactNode, modalProps?: {`<p/>` closeButtonAriaLabel?: string;`<p/>` 'data-test-subj'?: string;`<p/>` }) => OverlayRef</code> | |
|
||||
|
||||
|
|
|
@ -10,5 +10,5 @@
|
|||
openFlyout: (flyoutChildren: React.ReactNode, flyoutProps?: {
|
||||
closeButtonAriaLabel?: string;
|
||||
'data-test-subj'?: string;
|
||||
}) => FlyoutRef;
|
||||
}) => OverlayRef;
|
||||
```
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index) > [kibana-plugin-public](./kibana-plugin-public.md) > [OverlayStart](./kibana-plugin-public.overlaystart.md) > [openModal](./kibana-plugin-public.overlaystart.openmodal.md)
|
||||
|
||||
## OverlayStart.openModal property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
openModal: (modalChildren: React.ReactNode, modalProps?: {
|
||||
closeButtonAriaLabel?: string;
|
||||
'data-test-subj'?: string;
|
||||
}) => OverlayRef;
|
||||
```
|
|
@ -68,7 +68,6 @@ export class CoreSystem {
|
|||
private readonly application: ApplicationService;
|
||||
|
||||
private readonly rootDomElement: HTMLElement;
|
||||
private readonly overlayTargetDomElement: HTMLDivElement;
|
||||
private fatalErrorsSetup: FatalErrorsSetup | null = null;
|
||||
|
||||
constructor(params: Params) {
|
||||
|
@ -97,8 +96,7 @@ export class CoreSystem {
|
|||
this.http = new HttpService();
|
||||
this.basePath = new BasePathService();
|
||||
this.uiSettings = new UiSettingsService();
|
||||
this.overlayTargetDomElement = document.createElement('div');
|
||||
this.overlay = new OverlayService(this.overlayTargetDomElement);
|
||||
this.overlay = new OverlayService();
|
||||
this.application = new ApplicationService();
|
||||
this.chrome = new ChromeService({ browserSupportsCsp });
|
||||
|
||||
|
@ -169,6 +167,7 @@ export class CoreSystem {
|
|||
const application = await this.application.start({ basePath, injectedMetadata });
|
||||
|
||||
const notificationsTargetDomElement = document.createElement('div');
|
||||
const overlayTargetDomElement = document.createElement('div');
|
||||
const legacyPlatformTargetDomElement = document.createElement('div');
|
||||
|
||||
// ensure the rootDomElement is empty
|
||||
|
@ -176,13 +175,13 @@ export class CoreSystem {
|
|||
this.rootDomElement.classList.add('coreSystemRootDomElement');
|
||||
this.rootDomElement.appendChild(notificationsTargetDomElement);
|
||||
this.rootDomElement.appendChild(legacyPlatformTargetDomElement);
|
||||
this.rootDomElement.appendChild(this.overlayTargetDomElement);
|
||||
this.rootDomElement.appendChild(overlayTargetDomElement);
|
||||
|
||||
const notifications = await this.notifications.start({
|
||||
i18n,
|
||||
targetDomElement: notificationsTargetDomElement,
|
||||
});
|
||||
const overlays = await this.overlay.start({ i18n });
|
||||
const overlays = this.overlay.start({ i18n, targetDomElement: overlayTargetDomElement });
|
||||
|
||||
const core: CoreStart = {
|
||||
application,
|
||||
|
|
|
@ -41,7 +41,7 @@ import {
|
|||
ToastsApi,
|
||||
NotificationsStart,
|
||||
} from './notifications';
|
||||
import { FlyoutRef, OverlayStart } from './overlays';
|
||||
import { OverlayRef, OverlayStart } from './overlays';
|
||||
import { Plugin, PluginInitializer, PluginInitializerContext, PluginSetupContext } from './plugins';
|
||||
import { UiSettingsClient, UiSettingsSetup, UiSettingsState } from './ui_settings';
|
||||
import { ApplicationSetup, Capabilities, ApplicationStart } from './application';
|
||||
|
@ -119,8 +119,8 @@ export {
|
|||
PluginSetupContext,
|
||||
NotificationsSetup,
|
||||
NotificationsStart,
|
||||
OverlayRef,
|
||||
OverlayStart,
|
||||
FlyoutRef,
|
||||
Toast,
|
||||
ToastInput,
|
||||
ToastsApi,
|
||||
|
|
|
@ -64,7 +64,9 @@ export class NotificationsService {
|
|||
const toastsContainer = document.createElement('div');
|
||||
targetDomElement.appendChild(toastsContainer);
|
||||
|
||||
return { toasts: this.toasts.start({ i18n: i18nDep, targetDomElement: toastsContainer }) };
|
||||
return {
|
||||
toasts: this.toasts.start({ i18n: i18nDep, targetDomElement: toastsContainer }),
|
||||
};
|
||||
}
|
||||
|
||||
public stop() {
|
||||
|
|
64
src/core/public/overlays/__snapshots__/modal.test.tsx.snap
generated
Normal file
64
src/core/public/overlays/__snapshots__/modal.test.tsx.snap
generated
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ModalService ModalRef#close() can be called multiple times on the same ModalRef 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
<div />,
|
||||
],
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`ModalService openModal() renders a modal to the DOM 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
<EuiOverlayMask>
|
||||
<mockConstructor>
|
||||
<EuiModal
|
||||
maxWidth={true}
|
||||
onClose={[Function]}
|
||||
>
|
||||
<span>
|
||||
Modal content
|
||||
</span>
|
||||
</EuiModal>
|
||||
</mockConstructor>
|
||||
</EuiOverlayMask>,
|
||||
<div />,
|
||||
],
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`ModalService openModal() with a currently active modal replaces the current modal with a new one 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
<EuiOverlayMask>
|
||||
<mockConstructor>
|
||||
<EuiModal
|
||||
maxWidth={true}
|
||||
onClose={[Function]}
|
||||
>
|
||||
<span>
|
||||
Modal content 1
|
||||
</span>
|
||||
</EuiModal>
|
||||
</mockConstructor>
|
||||
</EuiOverlayMask>,
|
||||
<div />,
|
||||
],
|
||||
Array [
|
||||
<EuiOverlayMask>
|
||||
<mockConstructor>
|
||||
<EuiModal
|
||||
maxWidth={true}
|
||||
onClose={[Function]}
|
||||
>
|
||||
<span>
|
||||
Flyout content 2
|
||||
</span>
|
||||
</EuiModal>
|
||||
</mockConstructor>
|
||||
</EuiOverlayMask>,
|
||||
<div />,
|
||||
],
|
||||
]
|
||||
`;
|
|
@ -24,6 +24,7 @@ import React from 'react';
|
|||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import { Subject } from 'rxjs';
|
||||
import { I18nSetup } from '../i18n';
|
||||
import { OverlayRef } from './overlay_service';
|
||||
|
||||
/**
|
||||
* A FlyoutRef is a reference to an opened flyout panel. It offers methods to
|
||||
|
@ -36,7 +37,7 @@ import { I18nSetup } from '../i18n';
|
|||
*
|
||||
* @public
|
||||
*/
|
||||
export class FlyoutRef {
|
||||
export class FlyoutRef implements OverlayRef {
|
||||
/**
|
||||
* An Promise that will resolve once this flyout is closed.
|
||||
*
|
||||
|
|
|
@ -17,5 +17,4 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export { OverlayService, OverlayStart } from './overlay_service';
|
||||
export { FlyoutRef } from './flyout';
|
||||
export { OverlayService, OverlayStart, OverlayRef } from './overlay_service';
|
||||
|
|
99
src/core/public/overlays/modal.test.tsx
Normal file
99
src/core/public/overlays/modal.test.tsx
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { mockReactDomRender, mockReactDomUnmount } from './flyout.test.mocks';
|
||||
|
||||
import React from 'react';
|
||||
import { i18nServiceMock } from '../i18n/i18n_service.mock';
|
||||
import { ModalService, ModalRef } from './modal';
|
||||
|
||||
const i18nMock = i18nServiceMock.createSetupContract();
|
||||
|
||||
beforeEach(() => {
|
||||
mockReactDomRender.mockClear();
|
||||
mockReactDomUnmount.mockClear();
|
||||
});
|
||||
|
||||
describe('ModalService', () => {
|
||||
describe('openModal()', () => {
|
||||
it('renders a modal to the DOM', () => {
|
||||
const target = document.createElement('div');
|
||||
const modalService = new ModalService(target);
|
||||
expect(mockReactDomRender).not.toHaveBeenCalled();
|
||||
modalService.openModal(i18nMock, <span>Modal content</span>);
|
||||
expect(mockReactDomRender.mock.calls).toMatchSnapshot();
|
||||
});
|
||||
describe('with a currently active modal', () => {
|
||||
let target: HTMLElement, modalService: ModalService, ref1: ModalRef;
|
||||
beforeEach(() => {
|
||||
target = document.createElement('div');
|
||||
modalService = new ModalService(target);
|
||||
ref1 = modalService.openModal(i18nMock, <span>Modal content 1</span>);
|
||||
});
|
||||
it('replaces the current modal with a new one', () => {
|
||||
modalService.openModal(i18nMock, <span>Flyout content 2</span>);
|
||||
expect(mockReactDomRender.mock.calls).toMatchSnapshot();
|
||||
expect(mockReactDomUnmount).toHaveBeenCalledTimes(1);
|
||||
expect(() => ref1.close()).not.toThrowError();
|
||||
expect(mockReactDomUnmount).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
it('resolves onClose on the previous ref', async () => {
|
||||
const onCloseComplete = jest.fn();
|
||||
ref1.onClose.then(onCloseComplete);
|
||||
modalService.openModal(i18nMock, <span>Flyout content 2</span>);
|
||||
await ref1.onClose;
|
||||
expect(onCloseComplete).toBeCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('ModalRef#close()', () => {
|
||||
it('resolves the onClose Promise', async () => {
|
||||
const target = document.createElement('div');
|
||||
const modalService = new ModalService(target);
|
||||
const ref = modalService.openModal(i18nMock, <span>Flyout content</span>);
|
||||
|
||||
const onCloseComplete = jest.fn();
|
||||
ref.onClose.then(onCloseComplete);
|
||||
await ref.close();
|
||||
await ref.close();
|
||||
expect(onCloseComplete).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
it('can be called multiple times on the same ModalRef', async () => {
|
||||
const target = document.createElement('div');
|
||||
const modalService = new ModalService(target);
|
||||
const ref = modalService.openModal(i18nMock, <span>Flyout content</span>);
|
||||
expect(mockReactDomUnmount).not.toHaveBeenCalled();
|
||||
await ref.close();
|
||||
expect(mockReactDomUnmount.mock.calls).toMatchSnapshot();
|
||||
await ref.close();
|
||||
expect(mockReactDomUnmount).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
it("on a stale ModalRef doesn't affect the active flyout", async () => {
|
||||
const target = document.createElement('div');
|
||||
const modalService = new ModalService(target);
|
||||
const ref1 = modalService.openModal(i18nMock, <span>Modal content 1</span>);
|
||||
const ref2 = modalService.openModal(i18nMock, <span>Modal content 2</span>);
|
||||
const onCloseComplete = jest.fn();
|
||||
ref2.onClose.then(onCloseComplete);
|
||||
mockReactDomUnmount.mockClear();
|
||||
await ref1.close();
|
||||
expect(mockReactDomUnmount).toBeCalledTimes(0);
|
||||
expect(onCloseComplete).toBeCalledTimes(0);
|
||||
});
|
||||
});
|
||||
});
|
122
src/core/public/overlays/modal.tsx
Normal file
122
src/core/public/overlays/modal.tsx
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable max-classes-per-file */
|
||||
|
||||
import { EuiModal, EuiOverlayMask } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import { Subject } from 'rxjs';
|
||||
import { I18nSetup } from '../i18n';
|
||||
import { OverlayRef } from './overlay_service';
|
||||
|
||||
/**
|
||||
* A ModalRef is a reference to an opened modal. It offers methods to
|
||||
* close the modal.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class ModalRef implements OverlayRef {
|
||||
public readonly onClose: Promise<void>;
|
||||
|
||||
private closeSubject = new Subject<void>();
|
||||
|
||||
constructor() {
|
||||
this.onClose = this.closeSubject.toPromise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the referenced modal if it's still open which in turn will
|
||||
* resolve the `onClose` Promise. If the modal had already been
|
||||
* closed this method does nothing.
|
||||
*/
|
||||
public close(): Promise<void> {
|
||||
if (!this.closeSubject.closed) {
|
||||
this.closeSubject.next();
|
||||
this.closeSubject.complete();
|
||||
}
|
||||
return this.onClose;
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export class ModalService {
|
||||
private activeModal: ModalRef | null = null;
|
||||
|
||||
constructor(private readonly targetDomElement: Element) {}
|
||||
|
||||
/**
|
||||
* Opens a flyout panel with the given component inside. You can use
|
||||
* `close()` on the returned FlyoutRef to close the flyout.
|
||||
*
|
||||
* @param flyoutChildren - Mounts the children inside a flyout panel
|
||||
* @return {FlyoutRef} A reference to the opened flyout panel.
|
||||
*/
|
||||
public openModal = (
|
||||
i18n: I18nSetup,
|
||||
modalChildren: React.ReactNode,
|
||||
modalProps: {
|
||||
closeButtonAriaLabel?: string;
|
||||
'data-test-subj'?: string;
|
||||
} = {}
|
||||
): ModalRef => {
|
||||
// If there is an active flyout session close it before opening a new one.
|
||||
if (this.activeModal) {
|
||||
this.activeModal.close();
|
||||
this.cleanupDom();
|
||||
}
|
||||
|
||||
const modal = new ModalRef();
|
||||
|
||||
// If a modal gets closed through it's ModalRef, remove it from the dom
|
||||
modal.onClose.then(() => {
|
||||
if (this.activeModal === modal) {
|
||||
this.cleanupDom();
|
||||
}
|
||||
});
|
||||
|
||||
this.activeModal = modal;
|
||||
|
||||
render(
|
||||
<EuiOverlayMask>
|
||||
<i18n.Context>
|
||||
<EuiModal {...modalProps} onClose={() => modal.close()}>
|
||||
{modalChildren}
|
||||
</EuiModal>
|
||||
</i18n.Context>
|
||||
</EuiOverlayMask>,
|
||||
this.targetDomElement
|
||||
);
|
||||
|
||||
return modal;
|
||||
};
|
||||
|
||||
/**
|
||||
* Using React.Render to re-render into a target DOM element will replace
|
||||
* the content of the target but won't call unmountComponent on any
|
||||
* components inside the target or any of their children. So we properly
|
||||
* cleanup the DOM here to prevent subtle bugs in child components which
|
||||
* depend on unmounting for cleanup behaviour.
|
||||
*/
|
||||
private cleanupDom(): void {
|
||||
unmountComponentAtNode(this.targetDomElement);
|
||||
this.targetDomElement.innerHTML = '';
|
||||
this.activeModal = null;
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ import { OverlayService, OverlayStart } from './overlay_service';
|
|||
const createStartContractMock = () => {
|
||||
const startContract: jest.Mocked<PublicMethodsOf<OverlayStart>> = {
|
||||
openFlyout: jest.fn(),
|
||||
openModal: jest.fn(),
|
||||
};
|
||||
return startContract;
|
||||
};
|
||||
|
|
|
@ -18,25 +18,47 @@
|
|||
*/
|
||||
|
||||
import { FlyoutService } from './flyout';
|
||||
|
||||
import { FlyoutRef } from '..';
|
||||
import { ModalService } from './modal';
|
||||
import { I18nStart } from '../i18n';
|
||||
|
||||
export interface OverlayRef {
|
||||
/**
|
||||
* A Promise that will resolve once this overlay is closed.
|
||||
*
|
||||
* Overlays can close from user interaction, calling `close()` on the overlay
|
||||
* reference or another overlay replacing yours via `openModal` or `openFlyout`.
|
||||
*/
|
||||
onClose: Promise<void>;
|
||||
|
||||
/**
|
||||
* Closes the referenced overlay if it's still open which in turn will
|
||||
* resolve the `onClose` Promise. If the overlay had already been
|
||||
* closed this method does nothing.
|
||||
*/
|
||||
close(): Promise<void>;
|
||||
}
|
||||
|
||||
interface StartDeps {
|
||||
i18n: I18nStart;
|
||||
targetDomElement: HTMLElement;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export class OverlayService {
|
||||
private flyoutService: FlyoutService;
|
||||
private flyoutService?: FlyoutService;
|
||||
private modalService?: ModalService;
|
||||
|
||||
constructor(targetDomElement: HTMLElement) {
|
||||
this.flyoutService = new FlyoutService(targetDomElement);
|
||||
}
|
||||
public start({ i18n, targetDomElement }: StartDeps): OverlayStart {
|
||||
const flyoutElement = document.createElement('div');
|
||||
const modalElement = document.createElement('div');
|
||||
targetDomElement.appendChild(flyoutElement);
|
||||
targetDomElement.appendChild(modalElement);
|
||||
this.flyoutService = new FlyoutService(flyoutElement);
|
||||
this.modalService = new ModalService(modalElement);
|
||||
|
||||
public start({ i18n }: StartDeps): OverlayStart {
|
||||
return {
|
||||
openFlyout: this.flyoutService.openFlyout.bind(this.flyoutService, i18n),
|
||||
openModal: this.modalService.openModal.bind(this.modalService, i18n),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -49,5 +71,12 @@ export interface OverlayStart {
|
|||
closeButtonAriaLabel?: string;
|
||||
'data-test-subj'?: string;
|
||||
}
|
||||
) => FlyoutRef;
|
||||
) => OverlayRef;
|
||||
openModal: (
|
||||
modalChildren: React.ReactNode,
|
||||
modalProps?: {
|
||||
closeButtonAriaLabel?: string;
|
||||
'data-test-subj'?: string;
|
||||
}
|
||||
) => OverlayRef;
|
||||
}
|
||||
|
|
|
@ -157,13 +157,6 @@ export interface FatalErrorsSetup {
|
|||
get$: () => Rx.Observable<ErrorInfo>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export class FlyoutRef {
|
||||
constructor();
|
||||
close(): Promise<void>;
|
||||
readonly onClose: Promise<void>;
|
||||
}
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "HttpService" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// @public (undocumented)
|
||||
|
@ -288,6 +281,14 @@ export interface NotificationsSetup {
|
|||
// @public (undocumented)
|
||||
export type NotificationsStart = NotificationsSetup;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "OverlayRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export interface OverlayRef {
|
||||
close(): Promise<void>;
|
||||
onClose: Promise<void>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface OverlayStart {
|
||||
// Warning: (ae-forgotten-export) The symbol "React" needs to be exported by the entry point index.d.ts
|
||||
|
@ -296,7 +297,12 @@ export interface OverlayStart {
|
|||
openFlyout: (flyoutChildren: React.ReactNode, flyoutProps?: {
|
||||
closeButtonAriaLabel?: string;
|
||||
'data-test-subj'?: string;
|
||||
}) => FlyoutRef;
|
||||
}) => OverlayRef;
|
||||
// (undocumented)
|
||||
openModal: (modalChildren: React.ReactNode, modalProps?: {
|
||||
closeButtonAriaLabel?: string;
|
||||
'data-test-subj'?: string;
|
||||
}) => OverlayRef;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
import React from 'react';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FlyoutRef } from '../../../../core/public';
|
||||
import { OverlayRef } from '../../../../core/public';
|
||||
import { getNewPlatform } from '../new_platform';
|
||||
import { Adapters } from './types';
|
||||
import { InspectorPanel } from './ui/inspector_panel';
|
||||
|
@ -50,7 +50,7 @@ interface InspectorOptions {
|
|||
title?: string;
|
||||
}
|
||||
|
||||
export type InspectorSession = FlyoutRef;
|
||||
export type InspectorSession = OverlayRef;
|
||||
|
||||
/**
|
||||
* Opens the inspector panel for the given adapters and close any previously opened
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue