mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Dashboard] Makes lens default editor for creating new panels (#96181)
* Makes lens default editor in dashboard Added all editors menu to dashboard panel toolbar Fixed toggle on editor menu Removed unnecessary comments Added data test subjects to editor menu buttons Populated editor menu with vis types Removed unused imports Fixed imports Adds showCreateNewMenu prop to AddPanelFlyout Rearranged order of editor menu options Fixed ts errors Added groupnig to embeddable factory Use embeddable state transfer service to redirect to editors Added showGroups to TypeSelectionState Fixed add panel flyout test Fixed data test subjects Fixed factory groupings Removed unused import Fixed page object Added telemtry to dashboard toolbar Added telemtry to editor menu Fix ml embeddable functional tests Fix lens dashboard test Fix empty dashboard test Fixed ts errors Fixed time to visualize security test Fixed empty dashboard test Fixed clickAddNewEmbeddableLink in dashboardAddPanel service Fixed agg based vis functional tests Revert test changes Fixed typo Fix tests Fix more tests Fix ts errors Fixed more tests Fixed toolbar sizes and margins to align with lens Fix tests Fixed callbacks Fixed button prop type New vis modal copy updates Added savedObjectMetaData to log stream embeddable factory Addressed feedback Fixed ts error Fix more tests Fixed ts errors Updated dashboard empty prompt copy Adds tooltip to log stream embeddable factory saved object meta data Made icons monochrome in toolbar Fixed icon colors in dark mode Cleaned up css Fixed ts errors Updated snapshot Fixed map icon color * Added tooltips for ML embeddables * Restored test * Added empty dashboard panel test * Fixed i18n id * Fix dashboard_embedding test * Removed unused service * Fixed i18n error * Added icon and description properties to embeddable factory definition * Fixed ts errors * Fixed expected value Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
a89b756710
commit
3b31d81196
66 changed files with 686 additions and 232 deletions
|
@ -0,0 +1,17 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-embeddable-public](./kibana-plugin-plugins-embeddable-public.md) > [EmbeddableFactory](./kibana-plugin-plugins-embeddable-public.embeddablefactory.md) > [getDescription](./kibana-plugin-plugins-embeddable-public.embeddablefactory.getdescription.md)
|
||||
|
||||
## EmbeddableFactory.getDescription() method
|
||||
|
||||
Returns a description about the embeddable.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
getDescription(): string;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`string`
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-embeddable-public](./kibana-plugin-plugins-embeddable-public.md) > [EmbeddableFactory](./kibana-plugin-plugins-embeddable-public.embeddablefactory.md) > [getIconType](./kibana-plugin-plugins-embeddable-public.embeddablefactory.geticontype.md)
|
||||
|
||||
## EmbeddableFactory.getIconType() method
|
||||
|
||||
Returns an EUI Icon type to be displayed in a menu.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
getIconType(): string;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`string`
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-embeddable-public](./kibana-plugin-plugins-embeddable-public.md) > [EmbeddableFactory](./kibana-plugin-plugins-embeddable-public.embeddablefactory.md) > [grouping](./kibana-plugin-plugins-embeddable-public.embeddablefactory.grouping.md)
|
||||
|
||||
## EmbeddableFactory.grouping property
|
||||
|
||||
Indicates the grouping this factory should appear in a sub-menu. Example, this is used for grouping options in the editors menu in Dashboard for creating new embeddables
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
readonly grouping?: UiActionsPresentableGrouping;
|
||||
```
|
|
@ -16,6 +16,7 @@ export interface EmbeddableFactory<TEmbeddableInput extends EmbeddableInput = Em
|
|||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [grouping](./kibana-plugin-plugins-embeddable-public.embeddablefactory.grouping.md) | <code>UiActionsPresentableGrouping</code> | Indicates the grouping this factory should appear in a sub-menu. Example, this is used for grouping options in the editors menu in Dashboard for creating new embeddables |
|
||||
| [isContainerType](./kibana-plugin-plugins-embeddable-public.embeddablefactory.iscontainertype.md) | <code>boolean</code> | True if is this factory create embeddables that are Containers. Used in the add panel to conditionally show whether these can be added to another container. It's just not supported right now, but once nested containers are officially supported we can probably get rid of this interface. |
|
||||
| [isEditable](./kibana-plugin-plugins-embeddable-public.embeddablefactory.iseditable.md) | <code>() => Promise<boolean></code> | Returns whether the current user should be allowed to edit this type of embeddable. Most of the time this should be based off the capabilities service, hence it's async. |
|
||||
| [savedObjectMetaData](./kibana-plugin-plugins-embeddable-public.embeddablefactory.savedobjectmetadata.md) | <code>SavedObjectMetaData<TSavedObjectAttributes></code> | |
|
||||
|
@ -29,6 +30,8 @@ export interface EmbeddableFactory<TEmbeddableInput extends EmbeddableInput = Em
|
|||
| [create(initialInput, parent)](./kibana-plugin-plugins-embeddable-public.embeddablefactory.create.md) | Resolves to undefined if a new Embeddable cannot be directly created and the user will instead be redirected elsewhere.<!-- -->This will likely change in future iterations when we improve in place editing capabilities. |
|
||||
| [createFromSavedObject(savedObjectId, input, parent)](./kibana-plugin-plugins-embeddable-public.embeddablefactory.createfromsavedobject.md) | Creates a new embeddable instance based off the saved object id. |
|
||||
| [getDefaultInput(partial)](./kibana-plugin-plugins-embeddable-public.embeddablefactory.getdefaultinput.md) | Can be used to get any default input, to be passed in to during the creation process. Default input will not be stored in a parent container, so any inherited input from a container will trump default input parameters. |
|
||||
| [getDescription()](./kibana-plugin-plugins-embeddable-public.embeddablefactory.getdescription.md) | Returns a description about the embeddable. |
|
||||
| [getDisplayName()](./kibana-plugin-plugins-embeddable-public.embeddablefactory.getdisplayname.md) | Returns a display name for this type of embeddable. Used in "Create new... " options in the add panel for containers. |
|
||||
| [getExplicitInput()](./kibana-plugin-plugins-embeddable-public.embeddablefactory.getexplicitinput.md) | Can be used to request explicit input from the user, to be passed in to <code>EmbeddableFactory:create</code>. Explicit input is stored on the parent container for this embeddable. It overrides any inherited input passed down from the parent container. |
|
||||
| [getIconType()](./kibana-plugin-plugins-embeddable-public.embeddablefactory.geticontype.md) | Returns an EUI Icon type to be displayed in a menu. |
|
||||
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type EmbeddableFactoryDefinition<I extends EmbeddableInput = EmbeddableInput, O extends EmbeddableOutput = EmbeddableOutput, E extends IEmbeddable<I, O> = IEmbeddable<I, O>, T extends SavedObjectAttributes = SavedObjectAttributes> = Pick<EmbeddableFactory<I, O, E, T>, 'create' | 'type' | 'isEditable' | 'getDisplayName'> & Partial<Pick<EmbeddableFactory<I, O, E, T>, 'createFromSavedObject' | 'isContainerType' | 'getExplicitInput' | 'savedObjectMetaData' | 'canCreateNew' | 'getDefaultInput' | 'telemetry' | 'extract' | 'inject' | 'migrations'>>;
|
||||
export declare type EmbeddableFactoryDefinition<I extends EmbeddableInput = EmbeddableInput, O extends EmbeddableOutput = EmbeddableOutput, E extends IEmbeddable<I, O> = IEmbeddable<I, O>, T extends SavedObjectAttributes = SavedObjectAttributes> = Pick<EmbeddableFactory<I, O, E, T>, 'create' | 'type' | 'isEditable' | 'getDisplayName'> & Partial<Pick<EmbeddableFactory<I, O, E, T>, 'createFromSavedObject' | 'isContainerType' | 'getExplicitInput' | 'savedObjectMetaData' | 'canCreateNew' | 'getDefaultInput' | 'telemetry' | 'extract' | 'inject' | 'migrations' | 'grouping' | 'getIconType' | 'getDescription'>>;
|
||||
```
|
||||
|
|
|
@ -14,6 +14,7 @@ export declare function openAddPanelFlyout(options: {
|
|||
overlays: OverlayStart;
|
||||
notifications: NotificationsStart;
|
||||
SavedObjectFinder: React.ComponentType<any>;
|
||||
showCreateNewMenu?: boolean;
|
||||
}): OverlayRef;
|
||||
```
|
||||
|
||||
|
@ -21,7 +22,7 @@ export declare function openAddPanelFlyout(options: {
|
|||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| options | <code>{</code><br/><code> embeddable: IContainer;</code><br/><code> getFactory: EmbeddableStart['getEmbeddableFactory'];</code><br/><code> getAllFactories: EmbeddableStart['getEmbeddableFactories'];</code><br/><code> overlays: OverlayStart;</code><br/><code> notifications: NotificationsStart;</code><br/><code> SavedObjectFinder: React.ComponentType<any>;</code><br/><code>}</code> | |
|
||||
| options | <code>{</code><br/><code> embeddable: IContainer;</code><br/><code> getFactory: EmbeddableStart['getEmbeddableFactory'];</code><br/><code> getAllFactories: EmbeddableStart['getEmbeddableFactories'];</code><br/><code> overlays: OverlayStart;</code><br/><code> notifications: NotificationsStart;</code><br/><code> SavedObjectFinder: React.ComponentType<any>;</code><br/><code> showCreateNewMenu?: boolean;</code><br/><code>}</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
"share",
|
||||
"uiActions",
|
||||
"urlForwarding",
|
||||
"presentationUtil"
|
||||
"presentationUtil",
|
||||
"visualizations"
|
||||
],
|
||||
"optionalPlugins": [
|
||||
"home",
|
||||
|
|
|
@ -66,4 +66,17 @@
|
|||
.dshUnsavedListingItem__actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary fix for two tone icons to make them monochrome
|
||||
.dshSolutionToolbar__editorContextMenu--dark {
|
||||
.euiIcon path {
|
||||
fill: $euiColorGhost;
|
||||
}
|
||||
}
|
||||
|
||||
.dshSolutionToolbar__editorContextMenu--light {
|
||||
.euiIcon path {
|
||||
fill: $euiColorInk;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@ export async function mountApp({
|
|||
embeddable: embeddableStart,
|
||||
kibanaLegacy: { dashboardConfig },
|
||||
savedObjectsTaggingOss,
|
||||
visualizations,
|
||||
} = pluginsStart;
|
||||
|
||||
const spacesApi = pluginsStart.spacesOss?.isSpacesAvailable ? pluginsStart.spacesOss : undefined;
|
||||
|
@ -123,6 +124,7 @@ export async function mountApp({
|
|||
visualizeCapabilities: { save: Boolean(coreStart.application.capabilities.visualize?.save) },
|
||||
storeSearchSession: Boolean(coreStart.application.capabilities.dashboard.storeSearchSession),
|
||||
},
|
||||
visualizations,
|
||||
};
|
||||
|
||||
const getUrlStateStorage = (history: RouteComponentProps['history']) =>
|
||||
|
|
|
@ -49,7 +49,7 @@ export class DashboardContainerFactoryDefinition
|
|||
|
||||
public readonly getDisplayName = () => {
|
||||
return i18n.translate('dashboard.factory.displayName', {
|
||||
defaultMessage: 'dashboard',
|
||||
defaultMessage: 'Dashboard',
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -287,7 +287,7 @@ exports[`DashboardEmptyScreen renders correctly with edit mode 1`] = `
|
|||
<h3
|
||||
className="euiTitle euiTitle--xsmall"
|
||||
>
|
||||
Add your first panel
|
||||
Add your first visualization
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiSpacer
|
||||
|
|
|
@ -23,6 +23,7 @@ import { createKbnUrlStateStorage } from '../../services/kibana_utils';
|
|||
import { savedObjectsPluginMock } from '../../../../saved_objects/public/mocks';
|
||||
import { DashboardListing, DashboardListingProps } from './dashboard_listing';
|
||||
import { embeddablePluginMock } from '../../../../embeddable/public/mocks';
|
||||
import { visualizationsPluginMock } from '../../../../visualizations/public/mocks';
|
||||
import { DashboardAppServices, DashboardCapabilities } from '../types';
|
||||
import { dataPluginMock } from '../../../../data/public/mocks';
|
||||
import { chromeServiceMock, coreMock } from '../../../../../core/public/mocks';
|
||||
|
@ -76,6 +77,7 @@ function makeDefaultServices(): DashboardAppServices {
|
|||
dashboardPanelStorage,
|
||||
savedDashboards,
|
||||
core,
|
||||
visualizations: visualizationsPluginMock.createStartContract(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,26 +6,24 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { METRIC_TYPE } from '@kbn/analytics';
|
||||
import { EuiHorizontalRule } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import angular from 'angular';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import UseUnmount from 'react-use/lib/useUnmount';
|
||||
import { BaseVisType, VisTypeAlias } from '../../../../visualizations/public';
|
||||
import {
|
||||
AddFromLibraryButton,
|
||||
PrimaryActionButton,
|
||||
QuickButtonGroup,
|
||||
SolutionToolbar,
|
||||
QuickButtonProps,
|
||||
} from '../../../../presentation_util/public';
|
||||
import { useKibana } from '../../services/kibana_react';
|
||||
import { IndexPattern, SavedQuery, TimefilterContract } from '../../services/data';
|
||||
import {
|
||||
EmbeddableFactoryNotFoundError,
|
||||
EmbeddableInput,
|
||||
isErrorEmbeddable,
|
||||
openAddPanelFlyout,
|
||||
ViewMode,
|
||||
} from '../../services/embeddable';
|
||||
import { isErrorEmbeddable, openAddPanelFlyout, ViewMode } from '../../services/embeddable';
|
||||
import {
|
||||
getSavedObjectFinder,
|
||||
SavedObjectSaveOpts,
|
||||
|
@ -55,6 +53,7 @@ import { DashboardConstants } from '../../dashboard_constants';
|
|||
import { getNewDashboardTitle, unsavedChangesBadge } from '../../dashboard_strings';
|
||||
import { DASHBOARD_PANELS_UNSAVED_ID } from '../lib/dashboard_panel_storage';
|
||||
import { DashboardContainer } from '..';
|
||||
import { EditorMenu } from './editor_menu';
|
||||
|
||||
export interface DashboardTopNavState {
|
||||
chromeIsVisible: boolean;
|
||||
|
@ -104,12 +103,22 @@ export function DashboardTopNav({
|
|||
dashboardCapabilities,
|
||||
dashboardPanelStorage,
|
||||
allowByValueEmbeddables,
|
||||
visualizations,
|
||||
usageCollection,
|
||||
} = useKibana<DashboardAppServices>().services;
|
||||
|
||||
const [state, setState] = useState<DashboardTopNavState>({ chromeIsVisible: false });
|
||||
const [isSaveInProgress, setIsSaveInProgress] = useState(false);
|
||||
|
||||
const lensAlias = visualizations.getAliases().find(({ name }) => name === 'lens');
|
||||
const quickButtonVisTypes = ['markdown', 'maps'];
|
||||
const stateTransferService = embeddable.getStateTransfer();
|
||||
const IS_DARK_THEME = uiSettings.get('theme:darkMode');
|
||||
|
||||
const trackUiMetric = usageCollection?.reportUiCounter.bind(
|
||||
usageCollection,
|
||||
DashboardConstants.DASHBOARDS_ID
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const visibleSubscription = chrome.getIsVisible$().subscribe((chromeIsVisible) => {
|
||||
|
@ -152,27 +161,36 @@ export function DashboardTopNav({
|
|||
uiSettings,
|
||||
]);
|
||||
|
||||
const createNew = useCallback(async () => {
|
||||
const type = 'visualization';
|
||||
const factory = embeddable.getEmbeddableFactory(type);
|
||||
|
||||
if (!factory) {
|
||||
throw new EmbeddableFactoryNotFoundError(type);
|
||||
}
|
||||
|
||||
await factory.create({} as EmbeddableInput, dashboardContainer);
|
||||
}, [dashboardContainer, embeddable]);
|
||||
|
||||
const createNewVisType = useCallback(
|
||||
(newVisType: string) => async () => {
|
||||
stateTransferService.navigateToEditor('visualize', {
|
||||
path: `#/create?type=${encodeURIComponent(newVisType)}`,
|
||||
(visType?: BaseVisType | VisTypeAlias) => () => {
|
||||
let path = '';
|
||||
let appId = '';
|
||||
|
||||
if (visType) {
|
||||
if (trackUiMetric) {
|
||||
trackUiMetric(METRIC_TYPE.CLICK, visType.name);
|
||||
}
|
||||
|
||||
if ('aliasPath' in visType) {
|
||||
appId = visType.aliasApp;
|
||||
path = visType.aliasPath;
|
||||
} else {
|
||||
appId = 'visualize';
|
||||
path = `#/create?type=${encodeURIComponent(visType.name)}`;
|
||||
}
|
||||
} else {
|
||||
appId = 'visualize';
|
||||
path = '#/create?';
|
||||
}
|
||||
|
||||
stateTransferService.navigateToEditor(appId, {
|
||||
path,
|
||||
state: {
|
||||
originatingApp: DashboardConstants.DASHBOARDS_ID,
|
||||
},
|
||||
});
|
||||
},
|
||||
[stateTransferService]
|
||||
[trackUiMetric, stateTransferService]
|
||||
);
|
||||
|
||||
const clearAddPanel = useCallback(() => {
|
||||
|
@ -563,38 +581,57 @@ export function DashboardTopNav({
|
|||
|
||||
const { TopNavMenu } = navigation.ui;
|
||||
|
||||
const quickButtons = [
|
||||
{
|
||||
iconType: 'visText',
|
||||
createType: i18n.translate('dashboard.solutionToolbar.markdownQuickButtonLabel', {
|
||||
defaultMessage: 'Markdown',
|
||||
}),
|
||||
onClick: createNewVisType('markdown'),
|
||||
'data-test-subj': 'dashboardMarkdownQuickButton',
|
||||
},
|
||||
{
|
||||
iconType: 'controlsHorizontal',
|
||||
createType: i18n.translate('dashboard.solutionToolbar.inputControlsQuickButtonLabel', {
|
||||
defaultMessage: 'Input control',
|
||||
}),
|
||||
onClick: createNewVisType('input_control_vis'),
|
||||
'data-test-subj': 'dashboardInputControlsQuickButton',
|
||||
},
|
||||
];
|
||||
const getVisTypeQuickButton = (visTypeName: string) => {
|
||||
const visType =
|
||||
visualizations.get(visTypeName) ||
|
||||
visualizations.getAliases().find(({ name }) => name === visTypeName);
|
||||
|
||||
if (visType) {
|
||||
if ('aliasPath' in visType) {
|
||||
const { name, icon, title } = visType as VisTypeAlias;
|
||||
|
||||
return {
|
||||
iconType: icon,
|
||||
createType: title,
|
||||
onClick: createNewVisType(visType as VisTypeAlias),
|
||||
'data-test-subj': `dashboardQuickButton${name}`,
|
||||
isDarkModeEnabled: IS_DARK_THEME,
|
||||
};
|
||||
} else {
|
||||
const { name, icon, title, titleInWizard } = visType as BaseVisType;
|
||||
|
||||
return {
|
||||
iconType: icon,
|
||||
createType: titleInWizard || title,
|
||||
onClick: createNewVisType(visType as BaseVisType),
|
||||
'data-test-subj': `dashboardQuickButton${name}`,
|
||||
isDarkModeEnabled: IS_DARK_THEME,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
const quickButtons = quickButtonVisTypes
|
||||
.map(getVisTypeQuickButton)
|
||||
.filter((button) => button) as QuickButtonProps[];
|
||||
|
||||
return (
|
||||
<>
|
||||
<TopNavMenu {...getNavBarProps()} />
|
||||
<EuiHorizontalRule margin="none" />
|
||||
{viewMode !== ViewMode.VIEW ? (
|
||||
<SolutionToolbar>
|
||||
<SolutionToolbar isDarkModeEnabled={IS_DARK_THEME}>
|
||||
{{
|
||||
primaryActionButton: (
|
||||
<PrimaryActionButton
|
||||
isDarkModeEnabled={IS_DARK_THEME}
|
||||
label={i18n.translate('dashboard.solutionToolbar.addPanelButtonLabel', {
|
||||
defaultMessage: 'Create panel',
|
||||
defaultMessage: 'Create visualization',
|
||||
})}
|
||||
onClick={createNew}
|
||||
iconType="plusInCircleFilled"
|
||||
onClick={createNewVisType(lensAlias)}
|
||||
iconType="lensApp"
|
||||
data-test-subj="dashboardAddNewPanelButton"
|
||||
/>
|
||||
),
|
||||
|
@ -605,6 +642,12 @@ export function DashboardTopNav({
|
|||
data-test-subj="dashboardAddPanelButton"
|
||||
/>
|
||||
),
|
||||
extraButtons: [
|
||||
<EditorMenu
|
||||
createNewVisType={createNewVisType}
|
||||
dashboardContainer={dashboardContainer}
|
||||
/>,
|
||||
],
|
||||
}}
|
||||
</SolutionToolbar>
|
||||
) : null}
|
||||
|
|
255
src/plugins/dashboard/public/application/top_nav/editor_menu.tsx
Normal file
255
src/plugins/dashboard/public/application/top_nav/editor_menu.tsx
Normal file
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { useCallback } from 'react';
|
||||
import {
|
||||
EuiContextMenu,
|
||||
EuiContextMenuPanelItemDescriptor,
|
||||
EuiContextMenuItemIcon,
|
||||
} from '@elastic/eui';
|
||||
import { METRIC_TYPE } from '@kbn/analytics';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { BaseVisType, VisGroups, VisTypeAlias } from '../../../../visualizations/public';
|
||||
import { SolutionToolbarPopover } from '../../../../presentation_util/public';
|
||||
import { EmbeddableFactoryDefinition, EmbeddableInput } from '../../services/embeddable';
|
||||
import { useKibana } from '../../services/kibana_react';
|
||||
import { DashboardAppServices } from '../types';
|
||||
import { DashboardContainer } from '..';
|
||||
import { DashboardConstants } from '../../dashboard_constants';
|
||||
import { dashboardReplacePanelAction } from '../../dashboard_strings';
|
||||
|
||||
interface Props {
|
||||
/** Dashboard container */
|
||||
dashboardContainer: DashboardContainer;
|
||||
/** Handler for creating new visualization of a specified type */
|
||||
createNewVisType: (visType: BaseVisType | VisTypeAlias) => () => void;
|
||||
}
|
||||
|
||||
interface FactoryGroup {
|
||||
id: string;
|
||||
appName: string;
|
||||
icon: EuiContextMenuItemIcon;
|
||||
panelId: number;
|
||||
factories: EmbeddableFactoryDefinition[];
|
||||
}
|
||||
|
||||
export const EditorMenu = ({ dashboardContainer, createNewVisType }: Props) => {
|
||||
const {
|
||||
core,
|
||||
embeddable,
|
||||
visualizations,
|
||||
usageCollection,
|
||||
uiSettings,
|
||||
} = useKibana<DashboardAppServices>().services;
|
||||
|
||||
const IS_DARK_THEME = uiSettings.get('theme:darkMode');
|
||||
|
||||
const trackUiMetric = usageCollection?.reportUiCounter.bind(
|
||||
usageCollection,
|
||||
DashboardConstants.DASHBOARDS_ID
|
||||
);
|
||||
|
||||
const createNewAggsBasedVis = useCallback(
|
||||
(visType?: BaseVisType) => () =>
|
||||
visualizations.showNewVisModal({
|
||||
originatingApp: DashboardConstants.DASHBOARDS_ID,
|
||||
outsideVisualizeApp: true,
|
||||
showAggsSelection: true,
|
||||
selectedVisType: visType,
|
||||
}),
|
||||
[visualizations]
|
||||
);
|
||||
|
||||
const getVisTypesByGroup = (group: VisGroups) =>
|
||||
visualizations
|
||||
.getByGroup(group)
|
||||
.sort(({ name: a }: BaseVisType | VisTypeAlias, { name: b }: BaseVisType | VisTypeAlias) => {
|
||||
if (a < b) {
|
||||
return -1;
|
||||
}
|
||||
if (a > b) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
.filter(({ hidden }: BaseVisType) => !hidden);
|
||||
|
||||
const promotedVisTypes = getVisTypesByGroup(VisGroups.PROMOTED);
|
||||
const aggsBasedVisTypes = getVisTypesByGroup(VisGroups.AGGBASED);
|
||||
const toolVisTypes = getVisTypesByGroup(VisGroups.TOOLS);
|
||||
const visTypeAliases = visualizations
|
||||
.getAliases()
|
||||
.sort(({ promotion: a = false }: VisTypeAlias, { promotion: b = false }: VisTypeAlias) =>
|
||||
a === b ? 0 : a ? -1 : 1
|
||||
);
|
||||
|
||||
const factories = embeddable
|
||||
? Array.from(embeddable.getEmbeddableFactories()).filter(
|
||||
({ type, isEditable, canCreateNew, isContainerType }) =>
|
||||
isEditable() && !isContainerType && canCreateNew() && type !== 'visualization'
|
||||
)
|
||||
: [];
|
||||
|
||||
const factoryGroupMap: Record<string, FactoryGroup> = {};
|
||||
const ungroupedFactories: EmbeddableFactoryDefinition[] = [];
|
||||
const aggBasedPanelID = 1;
|
||||
|
||||
let panelCount = 1 + aggBasedPanelID;
|
||||
|
||||
factories.forEach((factory: EmbeddableFactoryDefinition, index) => {
|
||||
const { grouping } = factory;
|
||||
|
||||
if (grouping) {
|
||||
grouping.forEach((group) => {
|
||||
if (factoryGroupMap[group.id]) {
|
||||
factoryGroupMap[group.id].factories.push(factory);
|
||||
} else {
|
||||
factoryGroupMap[group.id] = {
|
||||
id: group.id,
|
||||
appName: group.getDisplayName ? group.getDisplayName({ embeddable }) : group.id,
|
||||
icon: (group.getIconType
|
||||
? group.getIconType({ embeddable })
|
||||
: 'empty') as EuiContextMenuItemIcon,
|
||||
factories: [factory],
|
||||
panelId: panelCount,
|
||||
};
|
||||
|
||||
panelCount++;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ungroupedFactories.push(factory);
|
||||
}
|
||||
});
|
||||
|
||||
const getVisTypeMenuItem = (visType: BaseVisType): EuiContextMenuPanelItemDescriptor => {
|
||||
const { name, title, titleInWizard, description, icon = 'empty', group } = visType;
|
||||
return {
|
||||
name: titleInWizard || title,
|
||||
icon: icon as string,
|
||||
onClick:
|
||||
group === VisGroups.AGGBASED ? createNewAggsBasedVis(visType) : createNewVisType(visType),
|
||||
'data-test-subj': `visType-${name}`,
|
||||
toolTipContent: description,
|
||||
};
|
||||
};
|
||||
|
||||
const getVisTypeAliasMenuItem = (
|
||||
visTypeAlias: VisTypeAlias
|
||||
): EuiContextMenuPanelItemDescriptor => {
|
||||
const { name, title, description, icon = 'empty' } = visTypeAlias;
|
||||
|
||||
return {
|
||||
name: title,
|
||||
icon,
|
||||
onClick: createNewVisType(visTypeAlias),
|
||||
'data-test-subj': `visType-${name}`,
|
||||
toolTipContent: description,
|
||||
};
|
||||
};
|
||||
|
||||
const getEmbeddableFactoryMenuItem = (
|
||||
factory: EmbeddableFactoryDefinition
|
||||
): EuiContextMenuPanelItemDescriptor => {
|
||||
const icon = factory?.getIconType ? factory.getIconType() : 'empty';
|
||||
|
||||
const toolTipContent = factory?.getDescription ? factory.getDescription() : undefined;
|
||||
|
||||
return {
|
||||
name: factory.getDisplayName(),
|
||||
icon,
|
||||
toolTipContent,
|
||||
onClick: async () => {
|
||||
if (trackUiMetric) {
|
||||
trackUiMetric(METRIC_TYPE.CLICK, factory.type);
|
||||
}
|
||||
let newEmbeddable;
|
||||
if (factory.getExplicitInput) {
|
||||
const explicitInput = await factory.getExplicitInput();
|
||||
newEmbeddable = await dashboardContainer.addNewEmbeddable(factory.type, explicitInput);
|
||||
} else {
|
||||
newEmbeddable = await factory.create({} as EmbeddableInput, dashboardContainer);
|
||||
}
|
||||
|
||||
if (newEmbeddable) {
|
||||
core.notifications.toasts.addSuccess({
|
||||
title: dashboardReplacePanelAction.getSuccessMessage(
|
||||
`'${newEmbeddable.getInput().title}'` || ''
|
||||
),
|
||||
'data-test-subj': 'addEmbeddableToDashboardSuccess',
|
||||
});
|
||||
}
|
||||
},
|
||||
'data-test-subj': `createNew-${factory.type}`,
|
||||
};
|
||||
};
|
||||
|
||||
const aggsPanelTitle = i18n.translate('dashboard.editorMenu.aggBasedGroupTitle', {
|
||||
defaultMessage: 'Aggregation based',
|
||||
});
|
||||
|
||||
const editorMenuPanels = [
|
||||
{
|
||||
id: 0,
|
||||
items: [
|
||||
...visTypeAliases.map(getVisTypeAliasMenuItem),
|
||||
...Object.values(factoryGroupMap).map(({ id, appName, icon, panelId }) => ({
|
||||
name: appName,
|
||||
icon,
|
||||
panel: panelId,
|
||||
'data-test-subj': `dashboardEditorMenu-${id}Group`,
|
||||
})),
|
||||
...ungroupedFactories.map(getEmbeddableFactoryMenuItem),
|
||||
...promotedVisTypes.map(getVisTypeMenuItem),
|
||||
{
|
||||
name: aggsPanelTitle,
|
||||
icon: 'visualizeApp',
|
||||
panel: aggBasedPanelID,
|
||||
'data-test-subj': `dashboardEditorAggBasedMenuItem`,
|
||||
},
|
||||
...toolVisTypes.map(getVisTypeMenuItem),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: aggBasedPanelID,
|
||||
title: aggsPanelTitle,
|
||||
items: aggsBasedVisTypes.map(getVisTypeMenuItem),
|
||||
},
|
||||
...Object.values(factoryGroupMap).map(
|
||||
({ appName, panelId, factories: groupFactories }: FactoryGroup) => ({
|
||||
id: panelId,
|
||||
title: appName,
|
||||
items: groupFactories.map(getEmbeddableFactoryMenuItem),
|
||||
})
|
||||
),
|
||||
];
|
||||
|
||||
return (
|
||||
<SolutionToolbarPopover
|
||||
ownFocus
|
||||
label={i18n.translate('dashboard.solutionToolbar.editorMenuButtonLabel', {
|
||||
defaultMessage: 'All types',
|
||||
})}
|
||||
iconType="arrowDown"
|
||||
iconSide="right"
|
||||
panelPaddingSize="none"
|
||||
data-test-subj="dashboardEditorMenuButton"
|
||||
>
|
||||
<EuiContextMenu
|
||||
initialPanelId={0}
|
||||
panels={editorMenuPanels}
|
||||
className={`dshSolutionToolbar__editorContextMenu ${
|
||||
IS_DARK_THEME
|
||||
? 'dshSolutionToolbar__editorContextMenu--dark'
|
||||
: 'dshSolutionToolbar__editorContextMenu--light'
|
||||
}`}
|
||||
data-test-subj="dashboardEditorContextMenu"
|
||||
/>
|
||||
</SolutionToolbarPopover>
|
||||
);
|
||||
};
|
|
@ -25,6 +25,7 @@ import { DataPublicPluginStart, IndexPatternsContract } from '../services/data';
|
|||
import { SavedObjectLoader, SavedObjectsStart } from '../services/saved_objects';
|
||||
import { DashboardPanelStorage } from './lib';
|
||||
import { UrlForwardingStart } from '../../../url_forwarding/public';
|
||||
import { VisualizationsStart } from '../../../visualizations/public';
|
||||
|
||||
export type DashboardRedirect = (props: RedirectToProps) => void;
|
||||
export type RedirectToProps =
|
||||
|
@ -83,4 +84,5 @@ export interface DashboardAppServices {
|
|||
savedObjectsClient: SavedObjectsClientContract;
|
||||
setHeaderActionMenu: AppMountParameters['setHeaderActionMenu'];
|
||||
savedQueryService: DataPublicPluginStart['query']['savedQueries'];
|
||||
visualizations: VisualizationsStart;
|
||||
}
|
||||
|
|
|
@ -377,7 +377,7 @@ export const emptyScreenStrings = {
|
|||
}),
|
||||
getEmptyWidgetTitle: () =>
|
||||
i18n.translate('dashboard.emptyWidget.addPanelTitle', {
|
||||
defaultMessage: 'Add your first panel',
|
||||
defaultMessage: 'Add your first visualization',
|
||||
}),
|
||||
getEmptyWidgetDescription: () =>
|
||||
i18n.translate('dashboard.emptyWidget.addPanelDescription', {
|
||||
|
|
|
@ -24,6 +24,7 @@ import {
|
|||
PluginInitializerContext,
|
||||
SavedObjectsClientContract,
|
||||
} from '../../../core/public';
|
||||
import { VisualizationsStart } from '../../visualizations/public';
|
||||
|
||||
import { createKbnUrlTracker } from './services/kibana_utils';
|
||||
import { UsageCollectionSetup } from './services/usage_collection';
|
||||
|
@ -115,6 +116,7 @@ export interface DashboardStartDependencies {
|
|||
presentationUtil: PresentationUtilPluginStart;
|
||||
savedObjectsTaggingOss?: SavedObjectTaggingOssPluginStart;
|
||||
spacesOss?: SpacesOssPluginStart;
|
||||
visualizations: VisualizationsStart;
|
||||
}
|
||||
|
||||
export type DashboardSetup = void;
|
||||
|
|
|
@ -37,11 +37,14 @@ export const defaultEmbeddableFactoryProvider = <
|
|||
type: def.type,
|
||||
isEditable: def.isEditable.bind(def),
|
||||
getDisplayName: def.getDisplayName.bind(def),
|
||||
getDescription: def.getDescription ? def.getDescription.bind(def) : () => '',
|
||||
getIconType: def.getIconType ? def.getIconType.bind(def) : () => 'empty',
|
||||
savedObjectMetaData: def.savedObjectMetaData,
|
||||
telemetry: def.telemetry || (() => ({})),
|
||||
inject: def.inject || ((state: EmbeddableStateWithType) => state),
|
||||
extract: def.extract || ((state: EmbeddableStateWithType) => ({ state, references: [] })),
|
||||
migrations: def.migrations || {},
|
||||
grouping: def.grouping,
|
||||
};
|
||||
return factory;
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@ import { IContainer } from '../containers/i_container';
|
|||
import { PropertySpec } from '../types';
|
||||
import { PersistableState } from '../../../../kibana_utils/common';
|
||||
import { EmbeddableStateWithType } from '../../../common/types';
|
||||
import { UiActionsPresentableGrouping } from '../../../../ui_actions/public';
|
||||
|
||||
export interface EmbeddableInstanceConfiguration {
|
||||
id: string;
|
||||
|
@ -48,6 +49,12 @@ export interface EmbeddableFactory<
|
|||
|
||||
readonly savedObjectMetaData?: SavedObjectMetaData<TSavedObjectAttributes>;
|
||||
|
||||
/**
|
||||
* Indicates the grouping this factory should appear in a sub-menu. Example, this is used for grouping
|
||||
* options in the editors menu in Dashboard for creating new embeddables
|
||||
*/
|
||||
readonly grouping?: UiActionsPresentableGrouping;
|
||||
|
||||
/**
|
||||
* True if is this factory create embeddables that are Containers. Used in the add panel to
|
||||
* conditionally show whether these can be added to another container. It's just not
|
||||
|
@ -62,6 +69,16 @@ export interface EmbeddableFactory<
|
|||
*/
|
||||
getDisplayName(): string;
|
||||
|
||||
/**
|
||||
* Returns an EUI Icon type to be displayed in a menu.
|
||||
*/
|
||||
getIconType(): string;
|
||||
|
||||
/**
|
||||
* Returns a description about the embeddable.
|
||||
*/
|
||||
getDescription(): string;
|
||||
|
||||
/**
|
||||
* If false, this type of embeddable can't be created with the "createNew" functionality. Instead,
|
||||
* use createFromSavedObject, where an existing saved object must first exist.
|
||||
|
|
|
@ -33,5 +33,8 @@ export type EmbeddableFactoryDefinition<
|
|||
| 'extract'
|
||||
| 'inject'
|
||||
| 'migrations'
|
||||
| 'grouping'
|
||||
| 'getIconType'
|
||||
| 'getDescription'
|
||||
>
|
||||
>;
|
||||
|
|
|
@ -61,6 +61,7 @@ test('createNewEmbeddable() add embeddable to container', async () => {
|
|||
getAllFactories={start.getEmbeddableFactories}
|
||||
notifications={core.notifications}
|
||||
SavedObjectFinder={() => null}
|
||||
showCreateNewMenu
|
||||
/>
|
||||
) as ReactWrapper<unknown, unknown, AddPanelFlyout>;
|
||||
|
||||
|
@ -112,6 +113,7 @@ test('selecting embeddable in "Create new ..." list calls createNewEmbeddable()'
|
|||
getAllFactories={start.getEmbeddableFactories}
|
||||
notifications={core.notifications}
|
||||
SavedObjectFinder={(props) => <DummySavedObjectFinder {...props} />}
|
||||
showCreateNewMenu
|
||||
/>
|
||||
) as ReactWrapper<any, {}, AddPanelFlyout>;
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ interface Props {
|
|||
getAllFactories: EmbeddableStart['getEmbeddableFactories'];
|
||||
notifications: CoreSetup['notifications'];
|
||||
SavedObjectFinder: React.ComponentType<any>;
|
||||
showCreateNewMenu?: boolean;
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -134,7 +135,9 @@ export class AddPanelFlyout extends React.Component<Props, State> {
|
|||
defaultMessage: 'No matching objects found.',
|
||||
})}
|
||||
>
|
||||
<SavedObjectFinderCreateNew menuItems={this.getCreateMenuItems()} />
|
||||
{this.props.showCreateNewMenu ? (
|
||||
<SavedObjectFinderCreateNew menuItems={this.getCreateMenuItems()} />
|
||||
) : null}
|
||||
</SavedObjectFinder>
|
||||
);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ export function openAddPanelFlyout(options: {
|
|||
overlays: OverlayStart;
|
||||
notifications: NotificationsStart;
|
||||
SavedObjectFinder: React.ComponentType<any>;
|
||||
showCreateNewMenu?: boolean;
|
||||
}): OverlayRef {
|
||||
const {
|
||||
embeddable,
|
||||
|
@ -28,6 +29,7 @@ export function openAddPanelFlyout(options: {
|
|||
overlays,
|
||||
notifications,
|
||||
SavedObjectFinder,
|
||||
showCreateNewMenu,
|
||||
} = options;
|
||||
const flyoutSession = overlays.openFlyout(
|
||||
toMountPoint(
|
||||
|
@ -42,6 +44,7 @@ export function openAddPanelFlyout(options: {
|
|||
getAllFactories={getAllFactories}
|
||||
notifications={notifications}
|
||||
SavedObjectFinder={SavedObjectFinder}
|
||||
showCreateNewMenu={showCreateNewMenu}
|
||||
/>
|
||||
),
|
||||
{
|
||||
|
|
|
@ -378,8 +378,12 @@ export interface EmbeddableFactory<TEmbeddableInput extends EmbeddableInput = Em
|
|||
create(initialInput: TEmbeddableInput, parent?: IContainer): Promise<TEmbeddable | ErrorEmbeddable | undefined>;
|
||||
createFromSavedObject(savedObjectId: string, input: Partial<TEmbeddableInput>, parent?: IContainer): Promise<TEmbeddable | ErrorEmbeddable>;
|
||||
getDefaultInput(partial: Partial<TEmbeddableInput>): Partial<TEmbeddableInput>;
|
||||
getDescription(): string;
|
||||
getDisplayName(): string;
|
||||
getExplicitInput(): Promise<Partial<TEmbeddableInput>>;
|
||||
getIconType(): string;
|
||||
// Warning: (ae-forgotten-export) The symbol "PresentableGrouping" needs to be exported by the entry point index.d.ts
|
||||
readonly grouping?: PresentableGrouping;
|
||||
readonly isContainerType: boolean;
|
||||
readonly isEditable: () => Promise<boolean>;
|
||||
// Warning: (ae-forgotten-export) The symbol "SavedObjectMetaData" needs to be exported by the entry point index.d.ts
|
||||
|
@ -393,7 +397,7 @@ export interface EmbeddableFactory<TEmbeddableInput extends EmbeddableInput = Em
|
|||
// Warning: (ae-missing-release-tag) "EmbeddableFactoryDefinition" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type EmbeddableFactoryDefinition<I extends EmbeddableInput = EmbeddableInput, O extends EmbeddableOutput = EmbeddableOutput, E extends IEmbeddable<I, O> = IEmbeddable<I, O>, T extends SavedObjectAttributes = SavedObjectAttributes> = Pick<EmbeddableFactory<I, O, E, T>, 'create' | 'type' | 'isEditable' | 'getDisplayName'> & Partial<Pick<EmbeddableFactory<I, O, E, T>, 'createFromSavedObject' | 'isContainerType' | 'getExplicitInput' | 'savedObjectMetaData' | 'canCreateNew' | 'getDefaultInput' | 'telemetry' | 'extract' | 'inject' | 'migrations'>>;
|
||||
export type EmbeddableFactoryDefinition<I extends EmbeddableInput = EmbeddableInput, O extends EmbeddableOutput = EmbeddableOutput, E extends IEmbeddable<I, O> = IEmbeddable<I, O>, T extends SavedObjectAttributes = SavedObjectAttributes> = Pick<EmbeddableFactory<I, O, E, T>, 'create' | 'type' | 'isEditable' | 'getDisplayName'> & Partial<Pick<EmbeddableFactory<I, O, E, T>, 'createFromSavedObject' | 'isContainerType' | 'getExplicitInput' | 'savedObjectMetaData' | 'canCreateNew' | 'getDefaultInput' | 'telemetry' | 'extract' | 'inject' | 'migrations' | 'grouping' | 'getIconType' | 'getDescription'>>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "EmbeddableFactoryNotFoundError" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
|
@ -724,6 +728,7 @@ export function openAddPanelFlyout(options: {
|
|||
overlays: OverlayStart_2;
|
||||
notifications: NotificationsStart_2;
|
||||
SavedObjectFinder: React.ComponentType<any>;
|
||||
showCreateNewMenu?: boolean;
|
||||
}): OverlayRef_2;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "OutputSpec" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
.solutionToolbarButton {
|
||||
line-height: $euiButtonHeight; // Keeps alignment of text and chart icon
|
||||
background-color: $euiColorEmptyShade;
|
||||
|
|
|
@ -12,17 +12,19 @@ import { EuiButtonPropsForButton } from '@elastic/eui/src/components/button/butt
|
|||
|
||||
import './button.scss';
|
||||
|
||||
export interface Props extends Pick<EuiButtonPropsForButton, 'onClick' | 'iconType'> {
|
||||
export interface Props
|
||||
extends Pick<EuiButtonPropsForButton, 'onClick' | 'iconType' | 'iconSide' | 'className'> {
|
||||
label: string;
|
||||
primary?: boolean;
|
||||
isDarkModeEnabled?: boolean;
|
||||
}
|
||||
|
||||
export const SolutionToolbarButton = ({ label, primary, ...rest }: Props) => (
|
||||
export const SolutionToolbarButton = ({ label, primary, className, ...rest }: Props) => (
|
||||
<EuiButton
|
||||
{...rest}
|
||||
size="s"
|
||||
size="m"
|
||||
color={primary ? 'primary' : 'text'}
|
||||
className="solutionToolbarButton"
|
||||
className={`solutionToolbarButton ${className}`}
|
||||
fill={primary}
|
||||
>
|
||||
{label}
|
||||
|
|
|
@ -20,14 +20,20 @@ type AllowedPopoverProps = Omit<
|
|||
|
||||
export type Props = AllowedButtonProps & AllowedPopoverProps;
|
||||
|
||||
export const SolutionToolbarPopover = ({ label, iconType, primary, ...popover }: Props) => {
|
||||
export const SolutionToolbarPopover = ({
|
||||
label,
|
||||
iconType,
|
||||
primary,
|
||||
iconSide,
|
||||
...popover
|
||||
}: Props) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const onButtonClick = () => setIsOpen((status) => !status);
|
||||
const closePopover = () => setIsOpen(false);
|
||||
|
||||
const button = (
|
||||
<SolutionToolbarButton {...{ label, iconType, primary }} onClick={onButtonClick} />
|
||||
<SolutionToolbarButton {...{ label, iconType, primary, iconSide }} onClick={onButtonClick} />
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
// Temporary fix for lensApp icon not support ghost color
|
||||
.solutionToolbar__primaryButton--dark {
|
||||
.euiIcon path {
|
||||
fill: $euiColorInk;
|
||||
}
|
||||
}
|
||||
|
||||
.solutionToolbar__primaryButton--light {
|
||||
.euiIcon path {
|
||||
fill: $euiColorGhost;
|
||||
}
|
||||
}
|
|
@ -10,6 +10,20 @@ import React from 'react';
|
|||
|
||||
import { SolutionToolbarButton, Props as SolutionToolbarButtonProps } from './button';
|
||||
|
||||
export const PrimaryActionButton = (props: Omit<SolutionToolbarButtonProps, 'primary'>) => (
|
||||
<SolutionToolbarButton primary={true} {...props} />
|
||||
import './primary_button.scss';
|
||||
|
||||
export interface Props extends Omit<SolutionToolbarButtonProps, 'primary'> {
|
||||
isDarkModeEnabled?: boolean;
|
||||
}
|
||||
|
||||
export const PrimaryActionButton = ({ isDarkModeEnabled, ...props }: Props) => (
|
||||
<SolutionToolbarButton
|
||||
primary={true}
|
||||
className={`solutionToolbar__primaryButton ${
|
||||
isDarkModeEnabled
|
||||
? 'solutionToolbar__primaryButton--dark'
|
||||
: 'solutionToolbar__primaryButton--light'
|
||||
}`}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -2,4 +2,17 @@
|
|||
.quickButtonGroup__button {
|
||||
background-color: $euiColorEmptyShade;
|
||||
}
|
||||
|
||||
// Temporary fix for two tone icons to make them monochrome
|
||||
.quickButtonGroup__button--dark {
|
||||
.euiIcon path {
|
||||
fill: $euiColorGhost;
|
||||
}
|
||||
}
|
||||
// Temporary fix for two tone icons to make them monochrome
|
||||
.quickButtonGroup__button--light {
|
||||
.euiIcon path {
|
||||
fill: $euiColorInk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,23 +17,27 @@ import './quick_group.scss';
|
|||
export interface QuickButtonProps extends Pick<EuiButtonGroupOptionProps, 'iconType'> {
|
||||
createType: string;
|
||||
onClick: () => void;
|
||||
isDarkModeEnabled?: boolean;
|
||||
}
|
||||
|
||||
export interface Props {
|
||||
buttons: QuickButtonProps[];
|
||||
}
|
||||
|
||||
type Option = EuiButtonGroupOptionProps & Omit<QuickButtonProps, 'createType'>;
|
||||
type Option = EuiButtonGroupOptionProps &
|
||||
Omit<QuickButtonProps, 'createType' | 'isDarkModeEnabled'>;
|
||||
|
||||
export const QuickButtonGroup = ({ buttons }: Props) => {
|
||||
const buttonGroupOptions: Option[] = buttons.map((button: QuickButtonProps, index) => {
|
||||
const { createType: label, ...rest } = button;
|
||||
const { createType: label, isDarkModeEnabled, ...rest } = button;
|
||||
const title = strings.getAriaButtonLabel(label);
|
||||
|
||||
return {
|
||||
...rest,
|
||||
'aria-label': title,
|
||||
className: 'quickButtonGroup__button',
|
||||
className: `quickButtonGroup__button ${
|
||||
isDarkModeEnabled ? 'quickButtonGroup__button--dark' : 'quickButtonGroup__button--light'
|
||||
}`,
|
||||
id: `${htmlIdGenerator()()}${index}`,
|
||||
label,
|
||||
title,
|
||||
|
@ -46,7 +50,7 @@ export const QuickButtonGroup = ({ buttons }: Props) => {
|
|||
|
||||
return (
|
||||
<EuiButtonGroup
|
||||
buttonSize="s"
|
||||
buttonSize="m"
|
||||
className="quickButtonGroup"
|
||||
legend={strings.getLegend()}
|
||||
options={buttonGroupOptions}
|
||||
|
|
|
@ -1,4 +1,17 @@
|
|||
.solutionToolbar {
|
||||
padding: 0 $euiSizeS $euiSizeS;
|
||||
padding: $euiSize $euiSizeS;
|
||||
flex-grow: 0;
|
||||
|
||||
// Temporary fix for two tone icons to make them monochrome
|
||||
.solutionToolbar--dark {
|
||||
.euiIcon path {
|
||||
fill: $euiColorInk;
|
||||
}
|
||||
}
|
||||
|
||||
.solutionToolbar--light {
|
||||
.euiIcon path {
|
||||
fill: $euiColorGhost;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,10 +28,11 @@ interface NamedSlots {
|
|||
}
|
||||
|
||||
export interface Props {
|
||||
isDarkModeEnabled?: boolean;
|
||||
children: NamedSlots;
|
||||
}
|
||||
|
||||
export const SolutionToolbar = ({ children }: Props) => {
|
||||
export const SolutionToolbar = ({ isDarkModeEnabled, children }: Props) => {
|
||||
const {
|
||||
primaryActionButton,
|
||||
quickButtonGroup,
|
||||
|
@ -49,8 +50,10 @@ export const SolutionToolbar = ({ children }: Props) => {
|
|||
|
||||
return (
|
||||
<EuiFlexGroup
|
||||
className="solutionToolbar"
|
||||
id="kbnPresentationToolbar__solutionToolbar"
|
||||
className={`solutionToolbar ${
|
||||
isDarkModeEnabled ? 'solutionToolbar--dark' : 'solutionToolbar--light'
|
||||
}`}
|
||||
id={`kbnPresentationToolbar__solutionToolbar`}
|
||||
gutterSize="s"
|
||||
>
|
||||
<EuiFlexItem grow={false}>{primaryActionButton}</EuiFlexItem>
|
||||
|
|
|
@ -19,6 +19,7 @@ export {
|
|||
LazySavedObjectSaveModalDashboard,
|
||||
withSuspense,
|
||||
} from './components';
|
||||
|
||||
export {
|
||||
AddFromLibraryButton,
|
||||
PrimaryActionButton,
|
||||
|
|
|
@ -113,7 +113,7 @@ export class VisualizeEmbeddableFactory
|
|||
|
||||
public getDisplayName() {
|
||||
return i18n.translate('visualizations.displayName', {
|
||||
defaultMessage: 'visualization',
|
||||
defaultMessage: 'Visualization',
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ export { getVisSchemas } from './vis_schemas';
|
|||
/** @public types */
|
||||
export { VisualizationsSetup, VisualizationsStart };
|
||||
export { VisGroups } from './vis_types';
|
||||
export type { VisTypeAlias, VisTypeDefinition, Schema, ISchemas } from './vis_types';
|
||||
export type { BaseVisType, VisTypeAlias, VisTypeDefinition, Schema, ISchemas } from './vis_types';
|
||||
export { SerializedVis, SerializedVisData, VisData } from './vis';
|
||||
export type VisualizeEmbeddableFactoryContract = PublicContract<VisualizeEmbeddableFactory>;
|
||||
export type VisualizeEmbeddableContract = PublicContract<VisualizeEmbeddable>;
|
||||
|
|
|
@ -24,7 +24,7 @@ function DialogNavigation(props: DialogNavigationProps) {
|
|||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
{i18n.translate('visualizations.newVisWizard.goBackLink', {
|
||||
defaultMessage: 'Go back',
|
||||
defaultMessage: 'Select a different visualization',
|
||||
})}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
|
|
@ -41,6 +41,8 @@ interface TypeSelectionProps {
|
|||
outsideVisualizeApp?: boolean;
|
||||
stateTransfer?: EmbeddableStateTransfer;
|
||||
originatingApp?: string;
|
||||
showAggsSelection?: boolean;
|
||||
selectedVisType?: BaseVisType;
|
||||
}
|
||||
|
||||
interface TypeSelectionState {
|
||||
|
@ -69,8 +71,9 @@ class NewVisModal extends React.Component<TypeSelectionProps, TypeSelectionState
|
|||
this.isLabsEnabled = props.uiSettings.get(VISUALIZE_ENABLE_LABS_SETTING);
|
||||
|
||||
this.state = {
|
||||
showSearchVisModal: false,
|
||||
showGroups: true,
|
||||
showSearchVisModal: Boolean(this.props.selectedVisType),
|
||||
showGroups: !this.props.showAggsSelection,
|
||||
visType: this.props.selectedVisType,
|
||||
};
|
||||
|
||||
this.trackUiMetric = this.props.usageCollection?.reportUiCounter.bind(
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
getEmbeddable,
|
||||
getDocLinks,
|
||||
} from '../services';
|
||||
import type { BaseVisType } from '../vis_types';
|
||||
|
||||
const NewVisModal = lazy(() => import('./new_vis_modal'));
|
||||
|
||||
|
@ -29,6 +30,8 @@ export interface ShowNewVisModalParams {
|
|||
originatingApp?: string;
|
||||
outsideVisualizeApp?: boolean;
|
||||
createByValue?: boolean;
|
||||
showAggsSelection?: boolean;
|
||||
selectedVisType?: BaseVisType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,6 +44,8 @@ export function showNewVisModal({
|
|||
onClose,
|
||||
originatingApp,
|
||||
outsideVisualizeApp,
|
||||
showAggsSelection,
|
||||
selectedVisType,
|
||||
}: ShowNewVisModalParams = {}) {
|
||||
const container = document.createElement('div');
|
||||
let isClosed = false;
|
||||
|
@ -78,6 +83,8 @@ export function showNewVisModal({
|
|||
usageCollection={getUsageCollector()}
|
||||
application={getApplication()}
|
||||
docLinks={getDocLinks()}
|
||||
showAggsSelection={showAggsSelection}
|
||||
selectedVisType={selectedVisType}
|
||||
/>
|
||||
</Suspense>
|
||||
</I18nProvider>
|
||||
|
|
|
@ -13,31 +13,12 @@ import { PluginFunctionalProviderContext } from 'test/plugin_functional/services
|
|||
export default function ({ getService }: PluginFunctionalProviderContext) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const flyout = getService('flyout');
|
||||
const retry = getService('retry');
|
||||
|
||||
describe('creating and adding children', () => {
|
||||
describe('adding children', () => {
|
||||
before(async () => {
|
||||
await testSubjects.click('embeddablePanelExample');
|
||||
});
|
||||
|
||||
it('Can create a new child', async () => {
|
||||
await testSubjects.click('embeddablePanelToggleMenuIcon');
|
||||
await testSubjects.click('embeddablePanelAction-ACTION_ADD_PANEL');
|
||||
|
||||
// this seem like an overkill, but clicking this button which opens context menu was flaky
|
||||
await testSubjects.waitForEnabled('createNew');
|
||||
await retry.waitFor('createNew popover opened', async () => {
|
||||
await testSubjects.click('createNew');
|
||||
return await testSubjects.exists('createNew-TODO_EMBEDDABLE');
|
||||
});
|
||||
await testSubjects.click('createNew-TODO_EMBEDDABLE');
|
||||
|
||||
await testSubjects.setValue('taskInputField', 'new task');
|
||||
await testSubjects.click('createTodoEmbeddable');
|
||||
const tasks = await testSubjects.getVisibleTextAll('todoEmbeddableTask');
|
||||
expect(tasks).to.eql(['Goes out on Wednesdays!', 'new task']);
|
||||
});
|
||||
|
||||
it('Can add a child backed off a saved object', async () => {
|
||||
await testSubjects.click('embeddablePanelToggleMenuIcon');
|
||||
await testSubjects.click('embeddablePanelAction-ACTION_ADD_PANEL');
|
||||
|
@ -46,7 +27,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
|
|||
await testSubjects.moveMouseTo('euiFlyoutCloseButton');
|
||||
await flyout.ensureClosed('dashboardAddPanel');
|
||||
const tasks = await testSubjects.getVisibleTextAll('todoEmbeddableTask');
|
||||
expect(tasks).to.eql(['Goes out on Wednesdays!', 'new task', 'Take the garbage out']);
|
||||
expect(tasks).to.eql(['Goes out on Wednesdays!', 'Take the garbage out']);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
it('adds new visualization via the top nav link', async () => {
|
||||
const originalPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
await dashboardAddPanel.clickCreateNewLink();
|
||||
await PageObjects.visualize.clickAggBasedVisualizations();
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await dashboardAddPanel.clickAggBasedVisualizations();
|
||||
await PageObjects.visualize.clickAreaChart();
|
||||
await PageObjects.visualize.clickNewSearch();
|
||||
await PageObjects.visualize.saveVisualizationExpectSuccess(
|
||||
|
@ -52,9 +52,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
|
||||
it('adds a new visualization', async () => {
|
||||
const originalPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
await dashboardAddPanel.ensureAddPanelIsShowing();
|
||||
await dashboardAddPanel.clickAddNewEmbeddableLink('visualization');
|
||||
await PageObjects.visualize.clickAggBasedVisualizations();
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await dashboardAddPanel.clickAggBasedVisualizations();
|
||||
await PageObjects.visualize.clickAreaChart();
|
||||
await PageObjects.visualize.clickNewSearch();
|
||||
await PageObjects.visualize.saveVisualizationExpectSuccess(
|
||||
|
@ -71,7 +70,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
|
||||
it('adds a markdown visualization via the quick button', async () => {
|
||||
const originalPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
await PageObjects.dashboard.clickMarkdownQuickButton();
|
||||
await dashboardAddPanel.clickMarkdownQuickButton();
|
||||
await PageObjects.visualize.saveVisualizationExpectSuccess(
|
||||
'visualization from markdown quick button',
|
||||
{ redirectToOrigin: true }
|
||||
|
@ -84,21 +83,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
});
|
||||
|
||||
it('adds an input control visualization via the quick button', async () => {
|
||||
const originalPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
await PageObjects.dashboard.clickInputControlsQuickButton();
|
||||
await PageObjects.visualize.saveVisualizationExpectSuccess(
|
||||
'visualization from input control quick button',
|
||||
{ redirectToOrigin: true }
|
||||
);
|
||||
|
||||
await retry.try(async () => {
|
||||
const panelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(panelCount).to.eql(originalPanelCount + 1);
|
||||
});
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
});
|
||||
|
||||
it('saves the listing page instead of the visualization to the app link', async () => {
|
||||
await PageObjects.header.clickVisualize(true);
|
||||
const currentUrl = await browser.getCurrentUrl();
|
||||
|
|
|
@ -25,8 +25,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
describe('dashboard unsaved listing', () => {
|
||||
const addSomePanels = async () => {
|
||||
// add an area chart by value
|
||||
await dashboardAddPanel.clickCreateNewLink();
|
||||
await PageObjects.visualize.clickAggBasedVisualizations();
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await dashboardAddPanel.clickAggBasedVisualizations();
|
||||
await PageObjects.visualize.clickAreaChart();
|
||||
await PageObjects.visualize.clickNewSearch();
|
||||
await PageObjects.visualize.saveVisualizationAndReturn();
|
||||
|
@ -132,8 +132,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await PageObjects.dashboard.switchToEditMode();
|
||||
|
||||
// add another panel so we can delete it later
|
||||
await dashboardAddPanel.clickCreateNewLink();
|
||||
await PageObjects.visualize.clickAggBasedVisualizations();
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await dashboardAddPanel.clickAggBasedVisualizations();
|
||||
await PageObjects.visualize.clickAreaChart();
|
||||
await PageObjects.visualize.clickNewSearch();
|
||||
await PageObjects.visualize.saveVisualizationExpectSuccess('Wildvis', {
|
||||
|
|
|
@ -41,8 +41,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
it('shows the unsaved changes badge after adding panels', async () => {
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
// add an area chart by value
|
||||
await dashboardAddPanel.clickCreateNewLink();
|
||||
await PageObjects.visualize.clickAggBasedVisualizations();
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await dashboardAddPanel.clickAggBasedVisualizations();
|
||||
await PageObjects.visualize.clickAreaChart();
|
||||
await PageObjects.visualize.clickNewSearch();
|
||||
await PageObjects.visualize.saveVisualizationAndReturn();
|
||||
|
|
|
@ -13,10 +13,9 @@ import { FtrProviderContext } from '../../ftr_provider_context';
|
|||
export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||
const PageObjects = getPageObjects(['dashboard', 'header', 'visualize', 'settings', 'common']);
|
||||
const esArchiver = getService('esArchiver');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
const dashboardPanelActions = getService('dashboardPanelActions');
|
||||
const dashboardVisualizations = getService('dashboardVisualizations');
|
||||
const dashboardAddPanel = getService('dashboardAddPanel');
|
||||
|
||||
describe('edit embeddable redirects', () => {
|
||||
before(async () => {
|
||||
|
@ -88,10 +87,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
const newTitle = 'test create panel originatingApp';
|
||||
await PageObjects.dashboard.loadSavedDashboard('few panels');
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
await testSubjects.exists('dashboardAddNewPanelButton');
|
||||
await testSubjects.click('dashboardAddNewPanelButton');
|
||||
await dashboardVisualizations.ensureNewVisualizationDialogIsShowing();
|
||||
await PageObjects.visualize.clickMarkdownWidget();
|
||||
await dashboardAddPanel.clickMarkdownQuickButton();
|
||||
await PageObjects.visualize.saveVisualizationExpectSuccess(newTitle, {
|
||||
saveAsNew: true,
|
||||
redirectToOrigin: false,
|
||||
|
|
|
@ -14,13 +14,14 @@ export default function ({ getService, getPageObjects }) {
|
|||
const testSubjects = getService('testSubjects');
|
||||
const appsMenu = getService('appsMenu');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
const dashboardAddPanel = getService('dashboardAddPanel');
|
||||
const dashboardPanelActions = getService('dashboardPanelActions');
|
||||
|
||||
const originalMarkdownText = 'Original markdown text';
|
||||
const modifiedMarkdownText = 'Modified markdown text';
|
||||
|
||||
const createMarkdownVis = async (title) => {
|
||||
await PageObjects.dashboard.clickMarkdownQuickButton();
|
||||
await dashboardAddPanel.clickMarkdownQuickButton();
|
||||
await PageObjects.visEditor.setMarkdownTxt(originalMarkdownText);
|
||||
await PageObjects.visEditor.clickGo();
|
||||
if (title) {
|
||||
|
|
|
@ -41,15 +41,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
it('should open add panel when add button is clicked', async () => {
|
||||
await testSubjects.click('dashboardAddPanelButton');
|
||||
await dashboardAddPanel.clickOpenAddPanel();
|
||||
const isAddPanelOpen = await dashboardAddPanel.isAddPanelOpen();
|
||||
expect(isAddPanelOpen).to.be(true);
|
||||
await testSubjects.click('euiFlyoutCloseButton');
|
||||
});
|
||||
|
||||
it('should add new visualization from dashboard', async () => {
|
||||
await testSubjects.exists('dashboardAddNewPanelButton');
|
||||
await testSubjects.click('dashboardAddNewPanelButton');
|
||||
await dashboardVisualizations.createAndAddMarkdown({
|
||||
name: 'Dashboard Test Markdown',
|
||||
markdown: 'Markdown text',
|
||||
|
@ -57,5 +55,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
await dashboardExpect.markdownWithValuesExists(['Markdown text']);
|
||||
});
|
||||
|
||||
it('should open editor menu when editor button is clicked', async () => {
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await testSubjects.existOrFail('dashboardEditorContextMenu');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -113,10 +113,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
|
||||
it('when a new vis is added', async function () {
|
||||
const originalPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
|
||||
await dashboardAddPanel.ensureAddPanelIsShowing();
|
||||
await dashboardAddPanel.clickAddNewEmbeddableLink('visualization');
|
||||
await PageObjects.visualize.clickAggBasedVisualizations();
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await dashboardAddPanel.clickAggBasedVisualizations();
|
||||
await PageObjects.visualize.clickAreaChart();
|
||||
await PageObjects.visualize.clickNewSearch();
|
||||
await PageObjects.visualize.saveVisualizationExpectSuccess('new viz panel', {
|
||||
|
|
|
@ -413,16 +413,6 @@ export function DashboardPageProvider({ getService, getPageObjects }: FtrProvide
|
|||
await testSubjects.click('confirmSaveSavedObjectButton');
|
||||
}
|
||||
|
||||
public async clickMarkdownQuickButton() {
|
||||
log.debug('Click markdown quick button');
|
||||
await testSubjects.click('dashboardMarkdownQuickButton');
|
||||
}
|
||||
|
||||
public async clickInputControlsQuickButton() {
|
||||
log.debug('Click input controls quick button');
|
||||
await testSubjects.click('dashboardInputControlsQuickButton');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param dashboardTitle {String}
|
||||
|
|
|
@ -30,15 +30,41 @@ export function DashboardAddPanelProvider({ getService, getPageObjects }: FtrPro
|
|||
await PageObjects.common.sleep(500);
|
||||
}
|
||||
|
||||
async clickQuickButton(visType: string) {
|
||||
log.debug(`DashboardAddPanel.clickQuickButton${visType}`);
|
||||
await testSubjects.click(`dashboardQuickButton${visType}`);
|
||||
}
|
||||
|
||||
async clickMarkdownQuickButton() {
|
||||
await this.clickQuickButton('markdown');
|
||||
}
|
||||
|
||||
async clickMapQuickButton() {
|
||||
await this.clickQuickButton('map');
|
||||
}
|
||||
|
||||
async clickEditorMenuButton() {
|
||||
log.debug('DashboardAddPanel.clickEditorMenuButton');
|
||||
await testSubjects.click('dashboardEditorMenuButton');
|
||||
}
|
||||
|
||||
async clickAggBasedVisualizations() {
|
||||
log.debug('DashboardAddPanel.clickEditorMenuAggBasedMenuItem');
|
||||
await testSubjects.click('dashboardEditorAggBasedMenuItem');
|
||||
}
|
||||
|
||||
async clickVisType(visType: string) {
|
||||
log.debug('DashboardAddPanel.clickVisType');
|
||||
await testSubjects.click(`visType-${visType}`);
|
||||
}
|
||||
|
||||
async clickEmbeddableFactoryGroupButton(groupId: string) {
|
||||
log.debug('DashboardAddPanel.clickEmbeddableFactoryGroupButton');
|
||||
await testSubjects.click(`dashboardEditorMenu-${groupId}Group`);
|
||||
}
|
||||
|
||||
async clickAddNewEmbeddableLink(type: string) {
|
||||
await testSubjects.click('createNew');
|
||||
await testSubjects.click(`createNew-${type}`);
|
||||
await testSubjects.missingOrFail(`createNew-${type}`);
|
||||
}
|
||||
|
||||
async toggleFilterPopover() {
|
||||
|
|
|
@ -10,8 +10,6 @@ import { FtrProviderContext } from '../../ftr_provider_context';
|
|||
|
||||
export function DashboardVisualizationProvider({ getService, getPageObjects }: FtrProviderContext) {
|
||||
const log = getService('log');
|
||||
const find = getService('find');
|
||||
const retry = getService('retry');
|
||||
const queryBar = getService('queryBar');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const dashboardAddPanel = getService('dashboardAddPanel');
|
||||
|
@ -31,8 +29,8 @@ export function DashboardVisualizationProvider({ getService, getPageObjects }: F
|
|||
if (inViewMode) {
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
}
|
||||
await dashboardAddPanel.ensureAddPanelIsShowing();
|
||||
await dashboardAddPanel.clickAddNewEmbeddableLink('visualization');
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await dashboardAddPanel.clickAddNewEmbeddableLink('metrics');
|
||||
await PageObjects.visualize.clickVisualBuilder();
|
||||
await PageObjects.visualize.saveVisualizationExpectSuccess(name);
|
||||
}
|
||||
|
@ -87,39 +85,13 @@ export function DashboardVisualizationProvider({ getService, getPageObjects }: F
|
|||
await dashboardAddPanel.addSavedSearch(name);
|
||||
}
|
||||
|
||||
async clickAddVisualizationButton() {
|
||||
log.debug('DashboardVisualizations.clickAddVisualizationButton');
|
||||
await testSubjects.click('dashboardAddNewPanelButton');
|
||||
}
|
||||
|
||||
async isNewVisDialogShowing() {
|
||||
log.debug('DashboardVisualizations.isNewVisDialogShowing');
|
||||
return await find.existsByCssSelector('.visNewVisDialog');
|
||||
}
|
||||
|
||||
async ensureNewVisualizationDialogIsShowing() {
|
||||
let isShowing = await this.isNewVisDialogShowing();
|
||||
log.debug(`DashboardVisualizations.ensureNewVisualizationDialogIsShowing:${isShowing}`);
|
||||
if (!isShowing) {
|
||||
await retry.try(async () => {
|
||||
await this.clickAddVisualizationButton();
|
||||
isShowing = await this.isNewVisDialogShowing();
|
||||
log.debug(`DashboardVisualizations.ensureNewVisualizationDialogIsShowing:${isShowing}`);
|
||||
if (!isShowing) {
|
||||
throw new Error('New Vis Dialog still not open, trying again.');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async createAndAddMarkdown({ name, markdown }: { name: string; markdown: string }) {
|
||||
log.debug(`createAndAddMarkdown(${markdown})`);
|
||||
const inViewMode = await PageObjects.dashboard.getIsInViewMode();
|
||||
if (inViewMode) {
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
}
|
||||
await this.ensureNewVisualizationDialogIsShowing();
|
||||
await PageObjects.visualize.clickMarkdownWidget();
|
||||
await dashboardAddPanel.clickMarkdownQuickButton();
|
||||
await PageObjects.visEditor.setMarkdownTxt(markdown);
|
||||
await PageObjects.visEditor.clickGo();
|
||||
await PageObjects.visualize.saveVisualizationExpectSuccess(name, {
|
||||
|
@ -134,10 +106,10 @@ export function DashboardVisualizationProvider({ getService, getPageObjects }: F
|
|||
if (inViewMode) {
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
}
|
||||
await this.ensureNewVisualizationDialogIsShowing();
|
||||
await PageObjects.visualize.clickAggBasedVisualizations();
|
||||
await PageObjects.visualize.clickMetric();
|
||||
await find.clickByCssSelector('li.euiListGroupItem:nth-of-type(2)');
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await dashboardAddPanel.clickAggBasedVisualizations();
|
||||
await dashboardAddPanel.clickVisType('metric');
|
||||
await testSubjects.click('savedObjectTitlelogstash-*');
|
||||
await testSubjects.exists('visualizesaveAndReturnButton');
|
||||
await testSubjects.click('visualizesaveAndReturnButton');
|
||||
}
|
||||
|
@ -148,8 +120,7 @@ export function DashboardVisualizationProvider({ getService, getPageObjects }: F
|
|||
if (inViewMode) {
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
}
|
||||
await this.ensureNewVisualizationDialogIsShowing();
|
||||
await PageObjects.visualize.clickMarkdownWidget();
|
||||
await dashboardAddPanel.clickMarkdownQuickButton();
|
||||
await PageObjects.visEditor.setMarkdownTxt(markdown);
|
||||
await PageObjects.visEditor.clickGo();
|
||||
await testSubjects.click('visualizesaveAndReturnButton');
|
||||
|
|
|
@ -22,7 +22,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
const esArchiver = getService('esArchiver');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
const dashboardExpect = getService('dashboardExpect');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const dashboardVisualizations = getService('dashboardVisualizations');
|
||||
const PageObjects = getPageObjects([
|
||||
'common',
|
||||
|
@ -47,8 +46,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
it('adding a metric visualization', async function () {
|
||||
const originalPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(originalPanelCount).to.eql(0);
|
||||
await testSubjects.exists('dashboardAddNewPanelButton');
|
||||
await testSubjects.click('dashboardAddNewPanelButton');
|
||||
await dashboardVisualizations.createAndEmbedMetric('Embedding Vis Test');
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
await dashboardExpect.metricValuesExist(['0']);
|
||||
|
@ -59,8 +56,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
it('adding a markdown', async function () {
|
||||
const originalPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(originalPanelCount).to.eql(1);
|
||||
await testSubjects.exists('dashboardAddNewPanelButton');
|
||||
await testSubjects.click('dashboardAddNewPanelButton');
|
||||
await dashboardVisualizations.createAndEmbedMarkdown({
|
||||
name: 'Embedding Markdown Test',
|
||||
markdown: 'Nice to meet you, markdown is my name',
|
||||
|
|
|
@ -40,6 +40,16 @@ export class LogStreamEmbeddableFactoryDefinition
|
|||
});
|
||||
}
|
||||
|
||||
public getDescription() {
|
||||
return i18n.translate('xpack.infra.logStreamEmbeddable.description', {
|
||||
defaultMessage: 'Add a table of live streaming logs.',
|
||||
});
|
||||
}
|
||||
|
||||
public getIconType() {
|
||||
return 'logsApp';
|
||||
}
|
||||
|
||||
public async getExplicitInput() {
|
||||
return {
|
||||
title: i18n.translate('xpack.infra.logStreamEmbeddable.title', {
|
||||
|
|
|
@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n';
|
|||
|
||||
import type { StartServicesAccessor } from 'kibana/public';
|
||||
|
||||
import { PLUGIN_ICON, PLUGIN_ID, ML_APP_NAME } from '../../../common/constants/app';
|
||||
import type {
|
||||
EmbeddableFactoryDefinition,
|
||||
IContainer,
|
||||
|
@ -27,6 +28,14 @@ export class AnomalyChartsEmbeddableFactory
|
|||
implements EmbeddableFactoryDefinition<AnomalyChartsEmbeddableInput> {
|
||||
public readonly type = ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE;
|
||||
|
||||
public readonly grouping = [
|
||||
{
|
||||
id: PLUGIN_ID,
|
||||
getDisplayName: () => ML_APP_NAME,
|
||||
getIconType: () => PLUGIN_ICON,
|
||||
},
|
||||
];
|
||||
|
||||
constructor(
|
||||
private getStartServices: StartServicesAccessor<MlStartDependencies, MlPluginStart>
|
||||
) {}
|
||||
|
@ -37,7 +46,13 @@ export class AnomalyChartsEmbeddableFactory
|
|||
|
||||
public getDisplayName() {
|
||||
return i18n.translate('xpack.ml.components.mlAnomalyExplorerEmbeddable.displayName', {
|
||||
defaultMessage: 'ML anomaly chart',
|
||||
defaultMessage: 'Anomaly chart',
|
||||
});
|
||||
}
|
||||
|
||||
public getDescription() {
|
||||
return i18n.translate('xpack.ml.components.mlAnomalyExplorerEmbeddable.description', {
|
||||
defaultMessage: 'View anomaly detection results in a chart.',
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n';
|
|||
|
||||
import type { StartServicesAccessor } from 'kibana/public';
|
||||
|
||||
import { PLUGIN_ID, PLUGIN_ICON, ML_APP_NAME } from '../../../common/constants/app';
|
||||
import type {
|
||||
EmbeddableFactoryDefinition,
|
||||
IContainer,
|
||||
|
@ -26,6 +27,14 @@ export class AnomalySwimlaneEmbeddableFactory
|
|||
implements EmbeddableFactoryDefinition<AnomalySwimlaneEmbeddableInput> {
|
||||
public readonly type = ANOMALY_SWIMLANE_EMBEDDABLE_TYPE;
|
||||
|
||||
public readonly grouping = [
|
||||
{
|
||||
id: PLUGIN_ID,
|
||||
getDisplayName: () => ML_APP_NAME,
|
||||
getIconType: () => PLUGIN_ICON,
|
||||
},
|
||||
];
|
||||
|
||||
constructor(
|
||||
private getStartServices: StartServicesAccessor<MlStartDependencies, MlPluginStart>
|
||||
) {}
|
||||
|
@ -36,7 +45,13 @@ export class AnomalySwimlaneEmbeddableFactory
|
|||
|
||||
public getDisplayName() {
|
||||
return i18n.translate('xpack.ml.components.jobAnomalyScoreEmbeddable.displayName', {
|
||||
defaultMessage: 'ML anomaly swim lane',
|
||||
defaultMessage: 'Anomaly swim lane',
|
||||
});
|
||||
}
|
||||
|
||||
public getDescription() {
|
||||
return i18n.translate('xpack.ml.components.jobAnomalyScoreEmbeddable.description', {
|
||||
defaultMessage: 'View anomaly detection results in a timeline.',
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -96,8 +96,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
it('can open job selection flyout', async () => {
|
||||
await PageObjects.dashboard.clickCreateDashboardPrompt();
|
||||
await ml.dashboardEmbeddables.assertDashboardIsEmpty();
|
||||
await dashboardAddPanel.clickOpenAddPanel();
|
||||
await dashboardAddPanel.ensureAddPanelIsShowing();
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await dashboardAddPanel.clickEmbeddableFactoryGroupButton('ml');
|
||||
await dashboardAddPanel.clickAddNewEmbeddableLink('ml_anomaly_charts');
|
||||
await ml.dashboardJobSelectionTable.assertJobSelectionTableExists();
|
||||
await a11y.testAppSnapshot();
|
||||
|
|
|
@ -15,7 +15,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
const esArchiver = getService('esArchiver');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const dashboardPanelActions = getService('dashboardPanelActions');
|
||||
const dashboardVisualizations = getService('dashboardVisualizations');
|
||||
|
||||
describe('dashboard lens by value', function () {
|
||||
before(async () => {
|
||||
|
@ -27,7 +26,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
it('can add a lens panel by value', async () => {
|
||||
await dashboardVisualizations.ensureNewVisualizationDialogIsShowing();
|
||||
await PageObjects.lens.createAndAddLensFromDashboard({});
|
||||
const newPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(newPanelCount).to.eql(1);
|
||||
|
|
|
@ -19,10 +19,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
|
||||
const log = getService('log');
|
||||
const esArchiver = getService('esArchiver');
|
||||
const dashboardVisualizations = getService('dashboardVisualizations');
|
||||
const dashboardPanelActions = getService('dashboardPanelActions');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const appsMenu = getService('appsMenu');
|
||||
const dashboardAddPanel = getService('dashboardAddPanel');
|
||||
|
||||
const LAYER_NAME = 'World Countries';
|
||||
let mapCounter = 0;
|
||||
|
@ -33,7 +33,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
if (inViewMode) {
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
}
|
||||
await PageObjects.visualize.clickMapsApp();
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await dashboardAddPanel.clickVisType('maps');
|
||||
await PageObjects.maps.clickSaveAndReturnButton();
|
||||
}
|
||||
|
||||
|
@ -82,8 +83,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
describe('adding a map by value', () => {
|
||||
it('can add a map by value', async () => {
|
||||
await createNewDashboard();
|
||||
|
||||
await dashboardVisualizations.ensureNewVisualizationDialogIsShowing();
|
||||
await createAndAddMapByValue();
|
||||
const newPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(newPanelCount).to.eql(1);
|
||||
|
@ -93,7 +92,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
describe('editing a map by value', () => {
|
||||
before(async () => {
|
||||
await createNewDashboard();
|
||||
await dashboardVisualizations.ensureNewVisualizationDialogIsShowing();
|
||||
await createAndAddMapByValue();
|
||||
await editByValueMap();
|
||||
});
|
||||
|
@ -112,7 +110,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
describe('editing a map and adding to map library', () => {
|
||||
beforeEach(async () => {
|
||||
await createNewDashboard();
|
||||
await dashboardVisualizations.ensureNewVisualizationDialogIsShowing();
|
||||
await createAndAddMapByValue();
|
||||
});
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
'lens',
|
||||
]);
|
||||
|
||||
const dashboardVisualizations = getService('dashboardVisualizations');
|
||||
const dashboardAddPanel = getService('dashboardAddPanel');
|
||||
const dashboardPanelActions = getService('dashboardPanelActions');
|
||||
const dashboardExpect = getService('dashboardExpect');
|
||||
const testSubjects = getService('testSubjects');
|
||||
|
@ -85,7 +85,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
it('can add a lens panel by value', async () => {
|
||||
await dashboardVisualizations.ensureNewVisualizationDialogIsShowing();
|
||||
await PageObjects.lens.createAndAddLensFromDashboard({});
|
||||
const newPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(newPanelCount).to.eql(1);
|
||||
|
@ -171,9 +170,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
await PageObjects.dashboard.clickNewDashboard();
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
|
||||
await testSubjects.click('dashboardAddNewPanelButton');
|
||||
await dashboardVisualizations.ensureNewVisualizationDialogIsShowing();
|
||||
await PageObjects.visualize.clickMarkdownWidget();
|
||||
await dashboardAddPanel.clickMarkdownQuickButton();
|
||||
await PageObjects.visEditor.setMarkdownTxt(originalMarkdownText);
|
||||
await PageObjects.visEditor.clickGo();
|
||||
|
||||
|
|
|
@ -49,7 +49,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await elasticChart.setNewChartUiDebugFlag(true);
|
||||
await PageObjects.dashboard.clickCreateDashboardPrompt();
|
||||
await dashboardAddPanel.clickCreateNewLink();
|
||||
await dashboardAddPanel.clickVisType('lens');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.lens.goToTimeRange();
|
||||
|
||||
|
@ -68,7 +67,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await PageObjects.lens.save('vis1', false, true);
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await dashboardAddPanel.clickCreateNewLink();
|
||||
await dashboardAddPanel.clickVisType('lens');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
|
||||
await PageObjects.lens.configureDimension({
|
||||
|
|
|
@ -10,7 +10,6 @@ import expect from '@kbn/expect';
|
|||
export default function ({ getPageObjects, getService }) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const esArchiver = getService('esArchiver');
|
||||
const dashboardVisualizations = getService('dashboardVisualizations');
|
||||
const dashboardPanelActions = getService('dashboardPanelActions');
|
||||
const PageObjects = getPageObjects(['common', 'dashboard', 'visualize', 'lens']);
|
||||
|
||||
|
@ -29,9 +28,6 @@ export default function ({ getPageObjects, getService }) {
|
|||
|
||||
it('adds Lens visualization to empty dashboard', async () => {
|
||||
const title = 'Dashboard Test Lens';
|
||||
await testSubjects.exists('dashboardAddNewPanelButton');
|
||||
await testSubjects.click('dashboardAddNewPanelButton');
|
||||
await dashboardVisualizations.ensureNewVisualizationDialogIsShowing();
|
||||
await PageObjects.lens.createAndAddLensFromDashboard({ title, redirectToOrigin: true });
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
await testSubjects.exists(`embeddablePanelHeading-${title}`);
|
||||
|
@ -87,9 +83,6 @@ export default function ({ getPageObjects, getService }) {
|
|||
const title = 'non-dashboard Test Lens';
|
||||
await PageObjects.dashboard.loadSavedDashboard('empty dashboard test');
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
await testSubjects.exists('dashboardAddNewPanelButton');
|
||||
await testSubjects.click('dashboardAddNewPanelButton');
|
||||
await dashboardVisualizations.ensureNewVisualizationDialogIsShowing();
|
||||
await PageObjects.lens.createAndAddLensFromDashboard({ title });
|
||||
await PageObjects.lens.notLinkedToOriginatingApp();
|
||||
await PageObjects.common.navigateToApp('dashboard');
|
||||
|
|
|
@ -134,7 +134,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await filterBar.addFilter('geo.dest', 'is', 'LS');
|
||||
|
||||
await dashboardAddPanel.clickCreateNewLink();
|
||||
await dashboardAddPanel.clickVisType('lens');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
const hasGeoDestFilter = await filterBar.hasFilter('geo.dest', 'LS');
|
||||
expect(hasGeoDestFilter).to.be(false);
|
||||
|
@ -200,7 +199,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await PageObjects.dashboard.clickNewDashboard();
|
||||
|
||||
await dashboardAddPanel.clickCreateNewLink();
|
||||
await dashboardAddPanel.clickVisType('lens');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.lens.goToTimeRange();
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
const esArchiver = getService('esArchiver');
|
||||
const retry = getService('retry');
|
||||
const find = getService('find');
|
||||
const dashboardVisualizations = getService('dashboardVisualizations');
|
||||
const dashboardAddPanel = getService('dashboardAddPanel');
|
||||
const dashboardPanelActions = getService('dashboardPanelActions');
|
||||
const PageObjects = getPageObjects([
|
||||
'common',
|
||||
|
@ -39,8 +39,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
|
||||
it('adds a new tag to a Lens visualization', async () => {
|
||||
// create lens
|
||||
await dashboardVisualizations.ensureNewVisualizationDialogIsShowing();
|
||||
await PageObjects.visualize.clickLensWidget();
|
||||
await dashboardAddPanel.clickCreateNewLink();
|
||||
await PageObjects.lens.goToTimeRange();
|
||||
await PageObjects.lens.configureDimension({
|
||||
dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension',
|
||||
|
|
|
@ -15,7 +15,6 @@ export default function ({ getPageObjects, getService }) {
|
|||
const security = getService('security');
|
||||
const dashboardAddPanel = getService('dashboardAddPanel');
|
||||
const dashboardPanelActions = getService('dashboardPanelActions');
|
||||
const dashboardVisualizations = getService('dashboardVisualizations');
|
||||
|
||||
describe('maps in embeddable library', () => {
|
||||
before(async () => {
|
||||
|
@ -34,8 +33,7 @@ export default function ({ getPageObjects, getService }) {
|
|||
});
|
||||
await PageObjects.common.navigateToApp('dashboard');
|
||||
await PageObjects.dashboard.clickNewDashboard();
|
||||
await dashboardAddPanel.clickCreateNewLink();
|
||||
await dashboardVisualizations.ensureNewVisualizationDialogIsShowing();
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await PageObjects.visualize.clickMapsApp();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.maps.waitForLayersToLoad();
|
||||
|
|
|
@ -11,7 +11,6 @@ export default function ({ getPageObjects, getService }) {
|
|||
const PageObjects = getPageObjects(['common', 'dashboard', 'header', 'maps', 'visualize']);
|
||||
const dashboardAddPanel = getService('dashboardAddPanel');
|
||||
const dashboardPanelActions = getService('dashboardPanelActions');
|
||||
const dashboardVisualizations = getService('dashboardVisualizations');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const security = getService('security');
|
||||
|
||||
|
@ -37,9 +36,8 @@ export default function ({ getPageObjects, getService }) {
|
|||
beforeEach(async () => {
|
||||
await PageObjects.common.navigateToApp('dashboard');
|
||||
await PageObjects.dashboard.clickNewDashboard();
|
||||
await dashboardAddPanel.clickCreateNewLink();
|
||||
await await dashboardVisualizations.ensureNewVisualizationDialogIsShowing();
|
||||
await PageObjects.visualize.clickMapsApp();
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await dashboardAddPanel.clickVisType('maps');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.maps.waitForLayersToLoad();
|
||||
});
|
||||
|
|
|
@ -87,8 +87,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
it('can open job selection flyout', async () => {
|
||||
await PageObjects.dashboard.clickCreateDashboardPrompt();
|
||||
await ml.dashboardEmbeddables.assertDashboardIsEmpty();
|
||||
await dashboardAddPanel.clickOpenAddPanel();
|
||||
await dashboardAddPanel.ensureAddPanelIsShowing();
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await dashboardAddPanel.clickEmbeddableFactoryGroupButton('ml');
|
||||
await dashboardAddPanel.clickAddNewEmbeddableLink('ml_anomaly_charts');
|
||||
await ml.dashboardJobSelectionTable.assertJobSelectionTableExists();
|
||||
});
|
||||
|
|
|
@ -18,6 +18,7 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont
|
|||
const find = getService('find');
|
||||
const comboBox = getService('comboBox');
|
||||
const browser = getService('browser');
|
||||
const dashboardAddPanel = getService('dashboardAddPanel');
|
||||
|
||||
const PageObjects = getPageObjects([
|
||||
'common',
|
||||
|
@ -753,7 +754,7 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont
|
|||
if (inViewMode) {
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
}
|
||||
await PageObjects.visualize.clickLensWidget();
|
||||
await dashboardAddPanel.clickCreateNewLink();
|
||||
await this.goToTimeRange();
|
||||
await this.configureDimension({
|
||||
dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue