Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ describe('TabbedModal', () => {

return (
<EuiFieldText
data-test-subj="log-user-input-field"
placeholder="Placeholder text"
value={state.inputText}
onChange={onChange}
Expand All @@ -57,7 +58,7 @@ describe('TabbedModal', () => {
},
};

it('renders the modal component', async () => {
it("when a single tab definition is passed it simply renders it's content into the modal component without tabs", async () => {
render(
<TabbedModal
tabs={[tabDefinition]}
Expand All @@ -66,6 +67,24 @@ describe('TabbedModal', () => {
/>
);

expect(screen.queryByText(tabDefinition.name)).not.toBeInTheDocument();

expect(screen.getByTestId('log-user-input-field')).toBeInTheDocument();

await userEvent.click(await screen.findByTestId(tabDefinition.modalActionBtn!.dataTestSubj));

expect(mockedHandlerFn).toHaveBeenCalled();
});

it('renders the tabbed modal with tabs for tab definition with length greater than 1', async () => {
render(
<TabbedModal
tabs={[tabDefinition, { ...tabDefinition, id: 'anotherTab', name: 'another tab' }]}
defaultSelectedTabId="logUserInput"
onClose={modalOnCloseHandler}
/>
);

expect(screen.queryByText(tabDefinition.name)).toBeInTheDocument();

await userEvent.click(await screen.findByTestId(tabDefinition.modalActionBtn!.dataTestSubj));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,21 +127,29 @@ const TabbedModalInner: FC<ITabbedModalInner> = ({
);

const renderTabs = useCallback(() => {
return tabs.map((tab, index) => {
return (
<EuiTab
key={index}
onClick={() => onSelectedTabChanged(tab.id)}
isSelected={tab.id === selectedTabId}
disabled={tab.disabled}
prepend={tab.prepend}
append={tab.append}
data-test-subj={tab.id}
>
{tab.name}
</EuiTab>
);
});
if (tabs.length === 1) {
return null;
}

return (
<EuiTabs>
{tabs.map((tab, index) => {
return (
<EuiTab
key={index}
onClick={() => onSelectedTabChanged(tab.id)}
isSelected={tab.id === selectedTabId}
disabled={tab.disabled}
prepend={tab.prepend}
append={tab.append}
data-test-subj={tab.id}
>
{tab.name}
</EuiTab>
);
})}
</EuiTabs>
);
}, [onSelectedTabChanged, selectedTabId, tabs]);

const modalPositionOverrideStyles: React.CSSProperties = {
Expand Down Expand Up @@ -170,19 +178,24 @@ const TabbedModalInner: FC<ITabbedModalInner> = ({
</EuiModalHeader>
<EuiModalBody>
<Fragment>
<EuiTabs>{renderTabs()}</EuiTabs>
<Fragment>{renderTabs()}</Fragment>
<EuiSpacer size="m" />
{React.createElement(function RenderSelectedTabContent() {
useLayoutEffect(() => {
requestAnimationFrame(onTabContentRender);
}, []);
return (
<SelectedTabContent
{...{
state: selectedTabState,
dispatch,
}}
/>
<div
css={{ display: 'contents' }}
data-test-subj={`tabbedModal-${selectedTabId}-content`}
>
<SelectedTabContent
{...{
state: selectedTabState,
dispatch,
}}
/>
</div>
);
})}
</Fragment>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import { render, screen } from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';
import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl';
import { ExportMenu } from './export_popover';
import { ExportMenu } from './export_integrations';
import type { IShareContext } from '../context';
import type { ExportShareConfig } from '../../types';

const mockShareContext: IShareContext = {
shareMenuItems: [
Expand Down Expand Up @@ -51,15 +52,19 @@ const mockShareContext: IShareContext = {
onClose: jest.fn(),
};

function ExportPopoverRender() {
function ExportPopoverRender({
shareContext = mockShareContext,
}: {
shareContext?: IShareContext;
}) {
const [clickTarget, setClickTarget] = React.useState<HTMLElement | null>();

return (
<IntlProvider locale="en">
{Boolean(clickTarget) && (
<ExportMenu
shareContext={{
...mockShareContext,
...shareContext,
anchorElement: clickTarget!,
}}
/>
Expand All @@ -69,7 +74,7 @@ function ExportPopoverRender() {
);
}

describe('ExportPopover', () => {
describe('Export Integrations', () => {
it('renders a popover with the list of registered export types', async () => {
const user = userEvent.setup();

Expand All @@ -83,4 +88,33 @@ describe('ExportPopover', () => {
expect(screen.getByText(label)).toBeInTheDocument();
});
});

it('will invoke the export integrations generateAssetExport config method if it is the singular export type available', async () => {
const user = userEvent.setup();

const singleExportShareContext: IShareContext = {
...mockShareContext,
shareMenuItems: [
{
shareType: 'integration',
groupId: 'export',
id: 'csv',
config: {
icon: 'empty',
label: 'CSV',
generateAssetExport: jest.fn(() => Promise.resolve()),
},
} as unknown as ExportShareConfig,
],
};

render(<ExportPopoverRender shareContext={singleExportShareContext} />);

await user.click(screen.getByText('click me'));

expect(
(singleExportShareContext.shareMenuItems[0] as ExportShareConfig).config.generateAssetExport
).toHaveBeenCalled();
expect(singleExportShareContext.onClose).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ function ManagedFlyout({
<EuiCodeBlock
data-test-subj="exportAssetValue"
css={{ overflowWrap: 'break-word' }}
overflowHeight={360}
language={exportIntegration.config.copyAssetURIConfig.contentType}
isCopyable
copyAriaLabel={i18n.translate('share.export.copyPostURLAriaLabel', {
Expand Down Expand Up @@ -286,34 +287,65 @@ function ExportMenuPopover({ intl }: ExportMenuProps) {
setIsFlyoutVisible(true);
}, []);

useEffect(() => {
// when there is only one share menu item, and no export derivatives registered,
// we want to open the flyout and not the popover
if (
exportIntegrations.length === 1 &&
exportDerivatives.length === 0 &&
!selectedMenuItemMeta
) {
openFlyout(exportIntegrations[0]);
}
}, [exportIntegrations, exportDerivatives, openFlyout, selectedMenuItemMeta]);
const exportIntegrationInteractionHandler = useCallback(
async (menuItem: ExportShareConfig) => {
if (
!menuItem.config.copyAssetURIConfig &&
!menuItem.config.generateAssetComponent &&
menuItem.config.generateAssetExport
) {
await menuItem.config
.generateAssetExport({
intl,
optimizedForPrinting: false,
})
.finally(() => {
onClose();
});
} else {
openFlyout(menuItem);
}
},
[intl, onClose, openFlyout]
);

const flyoutRef = useRef<HTMLDivElement | null>(null);

const canSkipDisplayingPopover = useMemo<boolean>(() => {
// when there is only one export share menu item, and no export derivatives registered,
// we'd like to skip displaying the popover
return exportIntegrations.length === 1 && !exportDerivatives.length;
}, [exportIntegrations, exportDerivatives]);

const flyoutOnCloseHandler = useCallback(() => {
return exportIntegrations.length === 1 && exportDerivatives.length === 0
? onClose()
: setIsFlyoutVisible(false);
}, [exportDerivatives.length, exportIntegrations.length, onClose]);
setIsFlyoutVisible(false);
if (canSkipDisplayingPopover) {
onClose();
}
}, [onClose, canSkipDisplayingPopover]);

const flyoutRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
if (canSkipDisplayingPopover && !selectedMenuItemMeta) {
exportIntegrationInteractionHandler(exportIntegrations[0]);
}
}, [
exportIntegrationInteractionHandler,
exportIntegrations,
onClose,
selectedMenuItemMeta,
canSkipDisplayingPopover,
]);

return (
<Fragment>
<EuiWrappingPopover
isOpen={!isFlyoutVisible}
data-test-subj="exportPopover"
isOpen={!isFlyoutVisible && !canSkipDisplayingPopover}
button={anchorElement!}
closePopover={onClose}
panelPaddingSize="s"
panelProps={{
'data-test-subj': 'exportPopoverPanel',
}}
>
<EuiListGroup flush>
{exportIntegrations.map((menuItem) => (
Expand All @@ -328,7 +360,7 @@ function ExportMenuPopover({ intl }: ExportMenuProps) {
label={menuItem.config.label}
data-test-subj={`exportMenuItem-${menuItem.config.label}`}
isDisabled={menuItem.config.disabled}
onClick={() => openFlyout(menuItem)}
onClick={exportIntegrationInteractionHandler.bind(null, menuItem)}
/>
</EuiToolTip>
))}
Expand Down Expand Up @@ -368,6 +400,7 @@ function ExportMenuPopover({ intl }: ExportMenuProps) {
? selectedMenuItem.config.flyoutSizing || {}
: {})}
>
{/* TODO: remove this global style once https://github.com/elastic/eui/issues/8801 is resolved */}
<Global
// @ts-expect-error -- we pass a z-index specifying important so we override the default z-index, so solve a known bug,
// where when `headerZindexLocation` is set to `above`, the popover panel z-index is not high enough
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

export { ExportMenu } from './export_popover';
export { ExportMenu } from './export_integrations';
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const ShareMenuTabs = () => {
tabs.push(linkTab);
}

// Embed is disabled in the serverless offering, hence the need to check that we received it
// Embed is disabled in the serverless offering, hence the need to check if the embed tab should be shown
if (
shareMenuItems.some(({ shareType }) => shareType === 'embed') &&
!objectTypeMeta?.config?.embed?.disabled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type { ShowShareMenuOptions } from '../types';
import type { ShareRegistry } from './share_menu_registry';
import type { ShareConfigs } from '../types';
import { ShareMenu } from '../components/share_tabs';
import { ExportMenu } from '../components/export_popover';
import { ExportMenu } from '../components/export_integrations';

interface ShareMenuManagerStartDeps {
core: CoreStart;
Expand Down
2 changes: 1 addition & 1 deletion src/platform/plugins/shared/share/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"@kbn/core-http-server-internal",
"@kbn/core-test-helpers-test-utils",
"@kbn/core-logging-server-mocks",
"@kbn/core-http-router-server-mocks",
"@kbn/core-http-router-server-mocks"
],
"exclude": ["target/**/*"]
}
2 changes: 1 addition & 1 deletion src/platform/test/functional/page_objects/export_page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class ExportPageObject extends FtrService {
}

async isExportPopoverOpen() {
return await this.testSubjects.exists('exportPopover');
return await this.testSubjects.exists('exportPopoverPanel');
}

async isPopoverItemEnabled(label: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {

it('should be possible to download a visualization with adhoc dataViews', async () => {
await lens.setCSVDownloadDebugFlag(true);
await lens.openCSVDownloadExport();
await lens.triggerCSVDownloadExport();

const csv = await lens.getCSVContent();
expect(csv).to.be.ok();
Expand Down
8 changes: 4 additions & 4 deletions x-pack/test/functional/apps/lens/group4/share.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});

it('should enable both download and URL sharing for valid configuration', async () => {
await lens.clickShareModal();

expect(await lens.isExportActionEnabled()).to.eql(true);

await lens.clickShareButton();
expect(await lens.isShareActionEnabled('link'));
});

Expand All @@ -83,7 +83,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {

it('should be able to download CSV data of the current visualization', async () => {
await lens.setCSVDownloadDebugFlag(true);
await lens.openCSVDownloadExport();
await lens.triggerCSVDownloadExport();

const csv = await lens.getCSVContent();
expect(csv).to.be.ok();
Expand All @@ -105,7 +105,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
field: 'bytes',
});

await lens.openCSVDownloadExport();
await lens.triggerCSVDownloadExport();

const csv = await lens.getCSVContent();
expect(csv).to.be.ok();
Expand Down
Loading