mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Canvas] Toolbar UI Updates (#113329)
This commit is contained in:
parent
d50ec56ed1
commit
16c049a2d9
16 changed files with 267 additions and 251 deletions
|
@ -543,7 +543,6 @@ export function DashboardTopNav({
|
|||
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;
|
||||
|
@ -553,7 +552,6 @@ export function DashboardTopNav({
|
|||
createType: titleInWizard || title,
|
||||
onClick: createNewVisType(visType as BaseVisType),
|
||||
'data-test-subj': `dashboardQuickButton${name}`,
|
||||
isDarkModeEnabled: IS_DARK_THEME,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -238,16 +238,18 @@ export const EditorMenu = ({ dashboardContainer, createNewVisType }: Props) => {
|
|||
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"
|
||||
/>
|
||||
{() => (
|
||||
<EuiContextMenu
|
||||
initialPanelId={0}
|
||||
panels={editorMenuPanels}
|
||||
className={`dshSolutionToolbar__editorContextMenu ${
|
||||
IS_DARK_THEME
|
||||
? 'dshSolutionToolbar__editorContextMenu--dark'
|
||||
: 'dshSolutionToolbar__editorContextMenu--light'
|
||||
}`}
|
||||
data-test-subj="dashboardEditorContextMenu"
|
||||
/>
|
||||
)}
|
||||
</SolutionToolbarPopover>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -18,13 +18,17 @@ type AllowedPopoverProps = Omit<
|
|||
'button' | 'isOpen' | 'closePopover' | 'anchorPosition'
|
||||
>;
|
||||
|
||||
export type Props = AllowedButtonProps & AllowedPopoverProps;
|
||||
export type Props = AllowedButtonProps &
|
||||
AllowedPopoverProps & {
|
||||
children: (arg: { closePopover: () => void }) => React.ReactNode;
|
||||
};
|
||||
|
||||
export const SolutionToolbarPopover = ({
|
||||
label,
|
||||
iconType,
|
||||
primary,
|
||||
iconSide,
|
||||
children,
|
||||
...popover
|
||||
}: Props) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
@ -33,10 +37,21 @@ export const SolutionToolbarPopover = ({
|
|||
const closePopover = () => setIsOpen(false);
|
||||
|
||||
const button = (
|
||||
<SolutionToolbarButton {...{ label, iconType, primary, iconSide }} onClick={onButtonClick} />
|
||||
<SolutionToolbarButton
|
||||
{...{ label, iconType, primary, iconSide }}
|
||||
onClick={onButtonClick}
|
||||
data-test-subj={popover['data-test-subj']}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiPopover anchorPosition="downLeft" {...{ isOpen, button, closePopover }} {...popover} />
|
||||
<EuiPopover
|
||||
anchorPosition="downLeft"
|
||||
panelPaddingSize="none"
|
||||
{...{ isOpen, button, closePopover }}
|
||||
{...popover}
|
||||
>
|
||||
{children({ closePopover })}
|
||||
</EuiPopover>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -8,17 +8,4 @@
|
|||
border-color: $euiBorderColor !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 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,27 +17,23 @@ 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' | 'isDarkModeEnabled'>;
|
||||
type Option = EuiButtonGroupOptionProps & Omit<QuickButtonProps, 'createType'>;
|
||||
|
||||
export const QuickButtonGroup = ({ buttons }: Props) => {
|
||||
const buttonGroupOptions: Option[] = buttons.map((button: QuickButtonProps, index) => {
|
||||
const { createType: label, isDarkModeEnabled, ...rest } = button;
|
||||
const { createType: label, ...rest } = button;
|
||||
const title = strings.getAriaButtonLabel(label);
|
||||
|
||||
return {
|
||||
...rest,
|
||||
'aria-label': title,
|
||||
className: `quickButtonGroup__button ${
|
||||
isDarkModeEnabled ? 'quickButtonGroup__button--dark' : 'quickButtonGroup__button--light'
|
||||
}`,
|
||||
className: `quickButtonGroup__button`,
|
||||
id: `${htmlIdGenerator()()}${index}`,
|
||||
label,
|
||||
title,
|
||||
|
|
|
@ -54,29 +54,31 @@ const primaryButtonConfigs = {
|
|||
panelPaddingSize="none"
|
||||
primary={true}
|
||||
>
|
||||
<EuiContextMenu
|
||||
initialPanelId={0}
|
||||
panels={[
|
||||
{
|
||||
id: 0,
|
||||
title: 'Open editor',
|
||||
items: [
|
||||
{
|
||||
name: 'Lens',
|
||||
icon: 'lensApp',
|
||||
},
|
||||
{
|
||||
name: 'Maps',
|
||||
icon: 'logoMaps',
|
||||
},
|
||||
{
|
||||
name: 'TSVB',
|
||||
icon: 'visVisualBuilder',
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
{() => (
|
||||
<EuiContextMenu
|
||||
initialPanelId={0}
|
||||
panels={[
|
||||
{
|
||||
id: 0,
|
||||
title: 'Open editor',
|
||||
items: [
|
||||
{
|
||||
name: 'Lens',
|
||||
icon: 'lensApp',
|
||||
},
|
||||
{
|
||||
name: 'Maps',
|
||||
icon: 'logoMaps',
|
||||
},
|
||||
{
|
||||
name: 'TSVB',
|
||||
icon: 'visVisualBuilder',
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</SolutionToolbarPopover>
|
||||
),
|
||||
Dashboard: (
|
||||
|
@ -93,29 +95,31 @@ const extraButtonConfigs = {
|
|||
Canvas: undefined,
|
||||
Dashboard: [
|
||||
<SolutionToolbarPopover iconType="visualizeApp" label="All editors" panelPaddingSize="none">
|
||||
<EuiContextMenu
|
||||
initialPanelId={0}
|
||||
panels={[
|
||||
{
|
||||
id: 0,
|
||||
title: 'Open editor',
|
||||
items: [
|
||||
{
|
||||
name: 'Lens',
|
||||
icon: 'lensApp',
|
||||
},
|
||||
{
|
||||
name: 'Maps',
|
||||
icon: 'logoMaps',
|
||||
},
|
||||
{
|
||||
name: 'TSVB',
|
||||
icon: 'visVisualBuilder',
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
{() => (
|
||||
<EuiContextMenu
|
||||
initialPanelId={0}
|
||||
panels={[
|
||||
{
|
||||
id: 0,
|
||||
title: 'Open editor',
|
||||
items: [
|
||||
{
|
||||
name: 'Lens',
|
||||
icon: 'lensApp',
|
||||
},
|
||||
{
|
||||
name: 'Maps',
|
||||
icon: 'logoMaps',
|
||||
},
|
||||
{
|
||||
name: 'TSVB',
|
||||
icon: 'visVisualBuilder',
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</SolutionToolbarPopover>,
|
||||
],
|
||||
};
|
||||
|
|
|
@ -31,7 +31,7 @@ $canvasLayoutFontSize: $euiFontSizeS;
|
|||
.canvasLayout__stageHeader {
|
||||
flex-grow: 0;
|
||||
flex-basis: auto;
|
||||
padding: 1px $euiSize 0;
|
||||
padding: $euiSizeS;
|
||||
font-size: $canvasLayoutFontSize;
|
||||
border-bottom: $euiBorderThin;
|
||||
background: $euiColorLightestShade;
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
exports[`Storyshots components/WorkpadHeader/ElementMenu default 1`] = `
|
||||
<div
|
||||
className="euiPopover euiPopover--anchorDownLeft"
|
||||
data-test-subj="add-element-button"
|
||||
>
|
||||
<div
|
||||
className="euiPopover__anchor"
|
||||
>
|
||||
<button
|
||||
aria-label="Add an element"
|
||||
className="euiButton euiButton--primary euiButton--small euiButton--fill canvasElementMenu__popoverButton"
|
||||
className="euiButton euiButton--primary euiButton--fill solutionToolbarButton undefined"
|
||||
data-test-subj="add-element-button"
|
||||
disabled={false}
|
||||
onClick={[Function]}
|
||||
|
|
|
@ -129,12 +129,6 @@ You can use standard Markdown in here, but you can also access your piped-in dat
|
|||
},
|
||||
};
|
||||
|
||||
const mockRenderEmbedPanel = () => <div id="embeddablePanel" />;
|
||||
|
||||
storiesOf('components/WorkpadHeader/ElementMenu', module).add('default', () => (
|
||||
<ElementMenu
|
||||
elements={testElements}
|
||||
addElement={action('addElement')}
|
||||
renderEmbedPanel={mockRenderEmbedPanel}
|
||||
/>
|
||||
<ElementMenu elements={testElements} addElement={action('addElement')} />
|
||||
));
|
||||
|
|
|
@ -6,17 +6,13 @@
|
|||
*/
|
||||
|
||||
import { sortBy } from 'lodash';
|
||||
import React, { Fragment, FunctionComponent, useState } from 'react';
|
||||
import React, { FunctionComponent, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
EuiButton,
|
||||
EuiContextMenu,
|
||||
EuiIcon,
|
||||
EuiContextMenuPanelItemDescriptor,
|
||||
} from '@elastic/eui';
|
||||
import { EuiContextMenu, EuiIcon, EuiContextMenuPanelItemDescriptor } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { PrimaryActionPopover } from '../../../../../../../src/plugins/presentation_util/public';
|
||||
import { getId } from '../../../lib/get_id';
|
||||
import { Popover, ClosePopoverFn } from '../../popover';
|
||||
import { ClosePopoverFn } from '../../popover';
|
||||
import { CONTEXT_MENU_TOP_BORDER_CLASSNAME } from '../../../../common/lib';
|
||||
import { ElementSpec } from '../../../../types';
|
||||
import { flattenPanelTree } from '../../../lib/flatten_panel_tree';
|
||||
|
@ -116,7 +112,7 @@ const categorizeElementsByType = (elements: ElementSpec[]): { [key: string]: Ele
|
|||
return categories;
|
||||
};
|
||||
|
||||
export interface Props {
|
||||
interface Props {
|
||||
/**
|
||||
* Dictionary of elements from elements registry
|
||||
*/
|
||||
|
@ -125,25 +121,14 @@ export interface Props {
|
|||
* Handler for adding a selected element to the workpad
|
||||
*/
|
||||
addElement: (element: ElementSpec) => void;
|
||||
/**
|
||||
* Renders embeddable flyout
|
||||
*/
|
||||
renderEmbedPanel: (onClose: () => void) => JSX.Element;
|
||||
}
|
||||
|
||||
export const ElementMenu: FunctionComponent<Props> = ({
|
||||
elements,
|
||||
addElement,
|
||||
renderEmbedPanel,
|
||||
}) => {
|
||||
export const ElementMenu: FunctionComponent<Props> = ({ elements, addElement }) => {
|
||||
const [isAssetModalVisible, setAssetModalVisible] = useState(false);
|
||||
const [isEmbedPanelVisible, setEmbedPanelVisible] = useState(false);
|
||||
const [isSavedElementsModalVisible, setSavedElementsModalVisible] = useState(false);
|
||||
|
||||
const hideAssetModal = () => setAssetModalVisible(false);
|
||||
const showAssetModal = () => setAssetModalVisible(true);
|
||||
const hideEmbedPanel = () => setEmbedPanelVisible(false);
|
||||
const showEmbedPanel = () => setEmbedPanelVisible(true);
|
||||
const hideSavedElementsModal = () => setSavedElementsModalVisible(false);
|
||||
const showSavedElementsModal = () => setSavedElementsModalVisible(true);
|
||||
|
||||
|
@ -214,47 +199,28 @@ export const ElementMenu: FunctionComponent<Props> = ({
|
|||
closePopover();
|
||||
},
|
||||
},
|
||||
{
|
||||
name: strings.getEmbedObjectMenuItemLabel(),
|
||||
className: CONTEXT_MENU_TOP_BORDER_CLASSNAME,
|
||||
icon: <EuiIcon type="logoKibana" size="m" />,
|
||||
onClick: () => {
|
||||
showEmbedPanel();
|
||||
closePopover();
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const exportControl = (togglePopover: React.MouseEventHandler<any>) => (
|
||||
<EuiButton
|
||||
fill
|
||||
iconType="plusInCircle"
|
||||
size="s"
|
||||
aria-label={strings.getElementMenuLabel()}
|
||||
onClick={togglePopover}
|
||||
className="canvasElementMenu__popoverButton"
|
||||
data-test-subj="add-element-button"
|
||||
>
|
||||
{strings.getElementMenuButtonLabel()}
|
||||
</EuiButton>
|
||||
);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Popover button={exportControl} panelPaddingSize="none" anchorPosition="downLeft">
|
||||
<>
|
||||
<PrimaryActionPopover
|
||||
panelPaddingSize="none"
|
||||
label={strings.getElementMenuButtonLabel()}
|
||||
iconType="plusInCircle"
|
||||
data-test-subj="add-element-button"
|
||||
>
|
||||
{({ closePopover }: { closePopover: ClosePopoverFn }) => (
|
||||
<EuiContextMenu
|
||||
initialPanelId={0}
|
||||
panels={flattenPanelTree(getPanelTree(closePopover))}
|
||||
/>
|
||||
)}
|
||||
</Popover>
|
||||
</PrimaryActionPopover>
|
||||
{isAssetModalVisible ? <AssetManager onClose={hideAssetModal} /> : null}
|
||||
{isEmbedPanelVisible ? renderEmbedPanel(hideEmbedPanel) : null}
|
||||
{isSavedElementsModalVisible ? <SavedElementsModal onClose={hideSavedElementsModal} /> : null}
|
||||
</Fragment>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
.canvasElementMenu__popoverButton {
|
||||
margin-right: $euiSizeS;
|
||||
}
|
|
@ -5,44 +5,4 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { compose, withProps } from 'recompose';
|
||||
import { Dispatch } from 'redux';
|
||||
import { State, ElementSpec } from '../../../../types';
|
||||
// @ts-expect-error untyped local
|
||||
import { elementsRegistry } from '../../../lib/elements_registry';
|
||||
import { ElementMenu as Component, Props as ComponentProps } from './element_menu.component';
|
||||
// @ts-expect-error untyped local
|
||||
import { addElement } from '../../../state/actions/elements';
|
||||
import { getSelectedPage } from '../../../state/selectors/workpad';
|
||||
import { AddEmbeddablePanel } from '../../embeddable_flyout';
|
||||
|
||||
interface StateProps {
|
||||
pageId: string;
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
addElement: (pageId: string) => (partialElement: ElementSpec) => void;
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: State) => ({
|
||||
pageId: getSelectedPage(state),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
||||
addElement: (pageId: string) => (element: ElementSpec) => dispatch(addElement(pageId, element)),
|
||||
});
|
||||
|
||||
const mergeProps = (stateProps: StateProps, dispatchProps: DispatchProps) => ({
|
||||
...stateProps,
|
||||
...dispatchProps,
|
||||
addElement: dispatchProps.addElement(stateProps.pageId),
|
||||
// Moved this section out of the main component to enable stories
|
||||
renderEmbedPanel: (onClose: () => void) => <AddEmbeddablePanel onClose={onClose} />,
|
||||
});
|
||||
|
||||
export const ElementMenu = compose<ComponentProps, {}>(
|
||||
connect(mapStateToProps, mapDispatchToProps, mergeProps),
|
||||
withProps(() => ({ elements: elementsRegistry.toJS() }))
|
||||
)(Component);
|
||||
export * from './element_menu.component';
|
||||
|
|
|
@ -5,13 +5,19 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import React, { FC, useCallback, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
// @ts-expect-error no @types definition
|
||||
import { Shortcuts } from 'react-shortcuts';
|
||||
import { EuiFlexItem, EuiFlexGroup, EuiButtonIcon, EuiToolTip } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import {
|
||||
AddFromLibraryButton,
|
||||
QuickButtonGroup,
|
||||
SolutionToolbar,
|
||||
} from '../../../../../../src/plugins/presentation_util/public';
|
||||
import { getElementStrings } from '../../../i18n';
|
||||
import { CommitFn, ElementSpec } from '../../../types';
|
||||
import { ToolTipShortcut } from '../tool_tip_shortcut/';
|
||||
import { RefreshControl } from './refresh_control';
|
||||
// @ts-expect-error untyped local
|
||||
|
@ -21,7 +27,6 @@ import { ElementMenu } from './element_menu';
|
|||
import { ShareMenu } from './share_menu';
|
||||
import { ViewMenu } from './view_menu';
|
||||
import { LabsControl } from './labs_control';
|
||||
import { CommitFn } from '../../../types';
|
||||
|
||||
const strings = {
|
||||
getFullScreenButtonAriaLabel: () =>
|
||||
|
@ -46,19 +51,30 @@ const strings = {
|
|||
}),
|
||||
};
|
||||
|
||||
const elementStrings = getElementStrings();
|
||||
|
||||
export interface Props {
|
||||
isWriteable: boolean;
|
||||
canUserWrite: boolean;
|
||||
commit: CommitFn;
|
||||
onSetWriteable?: (writeable: boolean) => void;
|
||||
renderEmbedPanel: (onClick: () => void) => JSX.Element;
|
||||
elements: { [key: string]: ElementSpec };
|
||||
addElement: (element: Partial<ElementSpec>) => void;
|
||||
}
|
||||
|
||||
export const WorkpadHeader: FunctionComponent<Props> = ({
|
||||
export const WorkpadHeader: FC<Props> = ({
|
||||
isWriteable,
|
||||
canUserWrite,
|
||||
commit,
|
||||
onSetWriteable = () => {},
|
||||
renderEmbedPanel,
|
||||
elements,
|
||||
addElement,
|
||||
}) => {
|
||||
const [isEmbedPanelVisible, setEmbedPanelVisible] = useState(false);
|
||||
const hideEmbedPanel = () => setEmbedPanelVisible(false);
|
||||
const showEmbedPanel = () => setEmbedPanelVisible(true);
|
||||
const toggleWriteable = () => onSetWriteable(!isWriteable);
|
||||
|
||||
const keyHandler = (action: string) => {
|
||||
|
@ -111,65 +127,104 @@ export const WorkpadHeader: FunctionComponent<Props> = ({
|
|||
);
|
||||
};
|
||||
|
||||
const createElement = useCallback(
|
||||
(elementName: string) => () => {
|
||||
const elementSpec = elements[elementName];
|
||||
if (elementSpec) {
|
||||
addElement(elements[elementName]);
|
||||
}
|
||||
},
|
||||
[addElement, elements]
|
||||
);
|
||||
|
||||
const quickButtons = [
|
||||
{
|
||||
iconType: 'visText',
|
||||
createType: elementStrings.markdown.displayName,
|
||||
onClick: createElement('markdown'),
|
||||
},
|
||||
{
|
||||
iconType: 'node',
|
||||
createType: elementStrings.shape.displayName,
|
||||
onClick: createElement('shape'),
|
||||
},
|
||||
{
|
||||
iconType: 'image',
|
||||
createType: elementStrings.image.displayName,
|
||||
onClick: createElement('image'),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<EuiFlexGroup
|
||||
gutterSize="none"
|
||||
alignItems="center"
|
||||
justifyContent="spaceBetween"
|
||||
className="canvasLayout__stageHeaderInner"
|
||||
>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="none">
|
||||
{isWriteable && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<ElementMenu />
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
<EuiFlexItem grow={false}>
|
||||
<ViewMenu />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EditMenu commit={commit} />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<ShareMenu />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<LabsControl />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="s">
|
||||
<EuiFlexItem grow={false}>
|
||||
{canUserWrite && (
|
||||
<Shortcuts
|
||||
name="EDITOR"
|
||||
handler={keyHandler}
|
||||
targetNodeSelector="body"
|
||||
global
|
||||
isolate
|
||||
/>
|
||||
<>
|
||||
<EuiFlexGroup
|
||||
gutterSize="none"
|
||||
alignItems="center"
|
||||
justifyContent="spaceBetween"
|
||||
className="canvasLayout__stageHeaderInner"
|
||||
>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="none">
|
||||
{isWriteable && (
|
||||
<EuiFlexItem>
|
||||
<SolutionToolbar>
|
||||
{{
|
||||
primaryActionButton: (
|
||||
<ElementMenu addElement={addElement} elements={elements} />
|
||||
),
|
||||
quickButtonGroup: <QuickButtonGroup buttons={quickButtons} />,
|
||||
addFromLibraryButton: <AddFromLibraryButton onClick={showEmbedPanel} />,
|
||||
}}
|
||||
</SolutionToolbar>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
<EuiToolTip position="bottom" content={getEditToggleToolTip()}>
|
||||
<EuiButtonIcon
|
||||
iconType={isWriteable ? 'eyeClosed' : 'eye'}
|
||||
onClick={toggleWriteable}
|
||||
size="s"
|
||||
aria-label={getEditToggleToolTipText()}
|
||||
isDisabled={!canUserWrite}
|
||||
/>
|
||||
</EuiToolTip>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<RefreshControl />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<FullscreenControl>{fullscreenButton}</FullscreenControl>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<ViewMenu />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EditMenu commit={commit} />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<ShareMenu />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<LabsControl />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="s">
|
||||
<EuiFlexItem grow={false}>
|
||||
{canUserWrite && (
|
||||
<Shortcuts
|
||||
name="EDITOR"
|
||||
handler={keyHandler}
|
||||
targetNodeSelector="body"
|
||||
global
|
||||
isolate
|
||||
/>
|
||||
)}
|
||||
<EuiToolTip position="bottom" content={getEditToggleToolTip()}>
|
||||
<EuiButtonIcon
|
||||
iconType={isWriteable ? 'eyeClosed' : 'eye'}
|
||||
onClick={toggleWriteable}
|
||||
size="s"
|
||||
aria-label={getEditToggleToolTipText()}
|
||||
isDisabled={!canUserWrite}
|
||||
/>
|
||||
</EuiToolTip>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<RefreshControl />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<FullscreenControl>{fullscreenButton}</FullscreenControl>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
{isEmbedPanelVisible ? renderEmbedPanel(hideEmbedPanel) : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -178,4 +233,7 @@ WorkpadHeader.propTypes = {
|
|||
commit: PropTypes.func.isRequired,
|
||||
onSetWriteable: PropTypes.func,
|
||||
canUserWrite: PropTypes.bool,
|
||||
renderEmbedPanel: PropTypes.func.isRequired,
|
||||
elements: PropTypes.object.isRequired,
|
||||
addElement: PropTypes.func.isRequired,
|
||||
};
|
||||
|
|
|
@ -5,22 +5,61 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import { Action } from 'redux-actions';
|
||||
// @ts-expect-error untyped local
|
||||
import { elementsRegistry } from '../../lib/elements_registry';
|
||||
import { canUserWrite } from '../../state/selectors/app';
|
||||
import { getSelectedPage, isWriteable } from '../../state/selectors/workpad';
|
||||
import { setWriteable } from '../../state/actions/workpad';
|
||||
import { State } from '../../../types';
|
||||
import { WorkpadHeader as Component } from './workpad_header.component';
|
||||
// @ts-expect-error untyped local
|
||||
import { addElement } from '../../state/actions/elements';
|
||||
import { CommitFn, ElementSpec, State } from '../../../types';
|
||||
import { WorkpadHeader as Component, Props as ComponentProps } from './workpad_header.component';
|
||||
import { AddEmbeddablePanel } from '../embeddable_flyout';
|
||||
|
||||
const mapStateToProps = (state: State) => ({
|
||||
interface Props {
|
||||
commit: CommitFn;
|
||||
}
|
||||
|
||||
interface StateProps {
|
||||
isWriteable: boolean;
|
||||
canUserWrite: boolean;
|
||||
selectedPage: string;
|
||||
pageId: string;
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
onSetWriteable: (isWorkpadWriteable: boolean) => Action<boolean>;
|
||||
addElement: (pageId: string) => (partialElement: Partial<ElementSpec>) => void;
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: State): StateProps => ({
|
||||
isWriteable: isWriteable(state) && canUserWrite(state),
|
||||
canUserWrite: canUserWrite(state),
|
||||
selectedPage: getSelectedPage(state),
|
||||
pageId: getSelectedPage(state),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
||||
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({
|
||||
onSetWriteable: (isWorkpadWriteable: boolean) => dispatch(setWriteable(isWorkpadWriteable)),
|
||||
addElement: (pageId: string) => (element: Partial<ElementSpec>) =>
|
||||
dispatch(addElement(pageId, element)),
|
||||
});
|
||||
|
||||
export const WorkpadHeader = connect(mapStateToProps, mapDispatchToProps)(Component);
|
||||
const mergeProps = (
|
||||
stateProps: StateProps,
|
||||
dispatchProps: DispatchProps,
|
||||
ownProps: Props
|
||||
): ComponentProps => ({
|
||||
...stateProps,
|
||||
...dispatchProps,
|
||||
...ownProps,
|
||||
renderEmbedPanel: (onClose: () => void) => <AddEmbeddablePanel onClose={onClose} />,
|
||||
addElement: dispatchProps.addElement(stateProps.pageId),
|
||||
elements: elementsRegistry.toJS(),
|
||||
});
|
||||
|
||||
export const WorkpadHeader = connect(mapStateToProps, mapDispatchToProps, mergeProps)(Component);
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
@import '../components/toolbar/toolbar';
|
||||
@import '../components/toolbar/tray/tray';
|
||||
@import '../components/workpad/workpad';
|
||||
@import '../components/workpad_header/element_menu/element_menu';
|
||||
@import '../components/workpad_header/share_menu/share_menu';
|
||||
@import '../components/workpad_header/view_menu/view_menu';
|
||||
@import '../components/workpad_page/workpad_page';
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
{ "path": "../../../src/plugins/kibana_legacy/tsconfig.json" },
|
||||
{ "path": "../../../src/plugins/kibana_react/tsconfig.json" },
|
||||
{ "path": "../../../src/plugins/kibana_utils/tsconfig.json" },
|
||||
{ "path": "../../../src/plugins/presentation_util/tsconfig.json" },
|
||||
{ "path": "../../../src/plugins/saved_objects/tsconfig.json" },
|
||||
{ "path": "../../../src/plugins/ui_actions/tsconfig.json" },
|
||||
{ "path": "../../../src/plugins/usage_collection/tsconfig.json" },
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue