Skip to content

Commit

Permalink
Merge branch 'main' into eui-v92.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
cee-chen authored Jan 24, 2024
2 parents 71ef042 + ee3934b commit 54262d0
Show file tree
Hide file tree
Showing 15 changed files with 177 additions and 71 deletions.
2 changes: 1 addition & 1 deletion packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pageLoadAssetSize:
datasetQuality: 50624
dataViewEditor: 28082
dataViewFieldEditor: 27000
dataViewManagement: 5136
dataViewManagement: 5176
dataViews: 51000
dataVisualizer: 27530
devTools: 38637
Expand Down
4 changes: 4 additions & 0 deletions packages/shared-ux/page/solution_nav/src/_variables.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// This size is also tracked with a variable in solution_nav.tsx, if updated
// update there as well
$solutionNavWidth: 248px;
$solutionNavCollapsedWidth: $euiSizeXXL;
8 changes: 5 additions & 3 deletions packages/shared-ux/page/solution_nav/src/collapse_button.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
@import 'variables';

.kbnSolutionNavCollapseButton {
position: absolute;
opacity: 0;
left: 248px - $euiSize;
left: $solutionNavWidth - $euiSize;
top: $euiSizeL;
z-index: 2;

Expand All @@ -18,7 +20,7 @@
&:hover,
&:focus {
opacity: 1;
left: 248px - $euiSizeL;
left: $solutionNavWidth - $euiSizeL;
}

.kbnSolutionNav__sidebar:hover & {
Expand All @@ -39,7 +41,7 @@
top: 0;
bottom: 0;
height: 100%;
width: $euiSizeXXL;
width: $solutionNavCollapsedWidth;
border-radius: 0;
// Keep the icon at the top instead of it getting shifted to the center of the page
padding-top: $euiSizeL + $euiSizeS;
Expand Down
3 changes: 2 additions & 1 deletion packages/shared-ux/page/solution_nav/src/solution_nav.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
$euiSideNavEmphasizedBackgroundColor: transparentize($euiColorLightShade, .7);
@import '@elastic/eui/src/components/side_nav/mixins';
@import 'variables';

// Put the page background color in the flyout version too
.kbnSolutionNav__flyout {
Expand All @@ -14,7 +15,7 @@ $euiSideNavEmphasizedBackgroundColor: transparentize($euiColorLightShade, .7);
flex-direction: column;

@include euiBreakpoint('m', 'l', 'xl') {
width: 248px;
width: $solutionNavWidth;
padding: $euiSizeL;
}

Expand Down
31 changes: 30 additions & 1 deletion packages/shared-ux/page/solution_nav/src/solution_nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/
import './solution_nav.scss';

import React, { FC, useState, useMemo } from 'react';
import React, { FC, useState, useMemo, useEffect } from 'react';
import classNames from 'classnames';
import {
EuiAvatarProps,
Expand All @@ -23,6 +23,8 @@ import {
htmlIdGenerator,
useIsWithinBreakpoints,
useIsWithinMinBreakpoint,
useEuiTheme,
useEuiThemeCSSVariables,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
Expand Down Expand Up @@ -71,6 +73,7 @@ export type SolutionNavProps = Omit<EuiSideNavProps<{}>, 'children' | 'items' |
};

const FLYOUT_SIZE = 248;
const FLYOUT_SIZE_CSS = `${FLYOUT_SIZE}px`;

const setTabIndex = (items: Array<EuiSideNavItemType<{}>>, isHidden: boolean) => {
return items.map((item) => {
Expand Down Expand Up @@ -174,6 +177,32 @@ export const SolutionNav: FC<SolutionNavProps> = ({
);
}, [children, headingID, isCustomSideNav, isHidden, items, rest]);

const { euiTheme } = useEuiTheme();
const navWidth = useMemo(() => {
if (isLargerBreakpoint) {
return isOpenOnDesktop ? FLYOUT_SIZE_CSS : euiTheme.size.xxl;
}
if (isMediumBreakpoint) {
return isSideNavOpenOnMobile || !canBeCollapsed ? FLYOUT_SIZE_CSS : euiTheme.size.xxl;
}
return '0';
}, [
euiTheme,
isOpenOnDesktop,
isSideNavOpenOnMobile,
canBeCollapsed,
isMediumBreakpoint,
isLargerBreakpoint,
]);
const { setGlobalCSSVariables } = useEuiThemeCSSVariables();
// Setting a global CSS variable with the nav width
// so that other pages have it available when needed.
useEffect(() => {
setGlobalCSSVariables({
'--kbnSolutionNavOffset': navWidth,
});
}, [navWidth, setGlobalCSSVariables]);

return (
<>
{isSmallerBreakpoint && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
box-shadow: inset 0 $embeddableConsoleInitialHeight 0 $embeddableConsoleBackground, inset 0 600rem 0 $euiPageBackgroundColor;
bottom: 0;
right: 0;
left: var(--euiCollapsibleNavOffset, 0);
transform: translateY(0);
height: $embeddableConsoleInitialHeight;
max-height: $embeddableConsoleMaxHeight;
Expand All @@ -18,6 +17,18 @@
z-index: $euiZLevel1;
}

&--projectChrome {
left: var(--euiCollapsibleNavOffset, 0);
}

&--classicChrome {
left: var(--kbnSolutionNavOffset, 0);
}

&--unknownChrome {
left: 0;
}

&-isOpen {
animation-duration: $euiAnimSpeedNormal;
animation-timing-function: $euiAnimSlightResistance;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import React, { useState } from 'react';
import classNames from 'classnames';
import useObservable from 'react-use/lib/useObservable';
import {
EuiButton,
EuiFocusTrap,
Expand Down Expand Up @@ -38,6 +39,7 @@ export const EmbeddableConsole = ({
}: EmbeddableConsoleProps & EmbeddableConsoleDependencies) => {
const [isConsoleOpen, setIsConsoleOpen] = useState<boolean>(false);
const toggleConsole = () => setIsConsoleOpen(!isConsoleOpen);
const chromeStyle = useObservable(core.chrome.getChromeStyle$());

const onKeyDown = (event: any) => {
if (event.key === keys.ESCAPE) {
Expand All @@ -52,6 +54,9 @@ export const EmbeddableConsole = ({
'embeddableConsole--large': size === 'l',
'embeddableConsole--medium': size === 'm',
'embeddableConsole--small': size === 's',
'embeddableConsole--classicChrome': chromeStyle === 'classic',
'embeddableConsole--projectChrome': chromeStyle === 'project',
'embeddableConsole--unknownChrome': chromeStyle === undefined,
'embeddableConsole--fixed': true,
'embeddableConsole--showOnMobile': false,
});
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/console/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ export class ConsoleUIPlugin implements Plugin<void, void, AppSetupUIPluginDepen
const {
ui: { enabled: isConsoleUiEnabled },
} = this.ctx.config.get<ClientConfigType>();
if (isConsoleUiEnabled) {

if (isConsoleUiEnabled && core.application.capabilities?.dev_tools?.show === true) {
return {
renderEmbeddableConsole: (props: EmbeddableConsoleProps) => {
const consoleDeps: EmbeddableConsoleDependencies = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { InputsModelId } from '../../../../common/store/inputs/constants';
import { AddToCaseButton } from '../add_to_case_button';
import { NewTimelineAction } from './new_timeline';
import { SaveTimelineButton } from './save_timeline_button';
import { OpenTimelineAction } from './open_timeline';
import { OpenTimelineButton } from '../../modal/actions/open_timeline_button';
import { TIMELINE_TOUR_CONFIG_ANCHORS } from '../../timeline/tour/step_config';

interface TimelineActionMenuProps {
Expand Down Expand Up @@ -54,7 +54,7 @@ const TimelineActionMenuComponent = ({
<NewTimelineAction timelineId={timelineId} />
</EuiFlexItem>
<EuiFlexItem data-test-subj="open-timeline-action">
<OpenTimelineAction />
<OpenTimelineButton />
</EuiFlexItem>
<EuiFlexItem data-test-subj="inspect-timeline-action">
<InspectButton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,34 +23,6 @@ export const NEW_TIMELINE = i18n.translate(
}
);

export const OPEN_TIMELINE_BTN = i18n.translate(
'xpack.securitySolution.flyout.timeline.actionMenu.openTimelineBtn',
{
defaultMessage: 'Open',
}
);

export const OPEN_TIMELINE_BTN_LABEL = i18n.translate(
'xpack.securitySolution.flyout.timeline.actionMenu.openTimelineBtnLabel',
{
defaultMessage: 'Open Existing Timeline',
}
);

export const SAVE_TIMELINE_BTN = i18n.translate(
'xpack.securitySolution.flyout.timeline.actionMenu.saveTimelineBtn',
{
defaultMessage: 'Save',
}
);

export const SAVE_TIMELINE_BTN_LABEL = i18n.translate(
'xpack.securitySolution.flyout.timeline.actionMenu.saveTimelineBtnLabel',
{
defaultMessage: 'Save currently opened Timeline',
}
);

export const NEW_TEMPLATE_TIMELINE = i18n.translate(
'xpack.securitySolution.flyout.timeline.actionMenu.newTimelineTemplate',
{
Expand All @@ -66,14 +38,6 @@ export const CALL_OUT_UNAUTHORIZED_MSG = i18n.translate(
}
);

export const CALL_OUT_IMMUTABLE = i18n.translate(
'xpack.securitySolution.timeline.callOut.immutable.message.description',
{
defaultMessage:
'This prebuilt timeline template cannot be modified. To make changes, please duplicate this template and make modifications to the duplicate template.',
}
);

export const SAVE_TIMELINE = i18n.translate(
'xpack.securitySolution.timeline.saveTimeline.modal.header',
{
Expand Down Expand Up @@ -149,24 +113,10 @@ export const OPTIONAL = i18n.translate(
}
);

export const SAVE_TOUR_CLOSE = i18n.translate(
'xpack.securitySolution.timeline.flyout.saveTour.closeButton',
{
defaultMessage: 'Close',
}
);

export const TITLE = i18n.translate('xpack.securitySolution.timeline.saveTimeline.modal.title', {
defaultMessage: 'Title',
});

export const SAVE_TOUR_TITLE = i18n.translate(
'xpack.securitySolution.timeline.flyout.saveTour.title',
{
defaultMessage: 'Timeline changes now require manual saves',
}
);

export const SAVE_AS_NEW = i18n.translate(
'xpack.securitySolution.timeline.saveTimeline.modal.saveAsNew',
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { render, waitFor } from '@testing-library/react';
import React from 'react';
import { OpenTimelineButton } from './open_timeline_button';
import { TestProviders } from '../../../../common/mock/test_providers';
import { useParams } from 'react-router-dom';
import { TimelineType } from '../../../../../common/api/timeline';
import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction';
import { useSourcererDataView } from '../../../../common/containers/sourcerer';
import { useTimelineStatus } from '../../open_timeline/use_timeline_status';

jest.mock('../../../../common/lib/apm/use_start_transaction');
jest.mock('../../../../common/containers/sourcerer');
jest.mock('../../open_timeline/use_timeline_status');
jest.mock('react-redux', () => {
const origin = jest.requireActual('react-redux');
return {
...origin,
useDispatch: jest.fn(),
};
});
jest.mock('react-router-dom', () => {
const actual = jest.requireActual('react-router-dom');
return {
...actual,
useParams: jest.fn(),
};
});
jest.mock('../../../../common/lib/kibana', () => {
const actual = jest.requireActual('../../../../common/lib/kibana');
return {
...actual,
useNavigation: () => ({
navigateTo: jest.fn(),
}),
};
});

const renderOpenTimelineButton = () =>
render(
<TestProviders>
<OpenTimelineButton />
</TestProviders>
);

describe('OpenTimelineButton', () => {
it('should render the button', () => {
const { getByTestId, queryByTestId } = renderOpenTimelineButton();

expect(getByTestId('timeline-modal-open-timeline-button')).toBeInTheDocument();
expect(getByTestId('timeline-modal-open-timeline-button')).toHaveTextContent('Open');

expect(queryByTestId('open-timeline-modal')).not.toBeInTheDocument();
});

it('should open the modal after clicking on the button', async () => {
(useParams as jest.Mock).mockReturnValue({ tabName: TimelineType.template });
(useStartTransaction as jest.Mock).mockReturnValue({ startTransaction: jest.fn() });
(useSourcererDataView as jest.Mock).mockReturnValue({ dataViewId: '', selectedPatterns: [] });
(useTimelineStatus as jest.Mock).mockReturnValue({
timelineStatus: 'active',
templateTimelineFilter: null,
installPrepackagedTimelines: jest.fn(),
});

const { getByTestId } = renderOpenTimelineButton();

getByTestId('timeline-modal-open-timeline-button').click();

await waitFor(() => {
expect(getByTestId('open-timeline-modal')).toBeInTheDocument();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,28 @@ import * as i18n from './translations';

const actionTimelineToHide: ActionTimelineToShow[] = ['createFrom'];

export const OpenTimelineAction = React.memo(() => {
/**
* Renders a button that opens the `OpenTimelineModal` to allow users to select a saved timeline to open
*/
export const OpenTimelineButton = React.memo(() => {
const [showTimelineModal, setShowTimelineModal] = useState(false);
const onCloseTimelineModal = useCallback(() => setShowTimelineModal(false), []);
const onOpenTimelineModal = useCallback(() => {
setShowTimelineModal(true);
}, []);
const toggleTimelineModal = useCallback(() => setShowTimelineModal((prev) => !prev), []);

return (
<>
<EuiButtonEmpty
data-test-subj="open-timeline-button"
onClick={onOpenTimelineModal}
data-test-subj="timeline-modal-open-timeline-button"
onClick={toggleTimelineModal}
aria-label={i18n.OPEN_TIMELINE_BTN_LABEL}
>
{i18n.OPEN_TIMELINE_BTN}
</EuiButtonEmpty>

{showTimelineModal ? (
<OpenTimelineModal onClose={onCloseTimelineModal} hideActions={actionTimelineToHide} />
<OpenTimelineModal onClose={toggleTimelineModal} hideActions={actionTimelineToHide} />
) : null}
</>
);
});

OpenTimelineAction.displayName = 'OpenTimelineAction';
OpenTimelineButton.displayName = 'OpenTimelineButton';
Loading

0 comments on commit 54262d0

Please sign in to comment.